from langchain_ollama import ChatOllama from langchain_ibm import ChatWatsonx from langchain_core.prompts import PromptTemplate, ChatPromptTemplate from langchain_core.output_parsers import ( StrOutputParser, JsonOutputParser, PydanticOutputParser, ) from pydantic import BaseModel, Field from typing import Literal from dotenv import load_dotenv import os import gradio as gr import time qwen_llm = ChatOllama(model="qwen3.5:4b", temperature=0) exaone_llm = ChatOllama(model="exaone3.5:2.4b", temperature=0) gemma_llm = ChatOllama(model="gemma4:e2b", temperature=0) class ReviewAnalysis(BaseModel): sentiment: Literal["긍정", "부정", "중립"] = Field(description="전체 감정") score: float = Field(ge=0.0, le=1.0, description="감정 강도") pros: list[str] = Field(description="긍정적인 리뷰 리스트") cons: list[str] = Field(description="부정적인 리뷰 리스트") recommend: bool = Field(description="추천여부 True/False") reply: str = Field(description="판매자 입장의 고객 답변 한 문장") pydantic_parser = PydanticOutputParser(pydantic_object=ReviewAnalysis) template = ChatPromptTemplate.from_messages( [ ( "system", "리뷰 담당자 입니다. 리뷰를 보고 정보를 추출하고 고객에 의문에 답변할 내용을 작성하세요. {format_instructions}", ), ("human", "{review}"), ] ).partial(format_instructions=pydantic_parser.get_format_instructions()) chain = template | gemma_llm | pydantic_parser def analyze(texts): # ===을 기준으로 리뷰 분리 reviews = [review.strip() for review in texts.split("===") if review.strip()] start = time.time() results = chain.batch([{"review": r} for r in reviews]) elapsed = time.time() - start output = [] for i, (review, result) in enumerate(zip(texts, results), 1): emoji = {"긍정": "😊", "부정": "😡", "중립": "😑"}[result.sentiment] output.append(f"[리뷰 {i}]") output.append(f"고객 리뷰 {review[:40]}....") output.append( f"리뷰 감정 {emoji} {result.sentiment}(강도 : {result.score:.2f})" ) output.append(f"장점 {", ".join(result.pros) if result.pros else "없음"}") output.append(f"단점 {", ".join(result.cons) if result.cons else "없음"}") output.append(f"추천 여부 {"👍 추천" if result.recommend else "👎 비추천"}") output.append(f"판매자 답변 {result.reply}") output.append("-" * 40) output.append(f"소요 시간 : {elapsed:.2f}초, ({len(reviews)} 개 리뷰) ") return "\n".join(output) app = gr.Interface( analyze, inputs=[ gr.Textbox( label="리뷰 입력", placeholder="여러 리뷰 입력 시 구분자로 ===을 사용하세요", lines=20, ), ], outputs=[ gr.Textbox(label="분석결과", lines=20), ], title="✒ 상품 리뷰 분석", description="리뷰 입력 시 감정, 장담점, 추천 여부를 분설합니다.", ) app.launch()