| # 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 | |