From 8c859971d1570ecc25fc6516e924ceb26b114ed2 Mon Sep 17 00:00:00 2001 From: sal Date: Mon, 1 Jun 2026 10:33:15 +0900 Subject: [PATCH] Add thinking box UI and fix async event loop errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Show thinking progress in a separate animated box above chatbot (🤔 사고 중... while streaming, 💭 사고 완료 when answer starts) - Fix ValueError: add missing 5th yield value (thinking_box) to all respond() yield statements - Fix [Reset] and other sync handlers: replace asyncio.get_event_loop() .run_until_complete() with asyncio.run() for AnyIO thread compatibility Co-Authored-By: Claude Sonnet 4.6 --- app.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/app.py b/app.py index 6aa5225..103de3d 100644 --- a/app.py +++ b/app.py @@ -95,23 +95,20 @@ async def tts_speak(text: str) -> str | None: async def respond(message, history, show_thinking, user_id, use_tts, run_ids): if not message.strip(): - yield history, "", None, run_ids + yield history, "", None, run_ids, gr.update() return history = list(history) run_ids = list(run_ids) history.append({"role": "user", "content": message}) history.append({"role": "assistant", "content": ""}) - yield history, "", None, run_ids + yield history, "", None, run_ids, gr.update(value="", visible=False) collected_run_id: str | None = None tts_text = "" # 순수 답변만 누적 (TTS용) thinking_acc = "" # 사고 과정 누적 thinking_active = False - # 사고 과정 박스 초기화 - yield history, "", None, run_ids, gr.update(value="", visible=False) - try: async for token, run_id in api_client.chat(message, user_id, show_thinking): if run_id is not None: @@ -171,9 +168,7 @@ def handle_feedback(like_data: gr.LikeData, history, run_ids, user_id): rating = 1 if like_data.liked else -1 try: - asyncio.get_event_loop().run_until_complete( - api_client.save_feedback(user_id, user_msg, asst_msg, rating, run_id) - ) + asyncio.run(api_client.save_feedback(user_id, user_msg, asst_msg, rating, run_id)) except Exception as e: print(f"[Feedback] 저장 실패: {e}") @@ -184,7 +179,7 @@ def switch_user(user_id): def reset_chat(user_id): try: - asyncio.get_event_loop().run_until_complete(api_client.reset(user_id)) + asyncio.run(api_client.reset(user_id)) except Exception as e: print(f"[Reset] 실패: {e}") return [], [] @@ -199,7 +194,7 @@ def ingest_files(files): results = [] for path in paths: try: - result = asyncio.get_event_loop().run_until_complete(api_client.ingest(path)) + result = asyncio.run(api_client.ingest(path)) name = os.path.basename(path) results.append(f"{name} → {result.get('chunks', '?')}개 청크") except Exception as e: @@ -209,7 +204,7 @@ def ingest_files(files): def list_docs(): try: - sources = asyncio.get_event_loop().run_until_complete(api_client.list_documents()) + sources = asyncio.run(api_client.list_documents()) return [[os.path.basename(s), s] for s in sources] except Exception as e: return [[f"오류: {e}", ""]] @@ -219,7 +214,7 @@ def delete_doc(source): if not source.strip(): return "삭제할 파일 경로를 입력하세요.", list_docs() try: - asyncio.get_event_loop().run_until_complete(api_client.delete_document(source.strip())) + asyncio.run(api_client.delete_document(source.strip())) return f"삭제 완료: {os.path.basename(source.strip())}", list_docs() except Exception as e: return f"오류: {e}", list_docs()