archivebot / app.py
suhyun1's picture
Update app.py
3050477 verified
import os
import gradio as gr
import bs4
from langchain_community.document_loaders import WebBaseLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain.chains import RetrievalQA
from langchain_groq import ChatGroq
from langchain_community.document_loaders import UnstructuredExcelLoader
# ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ๋ถ€ํ„ฐ Groq API Key ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
groq_api_key = os.environ.get("GROQ_API_KEY", "")
# ๊ตญ๊ฐ€๊ธฐ๋ก์› ์›น ๋ฌธ์„œ ๋ชฉ๋ก
urls = [
"https://archives.go.kr/next/newsearch/listSubjectContent.do?subjectFieldId=000011",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003140&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003288&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003290&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003292&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=008757&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003293&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003294&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003295&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003289&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=010816&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=010817&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=009154&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003260&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003278&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003281&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003283&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003284&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003280&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003282&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003287&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003286&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003285&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003279&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003141&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003143&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003144&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003142&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=008653&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=010827&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=008582&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=008663&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=008581&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=010828&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=010830&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=010831&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003145&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=009425&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003146&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=010821&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003151&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003149&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003148&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=008655&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=008654&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newsearch/listSubjectDescription.do?id=003150&pageFlag=A&sitePage=1-2-1",
"https://archives.go.kr/next/newmanager/recodeRegister.do",
"https://archives.go.kr/next/newtour/tourCourse.do",
"https://archives.go.kr/next/newrecordsMngPro/recordsDonateInfo.do",
"https://archives.go.kr/next/newdata/pepoleRecodPresentIntro.do",
"https://archives.go.kr/next/newsearch/searchGuideList.do",
"https://archives.go.kr/next/newsearch/searchGuideList.do?page=2",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=441",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=381",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=341",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=261",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=227",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=59",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=30",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=64",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=321",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=124",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=267",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=141",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=149",
"https://archives.go.kr/next/newsearch/searchGuideDetail.do?guideSeq=22"
]
# ์›น๋ฌธ์„œ ๋กœ๋”ฉ
loader = WebBaseLoader(web_paths=urls, bs_kwargs=dict(parse_only=bs4.SoupStrainer()))
docs = loader.load()
# ๊ธฐ๋ก๋ฌผ ๋ชฉ๋ก ์—‘์…€ ํŒŒ์ผ
excel_files = [
"๊ต์œก ์ „๋ฐ˜ ๊ด€๋ จ ๊ธฐ๋ก๋ฌผ ๋ชฉ๋ก1.xls",
"๊ต์œก ์ „๋ฐ˜ ๊ด€๋ จ ๊ธฐ๋ก๋ฌผ ๋ชฉ๋ก2.xls",
"๊ต์œก ์ „๋ฐ˜ ๊ด€๋ จ ๊ธฐ๋ก๋ฌผ ๋ชฉ๋ก3.xls"
]
# ์—‘์…€ ๋ฌธ์„œ ๋กœ๋”ฉ
excel_docs = []
for file in excel_files:
loader = UnstructuredExcelLoader(file)
excel_docs.extend(loader.load())
# ์›น๋ฌธ์„œ + ์—‘์…€๋ฌธ์„œ ๊ฒฐํ•ฉ
docs.extend(excel_docs)
# ๋ฌธ์„œ ๋ถ„ํ• 
splitter = CharacterTextSplitter(separator="\n", chunk_size=500, chunk_overlap=50)
split_docs = splitter.split_documents(docs)
# ์ž„๋ฒ ๋”ฉ ๋ฐ ๋ฒกํ„ฐ ์ €์žฅ ๋ฐ ๋ฆฌํŠธ๋ฆฌ๋ฒ„ ์„ค์ •
embedding_model = HuggingFaceEmbeddings(model_name="snunlp/KR-SBERT-V40K-klueNLI-augSTS")
vectorstore = FAISS.from_documents(split_docs, embedding_model)
retriever = vectorstore.as_retriever()
# LLM + QA ์ฒด์ธ
llm = ChatGroq(groq_api_key=groq_api_key, model_name="llama3-70b-8192")
qa_chain = RetrievalQA.from_chain_type(llm=llm, retriever=retriever, chain_type="stuff")
# ์˜ˆ์‹œ ์งˆ๋ฌธ
example_questions = [
"๊ธฐ๋ก๋ฌผ ์—ด๋žŒ ๋ฐฉ๋ฒ•์€ ์–ด๋–ป๊ฒŒ ๋˜๋‚˜์š”?",
"๊ฒฌํ•™์‹ ์ฒญ์— ๋Œ€ํ•ด ์•Œ ์ˆ˜ ์žˆ๋‚˜์š”?",
"๊ธฐ๋ก๋ฌผ ๊ธฐ์ฆ ์ ˆ์ฐจ๋Š” ์–ด๋–ป๊ฒŒ ๋˜๋‚˜์š”?",
"๊ธฐ๋ก๋ฌผ ๊ฒ€์ƒ‰ ๊ธธ์žก์ด๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€์š”?",
"๋ฏผ์ค‘๊ต์œก์ง€ ์‚ฌ๊ฑด์˜ ์ฃผ์ œ ์œ ํ˜•์€ ๋ฌด์—‡์ธ๊ฐ€์š”?",
"๊ต์œก๊ฐœํ˜์‹œ๋ฏผ์šด๋™์—ฐ๋Œ€์˜ ๋ฐฐ๊ฒฝ์€ ๋ฌด์—‡์ธ๊ฐ€์š”?",
"์ฐธ๊ต์œก ์šด๋™์˜ ์—ญ์‚ฌ์  ์˜์˜๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?",
"ํ•™๋„ํ˜ธ๊ตญ๋‹จ์˜ ๊ธฐ๋ก๋ฌผ๋“ค์€ ๊ณต๊ฐœ๊ตฌ๋ถ„์ด ์–ด๋–ป๊ฒŒ ๋˜๋‚˜์š”?",
"AI ๋””์ง€ํ„ธ ๊ต๊ณผ์„œ์˜ ๊ธฐ๋ก๋ฌผ ์ค‘์— ์ •๋ถ€๊ฐ„ํ–‰๋ฌผ์€ ๋ช‡๊ฑด์ธ๊ฐ€์š”?",
"๊ต์œก๊ฐœํ˜์‹ฌ์˜ํšŒ์˜ ๊ธฐ๋ก๋ฌผ์€ ๋ช‡๊ฑด์ธ๊ฐ€์š”?",
"๊ตญ๋ฏผ๊ต์œกํ—Œ์žฅ์˜ ๊ธฐ๋ก๋ฌผ๋“ค์ด ์–ด๋–ค ์ œ๋ชฉ์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ๋‚˜์š”?",
"์„ธ๊ณ„๋ฐ•๋žŒํšŒ(EXPO) ๊ธฐ๋ก๋ฌผ์˜ ๊ฐœ์š”๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?",
"๋Œ€ํ•™์ˆ˜ํ•™๋Šฅ๋ ฅ์‹œํ—˜ ๊ด€๋ จ ๊ธฐ๋ก๋ฌผ์˜ ๊ธฐ๋ก๋ฌผ ์ƒ์‚ฐ์ •๋ณด๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‚˜์š”?",
"ํ•œ๋ฏธ๋™๋งน ๊ธฐ๋ก๋ฌผ์„ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์‹ถ์€๋ฐ, ํ‚ค์›Œ๋“œ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‚˜์š”?",
"๋™ํ•™๋†๋ฏผํ˜๋ช…์˜ ๊ธฐ๋ก๋ฌผ ์ˆ˜์ง‘ ํ˜„ํ™ฉ์ด ์–ด๋–ป๊ฒŒ ๋˜๋‚˜์š”?"
]
# ํ‚ค์›Œ๋“œ ๊ณ„์ธต ๊ตฌ์กฐ
keyword_tree = {
"๊ต์œก ์ „๋ฐ˜": {
"๊ต์œก ๋ฏผ์ฃผํ™”์šด๋™": {
"๊ต์›์šด๋™": {
"๊ต์œก ๋ฏผ์ฃผํ™”์„ ์–ธ": {},
"๋ฏผ์ค‘๊ต์œก์ง€ ์‚ฌ๊ฑด": {},
"์ฐธ๊ต์œก ์šด๋™": {}
},
"ํ•™๋ถ€๋ชจ ์šด๋™": {
"๊ต์œก๊ฐœํ˜์‹œ๋ฏผ์šด๋™์—ฐ๋Œ€": {}
},
"ํ•™์ƒ์šด๋™": {}
},
"๊ต์œก ์ •๋ณดํ™” ์ •์ฑ…": {
"AI ๋””์ง€ํ„ธ ๊ต๊ณผ์„œ": {},
"e๋Ÿฌ๋‹ํ™œ์„ฑํ™”": {},
"๊ต์œกํ–‰์ •์ •๋ณด์‹œ์Šคํ…œ(NEIS)": {}
},
"๊ต์œก๊ฐœํ˜": {
"๊ต์œก๊ฐœํ˜์‹ฌ์˜ํšŒ": {},
"๊ต์œก๊ฐœํ˜์œ„์›ํšŒ": {
"5ยท31 ๊ต์œก๊ฐœํ˜": {}
},
"๊ต์œก์ •์ฑ…์‹ฌ์˜ํšŒ": {},
"๊ต์œก์ •์ฑ…์ž๋ฌธํšŒ์˜": {},
"๊ต์œกํ˜์‹ ์œ„์›ํšŒ": {},
"์ƒˆ๊ต์œก๊ณต๋™์ฒด์œ„์›ํšŒ": {},
"์ธ๋ ฅ์ž์›๊ฐœ๋ฐœํšŒ์˜": {},
"์žฅ๊ธฐ์ข…ํ•ฉ๊ณ„ํš์‹ฌ์˜ํšŒ": {}
},
"๊ต์œก์ด๋…": {
"๊ตญ๋ฏผ๊ต์œกํ—Œ์žฅ": {
"ํ•™๋„ํ˜ธ๊ตญ๋‹จ": {}
},
"ํ™์ต์ธ๊ฐ„ ๊ต์œก์ด๋…": {
"์ผ๋ฏผ์ฃผ์˜": {}
}
},
"๊ต์œก์ •์ฑ… ๊ด€๋ จ ๊ธฐ๊ด€": {
"ํ•œ๊ตญ๊ต์œก๊ฐœ๋ฐœ์›": {},
"ํ•œ๊ตญ๊ต์œก๊ณผ์ •ํ‰๊ฐ€์›": {},
"ํ•œ๊ตญ๊ต์œก๋ฐฉ์†ก๊ณต์‚ฌ": {}
},
"ํ•™์ˆ ์ง„ํฅ ์ •์ฑ…": {
"KERIS": {},
"๋Œ€ํ•œ๋ฏผ๊ตญํ•™์ˆ ์›": {}
},
"ํ•™์ œ": {
"ํ•™๋ น์ธ๊ตฌ ๊ฐ์†Œ": {},
"ํ•™์ œ ํ™•์ •": {}
},
"ํ—Œ๋ฒ•์˜ ๊ต์œก์กฐํ•ญ๊ณผ ๋ณ€์ฒœ": {
"๊ณ ๋“ฑ๊ต์œก๋ฒ•": {},
"๊ต์œก๊ธฐ๋ณธ๋ฒ•": {},
"๊ต์œก๋ฒ• ์ œ์ •": {},
"๊ต์œก์— ๊ด€ํ•œ ์ž„์‹œํŠน๋ก€๋ฒ•": {},
"์‚ฌ๋ฆฝํ•™๊ต๋ฒ•": {},
"์ดˆยท์ค‘๋“ฑ๊ต์œก๋ฒ•": {}
}
},
"๊ธฐ๋ก๋ฌผ ๊ฒ€์ƒ‰ ๊ธธ์žก์ด": {
"๋™ํ•™๋†๋ฏผํ˜๋ช…": {},
"์šฐํŽธํ–‰์ •": {},
"๋Œ€ํ•™์ˆ˜ํ•™๋Šฅ๋ ฅ์‹œํ—˜": {},
"๋„์‹œ์ฒ ๋„": {
"๋„์‹œ์ฒ ๋„ 1ํ˜ธ์„ ": {}
},
"์žฌ์™ธ๋™ํฌ": {
"์žฌ์™ธ๋™ํฌ์žฌ๋‹จ": {},
"๋‚จ๋ฏธ ํ•œ์ธ": {},
"์ค‘๊ตญ ํ•œ์ธ": {},
"๊ณ ๋ ค์ธ": {},
"์žฌ์™ธ๋™ํฌ": {},
"ํ•œ๋ฏธ๋™๋งน": {},
"๋ฏธ๊ตญ ํ•œ์ธ": {},
"ํŒŒ๋… ๊ด‘๋ถ€ ๋ฐ ๊ฐ„ํ˜ธ์‚ฌ": {},
"์กฐ์„ ๊ธฐ์ˆ ์ž": {}
},
"ํ•œ๋ฏธ๋™๋งน": {},
"๊ณต๊ธฐ์—…": {
"ํ•œ๊ตญ์ „๋ ฅ๊ณต์‚ฌ": {}
},
"๋ฐ•๋žŒํšŒ": {
"์„ธ๊ณ„๋ฐ•๋žŒํšŒ(EXPO)": {}
}
},
"๊ฒ€์ƒ‰ ๋ฐฉํ–ฅ": {
"๊ต์œก ์ „๋ฐ˜ ๊ด€๋ จ": {
"๊ธฐ๋ก๋ฌผ ๋ชฉ๋ก": {
"๊ด€๋ฆฌ๋ฒˆํ˜ธ": {},
"๊ธฐ๋ก๋ฌผ ์ฒ  ์ œ๋ชฉ": {},
"๊ธฐ๋ก๋ฌผ ๊ฑด ์ œ๋ชฉ": {},
"์ƒ์‚ฐ๊ธฐ๊ด€๋ช…": {},
"์ƒ์‚ฐ๋…„๋„": {},
"๊ธฐ๋ก๋ฌผํ˜•ํƒœ": {
"์ผ๋ฐ˜๋ฌธ์„œ๋ฅ˜": {},
"์ •๋ถ€๊ฐ„ํ–‰๋ฌผ๋ฅ˜": {},
"์‚ฌ์ง„,ํ•„๋ฆ„๋ฅ˜": {},
"๋…น์Œ,๋™์˜์ƒ๋ฅ˜": {}
},
"๊ณต๊ฐœ๊ตฌ๋ถ„": {}
},
"์ฃผ์ œ ์„ค๋ช…": {
"์ฃผ์ œ์œ ํ˜•": {},
"๊ทผ๊ฑฐ": {},
"๋ฐฐ๊ฒฝ(๋ฐœ์ƒ๋ฐฐ๊ฒฝ)": {},
"๊ฒฝ๊ณผ": {},
"๋‚ด์šฉ": {},
"์—ญ์‚ฌ์  ์˜์˜": {},
"์ฐธ๊ณ ์ž๋ฃŒ": {},
"์ง‘ํ•„์ž": {}
}
},
"๊ธฐ๋ก๋ฌผ ๊ฒ€์ƒ‰ ๊ธธ์žก์ด ๊ด€๋ จ": {
"๊ฐœ์š”": {},
"์ƒ์‚ฐ์ •๋ณด": {},
"์ด๊ด€ ํ˜„ํ™ฉ": {},
"์†Œ์žฅ ํ˜„ํ™ฉ": {},
"์ •๋ฆฌ ํ˜„ํ™ฉ": {}
}
}
}
# ๊ฒฝ๋กœ์—์„œ ํ•˜์œ„ ํ‚ค์›Œ๋“œ ๋ฐ˜ํ™˜
def get_keywords(path):
node = keyword_tree
for key in path:
node = node.get(key, {})
return list(node.keys())
def format_path(path):
return " > ".join(path) if path else "๊ต์œก ์ „๋ฐ˜"
def on_keyword_select(selected, path):
new_path = path + [selected]
next_keywords = get_keywords(new_path)
formatted = format_path(new_path)
return formatted, new_path, gr.update(choices=next_keywords)
# Gradio ์ฑ„ํŒ… ํ•จ์ˆ˜
def chat_with_history(user_input, history):
if history is None:
history = []
query = user_input.strip() + " ํ•œ๊ตญ์–ด๋กœ ๋‹ตํ•ด์ฃผ์„ธ์š”."
result = qa_chain({"query": query})
answer = result.get("result", "๋‹ต๋ณ€์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
# ๋ฉ”์‹œ์ง€ ํฌ๋งท ๋งž์ถ”๊ธฐ (๋”•์…”๋„ˆ๋ฆฌ ํ˜•ํƒœ)
history.append({"role": "user", "content": user_input})
history.append({"role": "assistant", "content": answer})
return "", history, history
# Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ
with gr.Blocks() as demo:
gr.Markdown("## ๐Ÿ“š ๊ตญ๊ฐ€๊ธฐ๋ก์› ์ฑ—๋ด‡")
gr.Markdown(
"""### **๊ตญ๊ฐ€๊ธฐ๋ก์› ์ •๋ณด ์ฑ—๋ด‡์— ์˜ค์‹  ๊ฒƒ์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!**
์ด ์ฑ—๋ด‡์€ ๊ตญ๊ฐ€๊ธฐ๋ก์›์— ๋ณด๊ด€๋œ ๋‹ค์–‘ํ•œ ๊ธฐ๋ก๋ฌผ์„ ๋ฐ”ํƒ•์œผ๋กœ ์—ฌ๋Ÿฌ๋ถ„์˜ ๊ถ๊ธˆ์ฆ์„ ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ํ•ด๊ฒฐํ•ด ๋“œ๋ฆฝ๋‹ˆ๋‹ค.
๊ตญ๊ฐ€๊ธฐ๋ก์›์˜ ์—ญํ• , ๊ธฐ๋ก๋ฌผ ์—ด๋žŒ ๋ฐฉ๋ฒ•, ๊ฒฌํ•™ ์‹ ์ฒญ, ๊ธฐ์ฆ ์ ˆ์ฐจ ๋“ฑ์˜ ๊ณต์‹ ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ต์œก ์ „๋ฐ˜ ๋ถ„์•ผ์— ๊ด€ํ•œ ์ •๋ณด๋ฅผ ์•ˆ๋‚ดํ•ด ๋“œ๋ฆฝ๋‹ˆ๋‹ค.
์•„๋ž˜ ์ž…๋ ฅ์ฐฝ์— ๊ถ๊ธˆํ•œ ๋‚ด์šฉ์„ ์ž์œ ๋กญ๊ฒŒ ์ž…๋ ฅํ•ด ๋ณด์„ธ์š”.
๐Ÿ’ก ์งˆ๋ฌธ์„ ์–ด๋–ป๊ฒŒ ์‹œ์ž‘ํ• ์ง€ ๊ณ ๋ฏผ ์ค‘์ด์‹ ๊ฐ€์š”?
- **์˜ˆ์‹œ ์งˆ๋ฌธ ๋ณด๊ธฐ**์—์„œ ์งˆ๋ฌธ์„ ์„ ํƒํ•ด ๋ณด์„ธ์š”. ๊ธฐ๋ก๋ฌผ ์ •๋ณด ํƒ์ƒ‰์ด ์ฒ˜์Œ์ด๋ผ๋„ ์‰ฝ๊ฒŒ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
- **๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ ํƒ์ƒ‰** ๊ธฐ๋Šฅ์„ ์ด์šฉํ•ด ๋ณด์„ธ์š”. ํ‚ค์›Œ๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋‚˜๋งŒ์˜ ๊ฒ€์ƒ‰ ๋ฐฉํ–ฅ์„ ์ •ํ•ด๋ณด์„ธ์š”!
"""
)
chatbot = gr.Chatbot(label="๊ธฐ๋ก์› ์ฑ—๋ด‡", type="messages")
with gr.Row():
dropdown = gr.Dropdown(choices=example_questions, label="๐Ÿ“ ์˜ˆ์‹œ ์งˆ๋ฌธ ๋ณด๊ธฐ")
msg = gr.Textbox(placeholder="์งˆ๋ฌธ์„ ์ž…๋ ฅํ•˜์„ธ์š”", label="๐Ÿ’ฌ ์งˆ๋ฌธ ์ž…๋ ฅ", lines=1)
state = gr.State([]) # ์ฑ„ํŒ… ๊ธฐ๋ก
path_state = gr.State([]) # ํ‚ค์›Œ๋“œ ๊ฒฝ๋กœ ์ƒํƒœ
dropdown.change(lambda q: q, inputs=dropdown, outputs=msg)
msg.submit(chat_with_history, inputs=[msg, state], outputs=[msg, chatbot, state])
with gr.Column():
gr.Markdown("### ๐Ÿ” ๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ ํƒ์ƒ‰")
gr.Markdown(
""" **๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ ํƒ์ƒ‰ ์•ˆ๋‚ด**
๊ตญ๊ฐ€๊ธฐ๋ก์›์˜ ๋‹ค์–‘ํ•œ ๊ธฐ๋ก๋ฌผ์„ ์ฃผ์ œ๋ณ„๋กœ ๋ถ„๋ฅ˜ํ•œ ํ‚ค์›Œ๋“œ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ฉฐ, ๊ด€์‹ฌ ์žˆ๋Š” ๋ถ„์•ผ์˜ ๊ธฐ๋ก์„ **๊ณ„์ธต์ ์œผ๋กœ ์‰ฝ๊ฒŒ ํƒ์ƒ‰**ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
"""
)
keyword_path_display = gr.Textbox(label="ํ˜„์žฌ ํ‚ค์›Œ๋“œ ๊ฒฝ๋กœ", interactive=False)
keyword_selector = gr.Radio(choices=get_keywords([]), label="ํ‚ค์›Œ๋“œ ์„ ํƒ", value=None)
keyword_selector.change(
fn=on_keyword_select,
inputs=[keyword_selector, path_state],
outputs=[keyword_path_display, path_state, keyword_selector]
)
# ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ์ถ”๊ฐ€
def on_back_click(path):
if path:
path = path[:-1]
next_keywords = get_keywords(path)
formatted = format_path(path)
return formatted, path, gr.update(choices=next_keywords)
back_btn = gr.Button("๐Ÿ”™ ํ•œ ๋‹จ๊ณ„ ๋’ค๋กœ๊ฐ€๊ธฐ")
back_btn.click(
fn=on_back_click,
inputs=[path_state],
outputs=[keyword_path_display, path_state, keyword_selector]
)
demo.launch()