oasis-chatbot / app.py
hallu11's picture
Update app.py
f949186 verified
import os
import fitz # PyMuPDF
import gradio as gr
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer
from groq import Groq
# ✅ 1. Groq API 키 설정
os.environ["GROQ_API_KEY"] = "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"
client = Groq(api_key=os.environ["GROQ_API_KEY"])
# ✅ 2. PDF 파일 경로 리스트
pdf_paths = [
"pdfs/의왕단오축제 _ 의왕문화원.pdf",
"pdfs/성인 문화학교 _ 의왕문화원.pdf",
"pdfs/횡성문화원_문화학교.pdf",
"pdfs/발달장애인 교육사업 _ 꿈꾸는 마을.pdf",
"pdfs/횡성의지역축제 - 횡성축제소개.pdf",
"pdfs/어린이 문화학교 _ 의왕문화원.pdf"
]
# ✅ 3. 텍스트 추출
def extract_texts_from_pdfs(pdf_paths):
chunks = []
for path in pdf_paths:
try:
with fitz.open(path) as doc:
for page in doc:
text = page.get_text().strip()
if len(text) > 30:
chunks.append({
"text": text,
"source": os.path.basename(path)
})
print(f"✅ 텍스트 추출 완료: {path}")
except Exception as e:
print(f"❌ 오류 발생: {path} -> {e}")
return chunks
docs = extract_texts_from_pdfs(pdf_paths)
# ✅ 4. 임베딩 및 FAISS 색인
embed_model = SentenceTransformer("jhgan/ko-sroberta-multitask")
texts = [doc["text"] for doc in docs]
sources = [doc["source"] for doc in docs]
embeddings = embed_model.encode(texts, convert_to_numpy=True, show_progress_bar=True)
index = faiss.IndexFlatL2(embeddings.shape[1])
index.add(np.array(embeddings))
# ✅ 5. 유사 문서 검색
def search_similar_docs(query, top_k=3):
query_emb = embed_model.encode([query])[0]
scores, indices = index.search(np.array([query_emb]), top_k)
results = []
for idx in indices[0]:
results.append(docs[idx]["text"])
return "\n\n".join(results)
# ✅ 6. Groq 응답
def ask_with_groq(question, context):
response = client.chat.completions.create(
model="llama3-8b-8192",
messages=[
{"role": "system", "content": "너는 문화 관련 문서를 기반으로 질문에 한국어로 답하는 도우미야."},
{"role": "user", "content": f"{question}\n\n[문서 내용]\n{context[:3000]}"}
]
)
return response.choices[0].message.content
# ✅ 7. 챗봇 인터페이스
def chatbot_interface(question):
context = search_similar_docs(question)
answer = ask_with_groq(question, context)
return answer
# ✅ 8. 추천 질문 리스트
suggested_questions = [
"의왕단오축제는 언제 열리나요?",
"의왕단오축제 주요 프로그램은 무엇인가요?",
"의왕문화원의 성인 문화학교 교육 대상은 누구인가요?",
"성인 문화학교에서 제공하는 수업 종류는 무엇인가요?",
"횡성문화원의 문화학교는 어떤 교육을 진행하나요?",
"꿈꾸는 마을 프로그램 참가 자격은 어떻게 되나요?",
"횡성지역축제의 대표 축제는 무엇인가요?",
"횡성축제의 개최 시기와 일정은 어떻게 되나요?",
"의왕문화원의 어린이 문화학교는 몇 세부터 참여 가능한가요?",
"어린이 문화학교에서 진행하는 주요 프로그램은 무엇인가요?",
"의왕문화원 문화 프로그램은 어디에서 진행되나요?",
"각 프로그램의 참가 신청 방법과 일정은 어떻게 되나요?",
"발달장애인 교육사업에서 제공하는 지원 서비스는 무엇인가요?",
"의왕단오축제 참가비는 얼마인가요?",
"횡성문화원 문화학교는 몇 개의 과정을 운영하나요?",
"어린이 문화학교 행사 일정은 어떻게 되나요?",
"문화 프로그램이 지역사회에 미치는 긍정적 영향은 무엇인가요?",
"프로그램 안전관리 및 코로나 방역 대책은 어떻게 되어 있나요?",
"문화 프로그램 참여 후 제공되는 피드백 절차가 있나요?",
]
# ✅ 9. Gradio UI
with gr.Blocks() as demo:
gr.Markdown("# 📘 오아시스 문서 기반 문화 프로그램 챗봇 🤖 '뮤지스(Musesis)'")
gr.Markdown("질문을 입력하면 유사 문서를 검색해 답변해줍니다.")
with gr.Row():
with gr.Column(scale=3):
question_box = gr.Textbox(placeholder="질문을 입력하세요", label="질문", lines=1)
with gr.Row():
submit_btn = gr.Button("질문하기")
clear_btn = gr.Button("기록 지우기")
answer_box = gr.Textbox(label="답변", lines=10)
with gr.Column(scale=1):
with gr.Accordion("💡 추천 질문 보기 (펼치기/접기)", open=False):
for q in suggested_questions:
btn = gr.Button(q, scale=1)
btn.click(fn=chatbot_interface, inputs=gr.Textbox(value=q, visible=False), outputs=answer_box)
# ✅ 버튼 클릭 및 Enter로 질문 실행
submit_btn.click(fn=chatbot_interface, inputs=question_box, outputs=answer_box)
question_box.submit(fn=chatbot_interface, inputs=question_box, outputs=answer_box)
# ✅ 기록 지우기
clear_btn.click(lambda: ("", ""), inputs=[], outputs=[question_box, answer_box])
# ✅ 10. 실행
if __name__ == "__main__":
demo.launch()