| # P3 Bug: Progress Bar Positioning/Overlap in ChatInterface |
|
|
| **Severity**: P3 (Low - UX polish) |
| **Status**: Open |
| **Discovered**: 2025-12-01 |
| **Reporter**: Internal QA |
|
|
| ## Symptom |
|
|
| The `gr.Progress()` bar renders in a strange position when used inside `ChatInterface`: |
| - Progress bar appears to "float" in the middle of the chat output |
| - Text overlaps with progress bar elements |
| - Bar appears static/stuck at certain percentages |
| - Visual artifact: `Round 2/5 (~2m 15s remaining) - 48.0%` renders both above and inside bar |
|
|
| ## Screenshot Evidence |
|
|
| Progress bar appears inline between chat messages rather than in a fixed position (top/bottom of component). |
|
|
| ## Root Cause Analysis |
|
|
| ### The Conflict |
|
|
| We're mixing **two different progress mechanisms**: |
|
|
| 1. **`gr.Progress()`** - Gradio's general-purpose progress bar API |
| - Designed for `gr.Interface` and `gr.Blocks` functions |
| - Renders as an overlay on the output component |
|
|
| 2. **`ChatInterface.show_progress`** - Built-in chat progress |
| - Options: `"full"`, `"minimal"`, `"hidden"` |
| - `"full"` = spinner + runtime display |
| - `"minimal"` = runtime display only (default) |
| |
| When both are used together in `ChatInterface`, the `gr.Progress()` bar fights for position with the chat's streaming output, causing visual glitches. |
| |
| ### Current Implementation (`src/app.py`) |
| |
| ```python |
| async def research_agent( |
| message: str, |
| history: list[dict[str, Any]], |
| ... |
| progress: gr.Progress = gr.Progress(), # <- ISSUE: Manual progress bar |
| ) -> AsyncGenerator[str, None]: |
| ... |
| if event.type == "started": |
| progress(0, desc="Starting research...") # <- Updates overlay |
| elif event.type == "progress": |
| progress(p, desc=event.message) # <- Conflicts with chat streaming |
| ``` |
| |
| ### Gradio Documentation |
| |
| From [Gradio ChatInterface Docs](https://www.gradio.app/docs/gradio/chatinterface): |
| |
| > `show_progress`: how to show the progress animation while event is running: 'full' shows a spinner which covers the output component area as well as a runtime display in the upper right corner, 'minimal' only shows the runtime display, 'hidden' shows no progress animation at all |
| |
| From [GitHub Issue #5967](https://github.com/gradio-app/gradio/issues/5967): |
| |
| > `gr.Progress` is "not integrated with ChatInterface or Chatbots" - known limitation. |
| |
| ## Impact |
| |
| | Aspect | Impact | |
| |--------|--------| |
| | Functionality | None - app works correctly | |
| | UX | Visual confusion, looks unprofessional | |
| | Accessibility | May cause screen reader confusion | |
| |
| ## Proposed Solutions |
| |
| ### Option 1: Remove `gr.Progress()` - Use Chat Text Only (RECOMMENDED) |
| |
| Remove the `gr.Progress()` parameter entirely and rely on our existing emoji status messages: |
| |
| ```python |
| async def research_agent( |
| message: str, |
| history: list[dict[str, Any]], |
| domain: str = "sexual_health", |
| api_key: str = "", |
| api_key_state: str = "", |
| # REMOVED: progress: gr.Progress = gr.Progress(), |
| ) -> AsyncGenerator[str, None]: |
| ... |
| # Keep emoji status updates in chat output |
| # ⏱️ **PROGRESS**: Round 1/5 (~3m 0s remaining) |
| # These are already being yielded to the chat |
| ``` |
| |
| **Pros**: |
| - Simplest solution |
| - No CSS hacks |
| - Status is visible in chat history |
| - Works with ChatInterface's built-in progress |
| |
| **Cons**: |
| - No visual progress bar (just text status) |
| |
| ### Option 2: Use `show_progress="full"` Parameter |
| |
| Add explicit `show_progress` to ChatInterface and remove `gr.Progress()`: |
| |
| ```python |
| demo = gr.ChatInterface( |
| fn=research_agent, |
| title="🍆 DeepBoner", |
| show_progress="full", # Built-in spinner + runtime |
| ... |
| ) |
| ``` |
| |
| **Pros**: |
| - Uses Gradio's intended mechanism |
| - Consistent with Gradio UX patterns |
| |
| **Cons**: |
| - Less granular (no percentage, no custom desc) |
| |
| ### Option 3: Custom Progress Component with CSS (COMPLEX) |
| |
| Wrap ChatInterface in `gr.Blocks` and add a separate `gr.HTML` progress bar outside the chat: |
| |
| ```python |
| with gr.Blocks() as demo: |
| progress_html = gr.HTML("<div id='custom-progress'></div>", visible=False) |
| chat = gr.ChatInterface(...) |
| |
| # Update progress_html separately from chat |
| ``` |
| |
| **Pros**: |
| - Full control over positioning |
| - Can match exact design requirements |
| |
| **Cons**: |
| - Significant refactor required |
| - May break MCP server integration |
| - More moving parts = more bugs |
| |
| ### Option 4: Hybrid - Progress in `additional_inputs_accordion` |
| |
| Place a separate `gr.Progress` component in a fixed position (e.g., accordion header): |
| |
| ```python |
| with gr.Blocks() as demo: |
| with gr.Row(): |
| progress_bar = gr.Slider(0, 100, value=0, label="Progress", interactive=False) |
| chat = gr.ChatInterface(...) |
| ``` |
| |
| **Pros**: |
| - Fixed position, no overlap |
| |
| **Cons**: |
| - Requires `gr.Blocks` wrapper (breaks MCP?) |
| - Clunky UX |
| |
| ## Recommended Fix |
| |
| **Option 1: Remove `gr.Progress()`, keep emoji status text** |
| |
| Rationale: |
| 1. Our emoji status updates (`⏱️ **PROGRESS**: Round 2/5`) already provide the information |
| 2. `gr.Progress()` was never designed for ChatInterface |
| 3. Removing it eliminates the positioning conflict entirely |
| 4. ChatInterface's built-in `show_progress="minimal"` handles the spinner |
| |
| ## Implementation Plan |
| |
| 1. **Remove** `progress: gr.Progress = gr.Progress()` parameter from `research_agent()` |
| 2. **Remove** all `progress(...)` calls in the function |
| 3. **Keep** emoji status yields (`⏱️ **PROGRESS**: ...`) |
| 4. **Optionally** add `show_progress="minimal"` to ChatInterface (already default) |
| 5. **Test** on HuggingFace Spaces |
|
|
| ## Testing |
|
|
| ```bash |
| # Local test |
| uv run python -c "from src.app import create_demo; demo, _ = create_demo(); demo.launch()" |
| |
| # Verify: |
| # 1. No floating progress bar |
| # 2. Emoji status updates visible in chat |
| # 3. ChatInterface spinner works as expected |
| ``` |
|
|
| ## References |
|
|
| - [Gradio Progress Bars Guide](https://www.gradio.app/guides/progress-bars) |
| - [Gradio ChatInterface Docs](https://www.gradio.app/docs/gradio/chatinterface) |
| - [GitHub Issue #5967: Progress bar for ChatInterface](https://github.com/gradio-app/gradio/issues/5967) |
| - [GitHub Issue #5815: Customize the progress bar](https://github.com/gradio-app/gradio/issues/5815) |
|
|
| ## Version Info |
|
|
| - Gradio: `>=6.0.0` (pyproject.toml constraint) |
| - ChatInterface: Streaming async generator mode |
| - MCP Server: Enabled |
|
|