랭체인 스터디 추가 (파서, 러너블, 멀티턴)
- 음식, 뉴스, 리뷰 등
This commit is contained in:
Generated
+10
@@ -0,0 +1,10 @@
|
|||||||
|
# 디폴트 무시된 파일
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# 에디터 기반 HTTP 클라이언트 요청
|
||||||
|
/httpRequests/
|
||||||
|
# 쿼리 파일을 포함한 무시된 디폴트 폴더
|
||||||
|
/queries/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
Generated
+18
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/ollama/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="~/Source/.venv" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="PackageRequirementsSettings" />
|
||||||
|
<component name="PyDocumentationSettings">
|
||||||
|
<option name="format" value="PLAIN" />
|
||||||
|
<option name="myDocStringFormat" value="Plain" />
|
||||||
|
</component>
|
||||||
|
<component name="ReSTService" />
|
||||||
|
<component name="TestRunnerService" />
|
||||||
|
</module>
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="~/Source/.venv" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/Source.iml" filepath="$PROJECT_DIR$/.idea/Source.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
qwen_llm = ChatOllama(model="qwen3.5:4b")
|
||||||
|
exaone_llm = ChatOllama(model="exaone3.5:2.4b")
|
||||||
|
|
||||||
|
system_prompt = """\
|
||||||
|
당신은 20년 경력의 전문 셰프이자 요리 연구가입니다.
|
||||||
|
사용자의 요리 질문에 대해
|
||||||
|
재료, 조리방법, 실패 방지 팁, 대체 재료를
|
||||||
|
포함하여 답변하세요.
|
||||||
|
항상 한국어로 답변하세요
|
||||||
|
"""
|
||||||
|
|
||||||
|
template = ChatPromptTemplate.from_messages(
|
||||||
|
[
|
||||||
|
("system", system_prompt),
|
||||||
|
("human", "{question}"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
chain = template | exaone_llm | StrOutputParser()
|
||||||
|
|
||||||
|
|
||||||
|
def chat(question, history):
|
||||||
|
response = chain.invoke({"question": question})
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
chatbot = gr.ChatInterface(
|
||||||
|
fn=chat,
|
||||||
|
title="🍝 요리 전문가",
|
||||||
|
description="요리경력 20년의 전문가입니다. 요리에 대한 궁금증을 해결하세요.",
|
||||||
|
)
|
||||||
|
|
||||||
|
chatbot.launch()
|
||||||
+1596
-57
File diff suppressed because one or more lines are too long
@@ -0,0 +1,78 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
qwen_llm = ChatOllama(model="qwen3.5:4b")
|
||||||
|
exaone_llm = ChatOllama(model="exaone3.5:2.4b")
|
||||||
|
|
||||||
|
system_prompt = """\
|
||||||
|
당신은 뉴스 분석 전문가입니다. 반드시 json 형식으로만 응답하세요.
|
||||||
|
다른 텍스트 없이 아래 형식으로만 반환하세요\n
|
||||||
|
{{"title":"기사제목", "date":"작성일자", "keywords":["키워드1", "키워드2", "키워드3"], "category" : "카테고리"}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
template = ChatPromptTemplate.from_messages(
|
||||||
|
[
|
||||||
|
("system", system_prompt),
|
||||||
|
("human", "{article}"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
chain = template | exaone_llm | JsonOutputParser()
|
||||||
|
|
||||||
|
|
||||||
|
# def news_input(article1, article2, article3):
|
||||||
|
# # 3개의 기사를 리스트로 묶음
|
||||||
|
# articles = [article1, article2, article3]
|
||||||
|
# results = []
|
||||||
|
|
||||||
|
# # 각 기사별로 체인 실행
|
||||||
|
# for text in articles:
|
||||||
|
# if text.strip(): # 내용이 있을 때만 실행
|
||||||
|
# res = chain.invoke({"article": text})
|
||||||
|
# results.append(res)
|
||||||
|
|
||||||
|
# # 결과를 하나로 합쳐서 반환
|
||||||
|
# return "\n\n---\n\n".join(results)
|
||||||
|
|
||||||
|
|
||||||
|
def news_input(texts):
|
||||||
|
# ===을 기준으로 기사 분리
|
||||||
|
articles = [article for article in texts.split("===") if article.strip()]
|
||||||
|
|
||||||
|
response = chain.batch([{"article": article} for article in articles])
|
||||||
|
return "\n\n".join(str(item) for item in response)
|
||||||
|
|
||||||
|
|
||||||
|
app = gr.Interface(
|
||||||
|
news_input,
|
||||||
|
# inputs=[
|
||||||
|
# gr.Textbox(label="기사 1", lines=5),
|
||||||
|
# gr.Textbox(label="기사 2", lines=5),
|
||||||
|
# gr.Textbox(label="기사 3", lines=5),
|
||||||
|
# ],
|
||||||
|
inputs=[
|
||||||
|
gr.Textbox(
|
||||||
|
label="기사",
|
||||||
|
placeholder="여러 기사 입력 시 구분자로 ===을 사용하세요",
|
||||||
|
lines=20,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[
|
||||||
|
gr.Textbox(label="요약", lines=20),
|
||||||
|
],
|
||||||
|
title="✒ 뉴스 분석 전문가",
|
||||||
|
description="뉴스 기사에서 정보를 추출합니다.",
|
||||||
|
)
|
||||||
|
|
||||||
|
app.launch()
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
qwen_llm = ChatOllama(model="qwen3.5:4b", temperature=0)
|
||||||
|
exaone_llm = ChatOllama(model="exaone3.5:2.4b", temperature=0)
|
||||||
|
|
||||||
|
|
||||||
|
class NewsResult(BaseModel):
|
||||||
|
title: str
|
||||||
|
date: str = Field(description="YYYY-MM-DD 형식, 없는 경우 '없음'")
|
||||||
|
category: Literal["정치", "경제", "사회", "문화", "스포츠", "IT", "국제", "기타"]
|
||||||
|
keywords: list[str] = Field(description="핵심 키워드 3개 이내")
|
||||||
|
|
||||||
|
|
||||||
|
pydantic_parser = PydanticOutputParser(pydantic_object=NewsResult)
|
||||||
|
template = ChatPromptTemplate.from_messages(
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"system",
|
||||||
|
"당신은 뉴스 분석 전문가입니다. 기사에서 아래 정보를 추출하세요. {format_instructions}",
|
||||||
|
),
|
||||||
|
("human", "{article}"),
|
||||||
|
]
|
||||||
|
).partial(format_instructions=pydantic_parser.get_format_instructions())
|
||||||
|
|
||||||
|
|
||||||
|
chain = template | exaone_llm | pydantic_parser
|
||||||
|
|
||||||
|
|
||||||
|
def news_input(texts):
|
||||||
|
# ===을 기준으로 기사 분리
|
||||||
|
articles = [article for article in texts.split("===") if article.strip()]
|
||||||
|
|
||||||
|
response = chain.batch([{"article": article} for article in articles])
|
||||||
|
return "\n\n".join(str(item) for item in response)
|
||||||
|
|
||||||
|
|
||||||
|
app = gr.Interface(
|
||||||
|
news_input,
|
||||||
|
inputs=[
|
||||||
|
gr.Textbox(
|
||||||
|
label="기사",
|
||||||
|
placeholder="여러 기사 입력 시 구분자로 ===을 사용하세요",
|
||||||
|
lines=20,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[
|
||||||
|
gr.Textbox(label="요약", lines=20),
|
||||||
|
],
|
||||||
|
title="✒ 뉴스 분석 전문가",
|
||||||
|
description="뉴스 기사에서 정보를 추출합니다.",
|
||||||
|
)
|
||||||
|
|
||||||
|
app.launch()
|
||||||
@@ -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