jedick
Overlay custom timer on chatbot
a741ada
Raw
History Blame Contribute Delete
3.78 kB
import gradio as gr
import time
# Inspired by: https://www.gradio.app/guides/agents-and-tool-usage
# Custom timer solution described by Claude Sonnet 4.6:
# https://claude.ai/share/d7adc776-05f2-4c2b-a93a-9cf6089dd7be
def interact_with_agent(prompt, messages=[]):
"""Simulate generation of two assistant messages after delays"""
time.sleep(4)
messages.append(
gr.ChatMessage(
role="assistant", content="First message — gr.Chatbot() timer stops here"
)
)
yield messages
time.sleep(4)
messages.append(
gr.ChatMessage(role="assistant", content="Second message — Custom timer stops here")
)
yield messages
def str_to_message(content, role="user"):
return [gr.ChatMessage(role=role, content=content)]
timer_html = """
<div id="agent-timer" style="font-family: monospace;"></div>
"""
timer_js = """
let startTime = null;
let interval = null;
const el = element.querySelector('#agent-timer');
el.addEventListener('agent-timer:start', () => {
startTime = Date.now();
el.textContent = '⏱ 0.0s';
interval = setInterval(() => {
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
el.textContent = '⏱ ' + elapsed + 's';
}, 100);
});
el.addEventListener('agent-timer:stop', () => {
if (interval) {
clearInterval(interval);
interval = null;
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
el.textContent = '✓ ' + elapsed + 's';
}
});
"""
chatbot_overlay_css = """
#timer-display {
position: absolute;
bottom: 0px;
}
"""
with gr.Blocks() as demo:
with gr.Row():
with gr.Column():
gr.Markdown(
"""
## Gradio chatbot timer that stops at the last (not first) yielded agent message
**Submit any user message to launch a chatbot simulation that responds with two assistant messages with a 4-second delay before each one.**
- The built-in `gr.Chatbot` timer (*lower right*) stops after the first message.
- The custom timer (*lower left*) keeps going until the last message is yielded.
- The custom timer is implemented in JavaScript and CSS and depends on `gr.HTML` capabilities in Gradio 6.
"""
)
input = gr.Textbox(
"Start the timers!",
label="User message",
autofocus=True,
submit_btn=True,
)
gr.Markdown(
"""
### App history
- 2025-07-25: Create demo to support [Gradio issue #11637](https://github.com/gradio-app/gradio/issues/11637) (Gradio 5.38.2)
- 2026-05-30: Add custom timer using [gr.HTML](https://huggingface.co/blog/gradio-html-one-shot-apps) (Gradio 6.15.2)
"""
)
with gr.Column():
chatbot = gr.Chatbot()
gr.HTML(value=timer_html, js_on_load=timer_js, elem_id="timer-display")
input.submit(
# Update chatbot UI with user message immediately
str_to_message,
input,
chatbot,
).then(
# Start custom timer
lambda: None, None, None,
js="() => document.getElementById('agent-timer')"
"?.dispatchEvent(new CustomEvent('agent-timer:start'))",
).then(
# Update chatbot UI with assistant messages
interact_with_agent,
[input, chatbot],
chatbot,
).then(
# Stop custom timer
lambda: None, None, None,
js="() => document.getElementById('agent-timer')"
"?.dispatchEvent(new CustomEvent('agent-timer:stop'))",
)
demo.launch(css=chatbot_overlay_css)