diff --git a/voice-to-mermaid/README.md b/voice-to-mermaid/README.md index e693236..8203703 100644 --- a/voice-to-mermaid/README.md +++ b/voice-to-mermaid/README.md @@ -78,7 +78,7 @@ It is volume-mounted in Docker, so changes take effect on restart without rebuil | `ollama.default_model` | `qwen3:8b` | Ollama model for diagram generation | | `ollama.model_filter` | _(list)_ | Model name prefixes shown in the UI picker | | `openai.model` | `gpt-4o-mini` | OpenAI-compatible model name | -| `whisper.enabled` | `false` | Set `true` after installing `requirements.stt.txt` | +| `whisper.enabled` | `false` | Set `true` after installing `requirements.stt.txt`; graceful no-op if import fails | | `whisper.model` | `medium.en` | Whisper model size | | `whisper.device` | `auto` | `auto` / `cpu` / `cuda` | | `paths.prompt` | `prompts/mermaid.txt` | Path to LLM prompt template | @@ -88,7 +88,7 @@ It is volume-mounted in Docker, so changes take effect on restart without rebuil | Variable | Default | Description | |---|---|---| -| `OLLAMA_URL` | `http://localhost:11434` | Ollama server URL | +| `OLLAMA_URL` | `http://ollama:11434` (Docker Compose) | Ollama server URL; use `http://host.docker.internal:11434` for a host-resident Ollama | | `OPENAI_BASE_URL` | _(empty)_ | OpenAI-compatible API base (optional) | | `OPENAI_API_KEY` | _(empty)_ | API key for OpenAI-compatible API | | `API_KEY` | _(empty)_ | If set, require `X-Api-Key` header on all requests | diff --git a/voice-to-mermaid/backend/.env.example b/voice-to-mermaid/backend/.env.example index 1ac6706..9fcab6a 100644 --- a/voice-to-mermaid/backend/.env.example +++ b/voice-to-mermaid/backend/.env.example @@ -5,8 +5,10 @@ # ── LLM backend URLs (secrets — keep out of config.yaml) ───────────────── -# Option A: Ollama (local, recommended for self-hosting) -OLLAMA_URL=http://localhost:11434 +# Option A: Ollama (bundled Docker Compose service — default for docker-compose up) +OLLAMA_URL=http://ollama:11434 +# To use a host-resident Ollama instead: +# OLLAMA_URL=http://host.docker.internal:11434 # Option B: OpenAI-compatible API (vLLM, OpenAI, Together, etc.) # OPENAI_BASE_URL=https://api.openai.com/v1 diff --git a/voice-to-mermaid/backend/config.yaml b/voice-to-mermaid/backend/config.yaml index 9acf4ae..8a85a24 100644 --- a/voice-to-mermaid/backend/config.yaml +++ b/voice-to-mermaid/backend/config.yaml @@ -18,11 +18,9 @@ openai: model: "gpt-4o-mini" whisper: - # true = attempt to load WhisperLiveKit at startup. - # If import fails (deps not installed), _stt_available stays False and - # /v1/config returns stt_enabled: false — no crash. - # Install requirements.stt.txt (or add it to Dockerfile) before setting true. - enabled: true + # Set true only after installing requirements.stt.txt (or adding it to Dockerfile). + # If import fails, _stt_available stays False and /v1/config returns stt_enabled: false — no crash. + enabled: false model: "medium.en" language: "en" device: "auto" # "auto", "cuda", "cpu" — maps to WhisperLiveKitConfig backend diff --git a/voice-to-mermaid/backend/docker-compose.yml b/voice-to-mermaid/backend/docker-compose.yml index 1d5ee68..d1601d7 100644 --- a/voice-to-mermaid/backend/docker-compose.yml +++ b/voice-to-mermaid/backend/docker-compose.yml @@ -24,9 +24,11 @@ services: - "${PORT:-7625}:7625" env_file: .env environment: - - OLLAMA_URL=http://ollama:11434 - depends_on: - - ollama + # Default to the bundled ollama service; override in .env to use a + # host-resident Ollama (http://host.docker.internal:11434) instead. + OLLAMA_URL: ${OLLAMA_URL:-http://ollama:11434} + extra_hosts: + - "host.docker.internal:host-gateway" volumes: - ./prompts:/app/prompts # mount prompts so edits don't need rebuild - ./config.yaml:/app/config.yaml # mount config so edits don't need rebuild diff --git a/voice-to-mermaid/backend/main.py b/voice-to-mermaid/backend/main.py index dedfa34..8e11236 100644 --- a/voice-to-mermaid/backend/main.py +++ b/voice-to-mermaid/backend/main.py @@ -357,7 +357,7 @@ async def refresh_models(): @app.websocket("/ws/mermaid") async def ws_mermaid(websocket: WebSocket): - if WHISPER_ENABLED: + if _stt_available: from whisperlivekit import AudioProcessor await websocket.accept() @@ -447,7 +447,7 @@ async def _consume_results(results_generator, line_count_ref: list[int]) -> None # Handshake await websocket.send_json({"type": "config", "useAudioWorklet": False}) - ready_msg = "Ready — speak now…" if WHISPER_ENABLED else "Ready — type or paste text to generate a diagram" + ready_msg = "Ready — speak now…" if _stt_available else "Ready — type or paste text to generate a diagram" await websocket.send_json({"type": "processing", "message": ready_msg}) transcript_lines: list[str] = [] @@ -455,7 +455,7 @@ async def _consume_results(results_generator, line_count_ref: list[int]) -> None results_task = None line_count_ref = [0] - if WHISPER_ENABLED: + if _stt_available: audio_processor = AudioProcessor(transcription_engine=_transcription_engine) results_generator = await audio_processor.create_tasks() results_task = asyncio.create_task(_consume_results(results_generator, line_count_ref)) @@ -518,7 +518,7 @@ async def _consume_results(results_generator, line_count_ref: list[int]) -> None pass continue - if WHISPER_ENABLED and audio_processor: + if _stt_available and audio_processor: audio_bytes = msg.get("bytes") if audio_bytes: await audio_processor.process_audio(audio_bytes)