Commit Graph

29 Commits

Author SHA1 Message Date
shinalok fb438864b1 UI/UX D2: branded header, custom theme, bubble styles, streaming animation, responsive
- app.py: styled HTML header with robot icon + subtitle (D2-11)
- app.py: gr.themes.Soft(blue/indigo/slate) applied to gr.Blocks (D2-12)
- app.py: user_selector moved to header Row, right-aligned scale=0 (D2-13)
- app.py: .message-wrap .user/.bot custom background + border-radius CSS (D2-14)
- app.py: streaming-indicator blink animation on _live_html (D2-15)
- app.py: @media max-width:768px responsive CSS (D2-16)
- ROADMAP.md: mark all D2 items complete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 14:41:51 +09:00
shinalok c1a28bfdcc UI/UX D1: examples, image accordion, layout improvements, table select, button size
- app.py: add gr.Examples with 3 sample questions (D1-5)
- app.py: wrap image input in gr.Accordion(open=False) (D1-6)
- app.py: checkboxes left Column(scale=3), reset btn right Column(scale=1) (D1-7)
- app.py: msg_box lines=2, send_btn .send-btn CSS min-height 80px (D1-8)
- app.py: doc_table.select -> select_doc_row auto-fills delete_source (D1-9)
- app.py: ingest_btn scale=0 min_width=200 to avoid full-width stretch (D1-10)
- ROADMAP.md: mark all D1 items complete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 14:28:21 +09:00
shinalok e08b43c785 UI/UX D0: fix Textbox label, hide audio accordion, hide footer, hide ingest result box
- app.py: show_label=False on msg_box to remove "Textbox" label
- app.py: wrap audio input in gr.Accordion(open=False) to hide microphone error on load
- app.py: add CSS to hide Gradio footer branding
- app.py: ingest_status starts visible=False; ingest_files returns gr.update(visible=True)
- ROADMAP.md: add UI/UX design improvement section (D0–D3) and mark D0 complete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 14:25:54 +09:00
shinalok 20f385e2a0 Merge remote-tracking branch 'origin/main' 2026-06-02 14:12:45 +09:00
shinalok 4565980915 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	.env.example
2026-06-02 14:09:54 +09:00
shinalok b13e3dfdd7 Add .env.example file with API and voice configuration templates 2026-06-02 14:09:40 +09:00
shinalok 0803479438 Fix: move image_input to separate row for cleaner layout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 14:04:01 +09:00
shinalok 7f50333bdb Phase 17: Add image upload to chat UI
- app.py: image_input gr.Image component, respond() accepts image_path,
  all yields updated to 7 outputs
- api_client.py: chat(image_path=None), base64-encodes image for API
- services/chat.py: chat(image_path=None) passes through to api_client

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 13:52:21 +09:00
shinalok 974bab7cd8 Phase 28: P3 — Pydantic Settings, dependency-injector IoC, tenacity retry
- config.py: dataclasses → pydantic-settings BaseSettings (flat AppConfig,
  env vars auto-loaded from .env, type-safe validation)
- api_client.py: HTTPAPIClient takes AppConfig directly (APIConfig removed);
  tenacity retry on 5 methods (reset/ingest/list/delete/feedback) —
  retries on 5xx + TransportError, 3 attempts, exponential backoff 1-8s
- container.py: manual DI → dependency_injector DeclarativeContainer with
  providers.Singleton; Container() needs no args
- app.py: container.X → container.X() calls, remove AppConfig import
- requirements.txt: add pydantic-settings, tenacity, dependency-injector

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 05:59:23 +09:00
shinalok 148211e236 Phase 27: P2 quality improvements — logging, httpx pooling, validation, tests
- app.py: replace print() with logging, basicConfig with LOG_LEVEL env var
- api_client.py: shared AsyncClient instance (connection pooling), URL-encode
  delete_document path parameter, aclose() for cleanup
- services/document.py: validate file exists and extension before ingest
- tests/: ChatService (4) + DocumentService (6) unit tests via pytest-asyncio
- pyproject.toml: asyncio_mode = auto
- requirements-dev.txt: pytest, pytest-asyncio

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 17:52:43 +09:00
shinalok 511c87b290 docs: update ROADMAP to reflect P0/P1 completion and services/ package structure
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 17:46:53 +09:00
shinalok 79f2abe7cf chore: exclude .claude/ from git tracking
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 17:41:17 +09:00
shinalok 7eed70d7f7 chore: add .gitignore rules for IDE and cache files, remove tracked artifacts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 17:40:08 +09:00
shinalok 1e93def909 Refactor: split services.py into services/ package
ChatService → services/chat.py
DocumentService → services/document.py
TTSService → services/tts.py
services/__init__.py re-exports all three for backward-compatible imports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 17:39:52 +09:00
shinalok d81a2f5888 Phase 26: P1 architecture refactor — DI container, service layer, async callbacks
- config.py: APIConfig + AppConfig dataclasses, env vars centralized
- api_client.py: APIClientProtocol (Protocol) + HTTPAPIClient class, remove module-level globals
- services.py: ChatService, DocumentService, TTSService (TTS moved from app.py)
- container.py: manual DI container with lazy singleton properties
- app.py: all callbacks converted to async, asyncio.run() fully removed, container wired in
- .env.example: add TTS_EDGE_VOICE entry
- ROADMAP.md: P0/P1 checklist updated to reflect completed work

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 17:36:35 +09:00
shinalok be4b7c40cb Merge remote-tracking branch 'origin/main' 2026-06-01 16:42:58 +09:00
shinalok 5ea7948ed3 Add project roadmap outlining improvements and priorities 2026-06-01 16:42:37 +09:00
shinalok 38d2edeeec Phase 25: Separate RAG sources into collapsible box below chatbot
- Add source_box gr.HTML component below chatbot
- Add _sources_html() helper rendering <details> expand/collapse
- Handle __sources token in respond(): update source_box independently of thinking_box
- Reset both thinking_box and source_box on each new message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 16:15:06 +09:00
shinalok 55ea69d902 Fix details close-on-update: use div during streaming, details on complete
During streaming: _live_html (plain div) shows only the current line —
no DOM reset, no closing issue. __thinking shows last non-empty line,
__meta shows the full trimmed message.
On completion: _thinking_html (<details>) shows all accumulated content
collapsed, expands on click.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 13:50:21 +09:00
shinalok 18609a4f7d Collapsible thinking box with details/summary, thinking on by default
- Thinking box uses <details>/<summary> — collapsed by default, expands on click
- Simple __status header shown before content arrives (no expand needed)
- show_thinking checkbox default changed to True

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 13:34:47 +09:00
shinalok 5cf8bdabfd Handle __status tokens for instant thinking box feedback
__status tokens show immediately in the thinking box but do not
accumulate in thinking_acc. When real content (__meta/__thinking)
arrives it overwrites the status message naturally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 13:08:30 +09:00
shinalok 4956ab7085 Replace gr.Markdown thinking box with gr.HTML for reliable streaming
gr.Markdown visible toggling is unreliable in Gradio streaming generators.
Switched to gr.HTML with inline styles — empty string hides the element,
HTML string shows the styled box. No visibility state needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 11:30:57 +09:00
shinalok 2348f17791 Move progress logs into thinking box alongside LLM reasoning
Both __meta (LangGraph/search progress) and __thinking (LLM reasoning)
tokens now stream into the thinking box instead of the chatbot.
Chatbot shows only the final answer. Thinking box shows the full
analysis pipeline: [LangGraph → ...], 문서 검색 중, thinking content.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 10:56:01 +09:00
shinalok 8c859971d1 Add thinking box UI and fix async event loop errors
- 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 <noreply@anthropic.com>
2026-06-01 10:33:15 +09:00
shinalok 0424cf4b31 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.
2026-06-01 10:26:29 +09:00
shinalok 6435af5837 Separate TTS text from metadata tokens in respond()
Filter __meta dict tokens from TTS accumulator so progress messages
([LangGraph], thinking blocks, source references) are displayed in chat
but not read aloud. Answer tokens continue to accumulate in tts_text.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:08:22 +09:00
shinalok 7fa45afc7f Fix TTS to use pure response content without meta tokens 2026-05-31 23:05:28 +09:00
shinalok cf68e19f38 Add cross-platform TTS support and update dependencies 2026-05-30 23:54:41 +09:00
shinalok 9455b591de Add initial implementation of Youlbot WebUI with Gradio frontend 2026-05-30 22:09:53 +09:00