| import os |
| import gradio as gr |
| import json |
| import logging |
| from app.app import app as flask_app |
| from flask import json as flask_json |
| from retrying import retry |
|
|
| |
| logging.basicConfig( |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', |
| level=logging.DEBUG |
| ) |
| logger = logging.getLogger(__name__) |
|
|
| |
| @retry(tries=5, delay=1, backoff=2) |
| def init_flask_client(): |
| """๋ฐฑ๊ทธ๋ผ์ด๋ ์คํ Flask ์๋ฒ์ ์ฐ๊ฒฐํ๋ ํด๋ผ์ด์ธํธ ์ด๊ธฐํ""" |
| try: |
| test_client = flask_app.test_client() |
| logger.info("Flask ํ
์คํธ ํด๋ผ์ด์ธํธ ์ด๊ธฐํ ์ฑ๊ณต") |
| return test_client |
| except Exception as e: |
| logger.error(f"Flask ํ
์คํธ ํด๋ผ์ด์ธํธ ์ด๊ธฐํ ์คํจ: {e}") |
| raise e |
|
|
| |
| def format_source_info(sources, prefix=""): |
| """๊ฒ์ ๊ฒฐ๊ณผ ์์ค ์ ๋ณด๋ฅผ ํ์ํ |
| |
| Args: |
| sources: ์์ค ์ ๋ณด ๋ฆฌ์คํธ |
| prefix: ๋ก๊ทธ ๋ฉ์์ง ์ ๋์ฌ (๊ธฐ๋ณธ๊ฐ: "") |
| |
| Returns: |
| ํ์ํ๋ ์์ค ์ ๋ณด ๋ฌธ์์ด |
| """ |
| source_info = "" |
| if sources and len(sources) > 0: |
| logger.debug(f"{prefix}์์ค ์ ๋ณด ํฌ๋งทํ
: {len(sources)}๊ฐ ์์ค: {json.dumps(sources, ensure_ascii=False, indent=2)}") |
| |
| source_list = [] |
| for src in sources: |
| source_text = src["source"] |
| |
| if "id" in src: |
| logger.debug(f"{prefix}ID ํ๋ ๋ฐ๊ฒฌ: {src['id']}") |
| source_text += f" (ID: {src['id']})" |
| source_list.append(source_text) |
| |
| if source_list: |
| source_info = "\n\n์ฐธ์กฐ ์์ค:\n" + "\n".join(source_list) |
| logger.debug(f"{prefix}์ต์ข
์์ค ์ ๋ณด ํ์: {source_info}") |
| |
| return source_info |
|
|
| |
| flask_client = init_flask_client() |
|
|
| |
| logger.info(f"Gradio ๋ฒ์ : {gr.__version__}") |
|
|
| |
| with gr.Blocks(title="RAG ๊ฒ์ ์ฑ๋ด with ์์ฑ์ธ์") as demo: |
| gr.HTML(""" |
| <div style="text-align: center; max-width: 800px; margin: 0 auto;"> |
| <h1>RAG ๊ฒ์ ์ฑ๋ด with ์์ฑ์ธ์</h1> |
| <p>ํ
์คํธ ๋๋ ์์ฑ์ผ๋ก ์ง๋ฌธ์ ์
๋ ฅํ์ธ์.</p> |
| </div> |
| """) |
|
|
| with gr.Tab("ํ
์คํธ ์ฑ"): |
| text_input = gr.Textbox(label="์ง๋ฌธ ์
๋ ฅ", placeholder="์ฌ๊ธฐ์ ์ง๋ฌธ์ ์
๋ ฅํ์ธ์...") |
| text_output = gr.Textbox(label="์๋ต", interactive=False) |
| text_button = gr.Button("์ง๋ฌธ ์ ์ถ") |
|
|
| with gr.Tab("์์ฑ ์ฑ"): |
| with gr.Row(): |
| |
| audio_input = gr.Audio( |
| label="์์ฑ ์
๋ ฅ", |
| type="filepath", |
| sources=["microphone"], |
| show_label=True, |
| waveform_options={"show_controls": True, "normalize": True}, |
| interactive=True |
| ) |
| |
| audio_transcription = gr.Textbox(label="์ธ์๋ ํ
์คํธ", interactive=False) |
| audio_output = gr.Textbox(label="์๋ต", interactive=False) |
| gr.Markdown(""" |
| <div style="text-align: center; margin: 10px 0;"> |
| <p>๋
น์ ์ ์ง ๋ฒํผ์ ๋๋ฅด๋ฉด ์๋์ผ๋ก ์์ฑ์ด ์ ์ก๋ฉ๋๋ค.</p> |
| </div> |
| """) |
|
|
| with gr.Tab("๋ฌธ์ ์
๋ก๋"): |
| doc_input = gr.File(label="๋ฌธ์ ์
๋ก๋", file_types=[".txt", ".md", ".pdf", ".docx", ".csv"]) |
| doc_output = gr.Textbox(label="์
๋ก๋ ๊ฒฐ๊ณผ", interactive=False) |
| doc_button = gr.Button("๋ฌธ์ ์
๋ก๋") |
|
|
| |
| def handle_text_chat(query): |
| if not query: |
| return "์ง๋ฌธ์ ์
๋ ฅํ์ธ์." |
| try: |
| logger.info("ํ
์คํธ ์ฑ ์์ฒญ: /api/chat") |
| response = flask_client.post("/api/chat", json={"query": query}) |
| data = flask_json.loads(response.data) |
| |
| |
| logger.info(f"API ์๋ต ๊ตฌ์กฐ: {json.dumps(data, ensure_ascii=False, indent=2)[:500]}...") |
| |
| if "error" in data: |
| logger.error(f"ํ
์คํธ ์ฑ ์ค๋ฅ: {data['error']}") |
| return data["error"] |
| |
| |
| source_info = "" |
| if "sources" in data and data["sources"]: |
| source_info = format_source_info(data["sources"]) |
| |
| |
| return data["answer"] + source_info |
| except Exception as e: |
| logger.error(f"ํ
์คํธ ์ฑ ์ฒ๋ฆฌ ์คํจ: {str(e)}") |
| return f"์ฒ๋ฆฌ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}" |
|
|
| |
| def handle_voice_chat(audio_file): |
| if not audio_file: |
| return "", "์์ฑ์ ์
๋ก๋ํ์ธ์." |
| try: |
| logger.info("์์ฑ ์ฑ ์์ฒญ: /api/voice") |
| with open(audio_file, "rb") as f: |
| |
| response = flask_client.post( |
| "/api/voice", |
| data={"audio": (f, "audio_file")} |
| ) |
| data = flask_json.loads(response.data) |
| |
| |
| logger.info(f"[์์ฑ์ฑ] API ์๋ต ๊ตฌ์กฐ: {json.dumps(data, ensure_ascii=False, indent=2)[:500]}...") |
| |
| if "error" in data: |
| logger.error(f"์์ฑ ์ฑ ์ค๋ฅ: {data['error']}") |
| return "", data["error"] |
| |
| |
| source_info = "" |
| if "sources" in data and data["sources"]: |
| source_info = format_source_info(data["sources"], prefix="[์์ฑ์ฑ] ") |
| |
| |
| return data["transcription"], data["answer"] + source_info |
| except Exception as e: |
| logger.error(f"์์ฑ ์ฑ ์ฒ๋ฆฌ ์คํจ: {str(e)}") |
| return "", f"์ฒ๋ฆฌ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}" |
|
|
| |
| def handle_doc_upload(doc_file): |
| if not doc_file: |
| return "๋ฌธ์๋ฅผ ์
๋ก๋ํ์ธ์." |
| try: |
| logger.info(f"๋ฌธ์ ์
๋ก๋ ์์ฒญ: /api/upload, ํ์ผ๋ช
: {doc_file.name}") |
| file_extension = os.path.splitext(doc_file.name)[1].lower() |
| logger.info(f"ํ์ผ ํ์ฅ์: {file_extension}") |
| |
| with open(doc_file, "rb") as f: |
| response = flask_client.post( |
| "/api/upload", |
| data={"document": (f, doc_file.name)} |
| ) |
| data = flask_json.loads(response.data) |
| if "error" in data: |
| logger.error(f"๋ฌธ์ ์
๋ก๋ ์ค๋ฅ: {data['error']}") |
| return data["error"] |
| return data["message"] |
| except Exception as e: |
| logger.error(f"๋ฌธ์ ์
๋ก๋ ์ฒ๋ฆฌ ์คํจ: {str(e)}") |
| return f"์ฒ๋ฆฌ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}" |
|
|
| |
| text_button.click( |
| fn=handle_text_chat, |
| inputs=text_input, |
| outputs=text_output |
| ) |
| |
| |
| audio_input.change( |
| fn=handle_voice_chat, |
| inputs=audio_input, |
| outputs=[audio_transcription, audio_output] |
| ) |
| |
| doc_button.click( |
| fn=handle_doc_upload, |
| inputs=doc_input, |
| outputs=doc_output |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch(server_port=7860) |