""" 소방 복무관리 RAG 챗봇 깔끔하고 심플한 Gradio UI + 관리자 탭 """ import gradio as gr from rag import chat from pdf_processor import process_pdf from database import get_all_documents import uuid import os # 세션별 대화 기록 저장 conversation_history = {} # 관리자 비밀번호 (환경변수로 설정 권장) ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "admin1234") def respond(message: str, history: list, session_id: str) -> tuple: """채팅 응답 처리""" if not message.strip(): return "", history if session_id not in conversation_history: conversation_history[session_id] = [] response = chat(message, conversation_history[session_id]) conversation_history[session_id].append({ "user": message, "assistant": response }) history.append((message, response)) return "", history def clear_chat(session_id: str) -> tuple: """대화 초기화""" if session_id in conversation_history: conversation_history[session_id] = [] return [], "" def verify_admin(password: str) -> tuple: """관리자 인증""" if password == ADMIN_PASSWORD: return gr.update(visible=False), gr.update(visible=True), "✅ 인증 성공" return gr.update(visible=True), gr.update(visible=False), "❌ 비밀번호가 틀렸습니다" def upload_pdf(file, title: str, category: str) -> str: """PDF 업로드 및 처리""" if file is None: return "❌ PDF 파일을 선택해주세요." if not title.strip(): return "❌ 문서 제목을 입력해주세요." result = process_pdf( pdf_path=file.name, title=title.strip(), category=category ) return result["message"] def get_documents_list() -> list: """저장된 문서 목록 조회""" docs = get_all_documents() if not docs: return [["데이터 없음", "-", "-"]] return [[d.get("title", ""), d.get("category", ""), str(d.get("id", ""))] for d in docs] # 커스텀 CSS custom_css = """ .gradio-container { max-width: 900px !important; margin: auto !important; font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, sans-serif !important; } .header { text-align: center; padding: 20px 0; border-bottom: 1px solid #e5e7eb; margin-bottom: 20px; } .header h1 { color: #dc2626; font-size: 1.8rem; font-weight: 700; margin: 0; } .header p { color: #6b7280; font-size: 0.9rem; margin-top: 8px; } .chatbot { border-radius: 12px !important; border: 1px solid #e5e7eb !important; box-shadow: 0 1px 3px rgba(0,0,0,0.1) !important; } .input-area { border-radius: 12px !important; border: 1px solid #e5e7eb !important; } .primary-btn { background-color: #dc2626 !important; border: none !important; border-radius: 8px !important; color: white !important; font-weight: 600 !important; } .primary-btn:hover { background-color: #b91c1c !important; } .secondary-btn { background-color: #f3f4f6 !important; border: 1px solid #e5e7eb !important; border-radius: 8px !important; color: #374151 !important; } .admin-section { background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 20px; margin: 10px 0; } .upload-section { background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 12px; padding: 20px; margin: 10px 0; } .footer { text-align: center; padding: 16px 0; color: #9ca3af; font-size: 0.8rem; } """ # Gradio 앱 구성 with gr.Blocks(css=custom_css, title="소방 복무관리 챗봇", theme=gr.themes.Soft()) as app: session_id = gr.State(value=str(uuid.uuid4())) # 헤더 gr.HTML("""
복무, 근무, 휴가 등 소방 업무에 관해 질문해주세요