랭체인 스터디 추가 (파서, 러너블, 멀티턴)
- 음식, 뉴스, 리뷰 등
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user