Spaces:
Sleeping
Sleeping
| """ | |
| HuggingFace Spaces์ฉ Gradio ์ฑ | |
| Financial RAG with Metacognitive Agent | |
| """ | |
| import gradio as gr | |
| import os | |
| import sys | |
| from loguru import logger | |
| import asyncio | |
| from typing import Dict, Tuple | |
| # ๋ก๊น ์ค์ | |
| logger.remove() | |
| logger.add( | |
| sys.stdout, | |
| format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <level>{message}</level>", | |
| level="INFO" | |
| ) | |
| # ํ๋ก์ ํธ ๋ฃจํธ๋ฅผ Python ๊ฒฝ๋ก์ ์ถ๊ฐ | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | |
| from app.metacognitive_agent import MetaCognitiveAgent | |
| from app.rag_pipeline import RAGPipeline | |
| from services.vector_store import VectorStore | |
| from services.embedder import Embedder | |
| from utils.config import settings | |
| # ๊ธ๋ก๋ฒ ๋ณ์ | |
| rag_pipeline = None | |
| def setup_vector_db(): | |
| """๋ฒกํฐ DB ์๋ ์ค์ (์์ผ๋ฉด ๋ค์ด๋ก๋ ๋๋ ์์ฑ)""" | |
| db_path = settings.chroma_persist_directory | |
| # ๋ฒกํฐ DB๊ฐ ์ด๋ฏธ ์กด์ฌํ๊ณ ๋น์ด์์ง ์์์ง ํ์ธ | |
| if os.path.exists(db_path): | |
| if os.listdir(db_path): | |
| logger.info("โ Vector DB already exists. Skipping setup.") | |
| return True | |
| logger.info("๐ฅ Vector DB not found. Setting up...") | |
| os.makedirs(db_path, exist_ok=True) | |
| # ์ต์ 1: GitHub Release์์ ๋ค์ด๋ก๋ ์๋ | |
| try: | |
| import urllib.request | |
| import tarfile | |
| release_url = "https://github.com/csjjin2025/Hallucination_and_Deception_for_financial_RAG/releases/download/v1.0/chroma_db.tar.gz" | |
| tar_path = "./data/chroma_db.tar.gz" | |
| logger.info(f"Attempting to download from {release_url}...") | |
| urllib.request.urlretrieve(release_url, tar_path) | |
| # ํ์ผ ํฌ๊ธฐ ํ์ธ | |
| file_size = os.path.getsize(tar_path) | |
| if file_size > 1000: | |
| logger.info(f"๐ฆ Extracting vector DB ({file_size} bytes)...") | |
| with tarfile.open(tar_path, 'r:gz') as tar: | |
| tar.extractall(path='./data/') | |
| os.remove(tar_path) | |
| logger.info("โ Vector DB downloaded and extracted!") | |
| return True | |
| else: | |
| logger.warning(f"Downloaded file too small ({file_size} bytes)") | |
| os.remove(tar_path) | |
| except Exception as e: | |
| logger.warning(f"Failed to download from Release: {e}") | |
| # ์ต์ 2: ํ ์คํธ DB ์์ฑ | |
| try: | |
| logger.info("โ ๏ธ Creating test DB with sample data...") | |
| import subprocess | |
| result = subprocess.run( | |
| ["python", "scripts/quick_setup_test_db.py"], | |
| capture_output=True, | |
| text=True, | |
| timeout=300 | |
| ) | |
| if result.returncode == 0: | |
| logger.info("โ Test DB created successfully!") | |
| return True | |
| else: | |
| logger.error(f"Test DB creation failed: {result.stderr}") | |
| return False | |
| except Exception as e: | |
| logger.error(f"Failed to create test DB: {e}") | |
| return False | |
| def initialize_rag_system(): | |
| """RAG ์์คํ ์ด๊ธฐํ""" | |
| global rag_pipeline | |
| try: | |
| logger.info("=" * 80) | |
| logger.info("๐ Financial RAG ์์คํ ์ด๊ธฐํ ์ค...") | |
| logger.info("=" * 80) | |
| # 0. Vector DB ์๋ ์ค์ | |
| logger.info("0๏ธโฃ Vector DB ์ค์ ํ์ธ ์ค...") | |
| if not setup_vector_db(): | |
| logger.error("โ Vector DB ์ค์ ์คํจ") | |
| return False | |
| # 1. Vector Store ์ด๊ธฐํ | |
| logger.info("1๏ธโฃ Vector Store ๋ก๋ฉ ์ค...") | |
| vector_store = VectorStore( | |
| persist_directory=settings.chroma_persist_directory, | |
| collection_name=settings.collection_name | |
| ) | |
| doc_count = vector_store.collection.count() | |
| logger.info(f"โ Vector Store ๋ก๋ฉ ์๋ฃ ({doc_count}๊ฐ ๋ฌธ์)") | |
| # 2. Embedder ์ด๊ธฐํ | |
| logger.info("2๏ธโฃ Embedder ์ด๊ธฐํ ์ค...") | |
| embedder = Embedder( | |
| model_type=settings.embedding_model, | |
| model_name=settings.embedding_model_name, | |
| openai_api_key=settings.openai_api_key, | |
| cohere_api_key=settings.cohere_api_key | |
| ) | |
| logger.info(f"โ Embedder ์ด๊ธฐํ ์๋ฃ ({embedder.get_embedding_dimension()}์ฐจ์)") | |
| # 3. Metacognitive Agent ์ด๊ธฐํ | |
| logger.info("3๏ธโฃ Metacognitive Agent ์ด๊ธฐํ ์ค...") | |
| agent = MetaCognitiveAgent(api_key=settings.anthropic_api_key) | |
| logger.info(f"โ Agent ์ด๊ธฐํ ์๋ฃ ({agent.model})") | |
| # 4. RAG Pipeline ์์ฑ | |
| logger.info("4๏ธโฃ RAG Pipeline ์์ฑ ์ค...") | |
| rag_pipeline = RAGPipeline( | |
| vector_store=vector_store, | |
| embedder=embedder, | |
| metacognitive_agent=agent | |
| ) | |
| logger.info("โ RAG Pipeline ์์ฑ ์๋ฃ") | |
| logger.info("=" * 80) | |
| logger.info("โจ ์์คํ ์ค๋น ์๋ฃ!") | |
| logger.info(f"๐ Vector DB: {doc_count}๊ฐ ๋ฌธ์") | |
| logger.info(f"๐ค Model: {agent.model}") | |
| logger.info("=" * 80) | |
| return True | |
| except Exception as e: | |
| logger.error(f"โ ์ด๊ธฐํ ์คํจ: {str(e)}") | |
| import traceback | |
| logger.error(traceback.format_exc()) | |
| return False | |
| def format_sources(sources: list) -> str: | |
| """์ถ์ฒ ๋ฌธ์ ํฌ๋งทํ """ | |
| if not sources: | |
| return "์ถ์ฒ ๋ฌธ์๊ฐ ์์ต๋๋ค." | |
| formatted = "### ๐ ์ฐธ๊ณ ๋ฌธ์\n\n" | |
| for idx, source in enumerate(sources[:3], 1): # ์์ 3๊ฐ๋ง ํ์ | |
| similarity = source.get('similarity', 0) * 100 | |
| filename = source.get('source_filename', 'unknown') | |
| text = source.get('text', '')[:300] # ์ 300์๋ง | |
| formatted += f"**{idx}. {filename}** (์ ์ฌ๋: {similarity:.1f}%)\n" | |
| formatted += f"> {text}...\n\n" | |
| return formatted | |
| def format_metacognition(metacognition: Dict) -> str: | |
| """๋ฉํ์ธ์ง ๊ณผ์ ํฌ๋งทํ """ | |
| if not metacognition: | |
| return "" | |
| history = metacognition.get('thinking_history', []) | |
| iterations = metacognition.get('iterations', 0) | |
| formatted = f"\n\n### ๐ง ๋ฉํ์ธ์ง ๊ณผ์ ({iterations}ํ ๋ฐ๋ณต)\n\n" | |
| for idx, step in enumerate(history, 1): | |
| stage = step.get('stage', 'unknown') | |
| content = step.get('content', '') | |
| stage_emoji = { | |
| 'planning': '๐', | |
| 'monitoring': '๐๏ธ', | |
| 'evaluation': 'โ ', | |
| 'revision': '๐' | |
| }.get(stage, '๐ญ') | |
| formatted += f"**{stage_emoji} {stage.capitalize()}**\n" | |
| formatted += f"{content}\n\n" | |
| return formatted | |
| async def process_query_async(question: str, top_k: int, enable_metacognition: bool) -> Tuple[str, str]: | |
| """๋น๋๊ธฐ ์ฟผ๋ฆฌ ์ฒ๋ฆฌ""" | |
| if not rag_pipeline: | |
| return "โ ์์คํ ์ด ์ด๊ธฐํ๋์ง ์์์ต๋๋ค.", "" | |
| if not question.strip(): | |
| return "โ ์ง๋ฌธ์ ์ ๋ ฅํด์ฃผ์ธ์.", "" | |
| try: | |
| logger.info(f"๐ ์ง๋ฌธ: {question}") | |
| # RAG ํ์ดํ๋ผ์ธ์ผ๋ก ์ฟผ๋ฆฌ ์ฒ๋ฆฌ | |
| result = await rag_pipeline.query( | |
| question=question, | |
| top_k=top_k, | |
| enable_metacognition=enable_metacognition | |
| ) | |
| # ๋ต๋ณ ํฌ๋งทํ | |
| answer = result.get('answer', '๋ต๋ณ์ ์์ฑํ ์ ์์ต๋๋ค.') | |
| sources = result.get('sources', []) | |
| metacognition = result.get('metacognition', None) | |
| # ์ถ๋ ฅ ๊ตฌ์ฑ | |
| main_output = f"## ๐ฌ ๋ต๋ณ\n\n{answer}\n\n" | |
| main_output += format_sources(sources) | |
| # ๋ฉํ์ธ์ง ๊ณผ์ (๋ณ๋ ํญ) | |
| meta_output = format_metacognition(metacognition) if metacognition else "๋ฉํ์ธ์ง๊ฐ ๋นํ์ฑํ๋์์ต๋๋ค." | |
| logger.info("โ ๋ต๋ณ ์์ฑ ์๋ฃ") | |
| return main_output, meta_output | |
| except Exception as e: | |
| error_msg = f"โ ์ค๋ฅ ๋ฐ์: {str(e)}" | |
| logger.error(error_msg) | |
| import traceback | |
| logger.error(traceback.format_exc()) | |
| return error_msg, "" | |
| def process_query(question: str, top_k: int, enable_metacognition: bool) -> Tuple[str, str]: | |
| """Gradio์ฉ ๋๊ธฐ ๋ํผ""" | |
| loop = asyncio.new_event_loop() | |
| asyncio.set_event_loop(loop) | |
| try: | |
| return loop.run_until_complete(process_query_async(question, top_k, enable_metacognition)) | |
| finally: | |
| loop.close() | |
| # Gradio ์ธํฐํ์ด์ค ๊ตฌ์ฑ | |
| def create_interface(): | |
| """Gradio ์ธํฐํ์ด์ค ์์ฑ""" | |
| with gr.Blocks(theme=gr.themes.Soft(), title="Financial RAG with Metacognitive Agent") as demo: | |
| gr.Markdown(""" | |
| # ๐ผ Financial RAG System | |
| ### ๋ฉํ์ธ์ง ์์ด์ ํธ ๊ธฐ๋ฐ ๊ธ์ต/๊ฒฝ์ ์ง์์๋ต ์์คํ | |
| ์ด ์์คํ ์ ๊ธ์ต/๊ฒฝ์ ๋ ผ๋ฌธ์ ๊ธฐ๋ฐ์ผ๋ก ์ง๋ฌธ์ ๋ต๋ณํฉ๋๋ค. | |
| ๋ฉํ์ธ์ง ๊ธฐ๋ฅ์ ํ์ฑํํ๋ฉด ๋ ๊น์ด ์๋ ์ฌ๊ณ ๊ณผ์ ์ ๊ฑฐ์ณ ๋ต๋ณ์ ์์ฑํฉ๋๋ค. | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| question_input = gr.Textbox( | |
| label="๐ฌ ์ง๋ฌธ์ ์ ๋ ฅํ์ธ์", | |
| placeholder="์: ํฌํธํด๋ฆฌ์ค ๋ค๊ฐํ๋ ๋ฌด์์ธ๊ฐ์?", | |
| lines=3 | |
| ) | |
| with gr.Row(): | |
| top_k_slider = gr.Slider( | |
| minimum=1, | |
| maximum=10, | |
| value=5, | |
| step=1, | |
| label="๐ ๊ฒ์ํ ๋ฌธ์ ๊ฐ์" | |
| ) | |
| metacognition_check = gr.Checkbox( | |
| label="๐ง ๋ฉํ์ธ์ง ํ์ฑํ", | |
| value=True, | |
| info="๋ ๊น์ด ์๋ ์ฌ๊ณ ๊ณผ์ (์ฒ๋ฆฌ ์๊ฐ ์ฆ๊ฐ)" | |
| ) | |
| submit_btn = gr.Button("๐ ์ง๋ฌธํ๊ธฐ", variant="primary", size="lg") | |
| gr.Markdown(""" | |
| ### ๐ก ์ฌ์ฉ ํ | |
| - **๋ฉํ์ธ์ง ํ์ฑํ**: Planning โ Monitoring โ Evaluation โ Revision ๊ณผ์ ์ ๊ฑฐ์ณ ์ ์คํ ๋ต๋ณ ์์ฑ | |
| - **๋ฉํ์ธ์ง ๋นํ์ฑํ**: ๋น ๋ฅธ ๋ต๋ณ ์์ฑ | |
| - **๊ฒ์ ๋ฌธ์ ๊ฐ์**: ๋ง์์๋ก ๋ ๋ง์ ์ ๋ณด๋ฅผ ์ฐธ๊ณ ํ์ง๋ง ์ฒ๋ฆฌ ์๊ฐ ์ฆ๊ฐ | |
| """) | |
| with gr.Column(scale=3): | |
| with gr.Tabs(): | |
| with gr.Tab("๐ ๋ต๋ณ ๋ฐ ์ถ์ฒ"): | |
| answer_output = gr.Markdown(label="๋ต๋ณ") | |
| with gr.Tab("๐ง ๋ฉํ์ธ์ง ๊ณผ์ "): | |
| metacognition_output = gr.Markdown(label="์ฌ๊ณ ๊ณผ์ ") | |
| # ์ด๋ฒคํธ ํธ๋ค๋ฌ | |
| submit_btn.click( | |
| fn=process_query, | |
| inputs=[question_input, top_k_slider, metacognition_check], | |
| outputs=[answer_output, metacognition_output] | |
| ) | |
| # Enter ํค๋ก๋ ์ ์ถ | |
| question_input.submit( | |
| fn=process_query, | |
| inputs=[question_input, top_k_slider, metacognition_check], | |
| outputs=[answer_output, metacognition_output] | |
| ) | |
| gr.Markdown(""" | |
| --- | |
| ### ๐ ์์คํ ์ ๋ณด | |
| - **๋ชจ๋ธ**: Claude 3.5 Sonnet | |
| - **์๋ฒ ๋ฉ**: sentence-transformers/all-MiniLM-L6-v2 | |
| - **๋ฒกํฐ DB**: ChromaDB | |
| """) | |
| return demo | |
| # ๋ฉ์ธ ์คํ | |
| if __name__ == "__main__": | |
| # ์์คํ ์ด๊ธฐํ | |
| logger.info("์์คํ ์ด๊ธฐํ ์์...") | |
| success = initialize_rag_system() | |
| if not success: | |
| logger.error("์์คํ ์ด๊ธฐํ ์คํจ. ์ข ๋ฃํฉ๋๋ค.") | |
| sys.exit(1) | |
| # Gradio ์ฑ ์คํ | |
| demo = create_interface() | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False | |
| ) | |