Add thinking process visualization to WebUI
- Introduced "thinking box" UI to display intermediate thought processes. - Added CSS styling for the thinking box with scrollable and formatted design. - Updated response handling to show thinking progress and completion dynamically. - Enhanced Gradio outputs to include the new thinking box component.
This commit is contained in:
@@ -105,31 +105,53 @@ async def respond(message, history, show_thinking, user_id, use_tts, run_ids):
|
|||||||
yield history, "", None, run_ids
|
yield history, "", None, run_ids
|
||||||
|
|
||||||
collected_run_id: str | None = None
|
collected_run_id: str | None = None
|
||||||
tts_text = "" # 순수 답변만 누적 (메타 토큰 제외)
|
tts_text = "" # 순수 답변만 누적 (TTS용)
|
||||||
|
thinking_acc = "" # 사고 과정 누적
|
||||||
|
thinking_active = False
|
||||||
|
|
||||||
|
# 사고 과정 박스 초기화
|
||||||
|
yield history, "", None, run_ids, gr.update(value="", visible=False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async for token, run_id in api_client.chat(message, user_id, show_thinking):
|
async for token, run_id in api_client.chat(message, user_id, show_thinking):
|
||||||
if run_id is not None:
|
if run_id is not None:
|
||||||
collected_run_id = run_id
|
collected_run_id = run_id
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if isinstance(token, dict) and "__thinking" in token:
|
||||||
|
thinking_active = True
|
||||||
|
thinking_acc += token["__thinking"]
|
||||||
|
thinking_md = f"🤔 **사고 중...**\n\n{thinking_acc}▌"
|
||||||
|
yield history, "", None, run_ids, gr.update(value=thinking_md, visible=True)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if thinking_active:
|
||||||
|
# 첫 답변 토큰 도착 — 사고 완료 표시
|
||||||
|
thinking_active = False
|
||||||
|
yield history, "", None, run_ids, gr.update(
|
||||||
|
value=f"💭 **사고 완료**\n\n{thinking_acc}", visible=True
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(token, dict) and "__meta" in token:
|
if isinstance(token, dict) and "__meta" in token:
|
||||||
display_token = token["__meta"]
|
display_token = token["__meta"]
|
||||||
else:
|
else:
|
||||||
display_token = token
|
display_token = token
|
||||||
tts_text += display_token
|
tts_text += display_token
|
||||||
history[-1]["content"] += display_token
|
history[-1]["content"] += display_token
|
||||||
yield history, "", None, run_ids
|
yield history, "", None, run_ids, gr.update()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
history[-1]["content"] += f"\n\n[오류: {e}]"
|
history[-1]["content"] += f"\n\n[오류: {e}]"
|
||||||
yield history, "", None, run_ids
|
yield history, "", None, run_ids, gr.update()
|
||||||
return
|
return
|
||||||
|
|
||||||
run_ids.append(collected_run_id)
|
run_ids.append(collected_run_id)
|
||||||
|
|
||||||
if use_tts:
|
if use_tts:
|
||||||
audio_path = await tts_speak(tts_text)
|
audio_path = await tts_speak(tts_text)
|
||||||
yield history, "", audio_path, run_ids
|
yield history, "", audio_path, run_ids, gr.update()
|
||||||
else:
|
else:
|
||||||
yield history, "", None, run_ids
|
yield history, "", None, run_ids, gr.update()
|
||||||
|
|
||||||
|
|
||||||
def handle_feedback(like_data: gr.LikeData, history, run_ids, user_id):
|
def handle_feedback(like_data: gr.LikeData, history, run_ids, user_id):
|
||||||
@@ -205,7 +227,22 @@ def delete_doc(source):
|
|||||||
|
|
||||||
# ── UI 구성 ──────────────────────────────────────────────────────
|
# ── UI 구성 ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
with gr.Blocks(title="율봇") as demo:
|
_THINKING_CSS = """
|
||||||
|
.thinking-box {
|
||||||
|
background: #f9f9f9;
|
||||||
|
border-left: 3px solid #bbb;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
max-height: 220px;
|
||||||
|
overflow-y: auto;
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: #555;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
with gr.Blocks(title="율봇", css=_THINKING_CSS) as demo:
|
||||||
gr.Markdown("# 율봇\n육아·금융 전문 AI 상담 도우미")
|
gr.Markdown("# 율봇\n육아·금융 전문 AI 상담 도우미")
|
||||||
|
|
||||||
user_state = gr.State(DEFAULT_USER)
|
user_state = gr.State(DEFAULT_USER)
|
||||||
@@ -220,6 +257,11 @@ with gr.Blocks(title="율봇") as demo:
|
|||||||
scale=1,
|
scale=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
thinking_box = gr.Markdown(
|
||||||
|
value="",
|
||||||
|
visible=False,
|
||||||
|
elem_classes=["thinking-box"],
|
||||||
|
)
|
||||||
chatbot = gr.Chatbot(label="율봇", height=500)
|
chatbot = gr.Chatbot(label="율봇", height=500)
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
msg_box = gr.Textbox(
|
msg_box = gr.Textbox(
|
||||||
@@ -260,12 +302,12 @@ with gr.Blocks(title="율봇") as demo:
|
|||||||
send_btn.click(
|
send_btn.click(
|
||||||
respond,
|
respond,
|
||||||
inputs=[msg_box, chatbot, show_thinking, user_state, use_tts, run_ids_state],
|
inputs=[msg_box, chatbot, show_thinking, user_state, use_tts, run_ids_state],
|
||||||
outputs=[chatbot, msg_box, tts_output, run_ids_state],
|
outputs=[chatbot, msg_box, tts_output, run_ids_state, thinking_box],
|
||||||
)
|
)
|
||||||
msg_box.submit(
|
msg_box.submit(
|
||||||
respond,
|
respond,
|
||||||
inputs=[msg_box, chatbot, show_thinking, user_state, use_tts, run_ids_state],
|
inputs=[msg_box, chatbot, show_thinking, user_state, use_tts, run_ids_state],
|
||||||
outputs=[chatbot, msg_box, tts_output, run_ids_state],
|
outputs=[chatbot, msg_box, tts_output, run_ids_state, thinking_box],
|
||||||
)
|
)
|
||||||
reset_btn.click(reset_chat, inputs=[user_state], outputs=[chatbot, run_ids_state])
|
reset_btn.click(reset_chat, inputs=[user_state], outputs=[chatbot, run_ids_state])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user