Spaces:
Sleeping
Sleeping
import os | |
import gradio as gr | |
from langchain_groq import ChatGroq | |
from langchain.chains import RetrievalQA | |
from langchain.prompts import PromptTemplate | |
from langchain.vectorstores import FAISS | |
from langchain.embeddings import HuggingFaceEmbeddings | |
# Groq API 키 (Hugging Face Secrets에서 가져옴) | |
GROQ_API_KEY = os.environ.get("GROQ_API_KEY") | |
# 전역 변수들 | |
vectorstore = None | |
embeddings = None | |
def load_vectorstore(): | |
"""벡터스토어를 로드하는 함수""" | |
global vectorstore, embeddings | |
if vectorstore is None: | |
try: | |
embeddings = HuggingFaceEmbeddings( | |
model_name="sentence-transformers/all-MiniLM-L6-v2" | |
) | |
vectorstore = FAISS.load_local( | |
"vectorstore", | |
embeddings, | |
allow_dangerous_deserialization=True | |
) | |
print("✅ 벡터스토어 로드 완료") | |
except Exception as e: | |
print(f"❌ 벡터스토어 로드 실패: {e}") | |
vectorstore = None | |
return vectorstore | |
# 질문 리스트 | |
suggested_questions = [ | |
'교원 신규 임용은 어떻게 하나요?', | |
'교원 연구년 기간은 어떻게 되나요?', | |
'조교 신규 임용 기준은 무엇인가요?', | |
'교직원의 평일 근무시간은 어떻게 되나요?', | |
'직원 신규 임용 원칙은 무엇인가요?', | |
'직원 임용시 가산점이 있나요?', | |
'교원 업적의 심사 내용은 무엇인가요?', | |
'외국인 교원의 임기는 어떻게 되나요?', | |
'외국인 교원의 면직 기준은 무엇인가요?', | |
'기간제 계약직의 임기는 얼마정도인가요?', | |
'등록금 납부 방법은 무엇인가요?', | |
'교직 이수는 언제 신청이 가능한가요?', | |
'해외교류유학 지원자격은 어떻게 되나요?', | |
'만족도 조사 실행 대상은 누구인가요?', | |
'마이크로디그리의 유형은 무엇이 있나요?', | |
'장학금 관리 기관은 어디인가요?', | |
'학생 단체는 어떻게 등록하나요?', | |
'학생 설치물 중 금지된 설치물이 있나요?', | |
'비교과 교육과정의 종류는 무엇이 있나요?', | |
'안전사고예방계획은 어디에 제출해야 하나요?' | |
] | |
# 프롬프트 템플릿 | |
prompt_template = """당신은 한남대학교 규정집 도우미입니다. | |
반드시 한국어로만 답변해주세요. 영어나 다른 언어는 절대 사용하지 마세요. | |
주어진 문서 내용을 바탕으로 질문에 대해 정확하고 친절하게 한국어로 답변해주세요. | |
참고 문서: | |
{context} | |
질문: {question} | |
답변 지침: | |
- 이용자를 반기는 인사로 시작하세요 | |
- 반드시 한국어로만 답변하세요 | |
- 정중하고 친근한 말투를 사용하세요 | |
- 구체적이고 도움이 되는 정보를 제공하세요 | |
- 문서에서 답을 찾을 수 없으면 "죄송하지만 해당 정보를 규정집에서 찾을 수 없습니다"라고 답변하세요 | |
한국어 답변:""" | |
prompt = PromptTemplate( | |
template=prompt_template, | |
input_variables=["context", "question"] | |
) | |
def respond_with_groq(question, selected_q, model): | |
"""질문에 대한 답변을 생성하는 함수""" | |
# 선택된 질문이 있으면 그것을 사용 | |
if selected_q != "직접 입력": | |
question = selected_q | |
if not question.strip(): | |
return "질문을 입력해주세요." | |
if not GROQ_API_KEY: | |
return "❌ API 키가 설정되지 않았습니다. 관리자에게 문의하세요." | |
try: | |
# 벡터스토어 로드 | |
current_vectorstore = load_vectorstore() | |
if not current_vectorstore: | |
return "❌ 벡터스토어를 로드할 수 없습니다." | |
# LLM 설정 | |
llm = ChatGroq( | |
groq_api_key=GROQ_API_KEY, | |
model_name=model, | |
temperature=0.1, | |
max_tokens=1000 | |
) | |
# QA 체인 생성 | |
qa_chain = RetrievalQA.from_chain_type( | |
llm=llm, | |
chain_type="stuff", | |
retriever=current_vectorstore.as_retriever(search_kwargs={"k": 3}), | |
chain_type_kwargs={"prompt": prompt}, | |
return_source_documents=True | |
) | |
# 답변 생성 | |
result = qa_chain({"query": question}) | |
return result['result'] | |
except Exception as e: | |
return f"❌ 오류가 발생했습니다: {str(e)}" | |
def update_question(selected): | |
"""드롭다운 선택 시 질문을 업데이트하는 함수""" | |
if selected != "직접 입력": | |
return selected | |
return "" | |
# Gradio 인터페이스 생성 | |
with gr.Blocks(title="한남대학교 Q&A") as interface: | |
gr.HTML(""" | |
<div style="text-align: center; padding: 20px; background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px; margin-bottom: 20px;"> | |
<h1>🏫 한남대학교 규정집 Q&A</h1> | |
<p>한남대학교 규정집에 대한 질문에 AI가 답변해드립니다.</p> | |
</div> | |
""") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
question_dropdown = gr.Dropdown( | |
choices=["직접 입력"] + suggested_questions, | |
label="💡 자주 묻는 질문", | |
value="직접 입력" | |
) | |
question_input = gr.Textbox( | |
label="❓ 질문을 입력하세요", | |
placeholder="예: 졸업 요건은 무엇인가요?", | |
lines=3 | |
) | |
submit_btn = gr.Button("답변 받기", variant="primary", size="lg") | |
model_choice = gr.Radio( | |
choices=["llama3-70b-8192", "llama3-8b-8192"], | |
label="🤖 AI 모델 선택", | |
value="llama3-70b-8192" | |
) | |
with gr.Column(scale=2): | |
output = gr.Textbox( | |
label="💬 답변", | |
lines=15, | |
max_lines=20, | |
show_copy_button=True | |
) | |
# 이벤트 연결 | |
submit_btn.click( | |
fn=respond_with_groq, | |
inputs=[question_input, question_dropdown, model_choice], | |
outputs=output | |
) | |
question_dropdown.change( | |
fn=update_question, | |
inputs=question_dropdown, | |
outputs=question_input | |
) | |
# 앱 실행 | |
if __name__ == "__main__": | |
interface.launch() | |