diff --git a/static/js/settings.js b/static/js/settings.js index ea05c04..aa221ca 100644 --- a/static/js/settings.js +++ b/static/js/settings.js @@ -33,9 +33,9 @@ function backendComputeDevice(id) { const b = backendById(id); const text = [id, b?.label, b?.speed, b?.latency, b?.quality, b?.ram, b?.purpose, b?.best_for] .filter(Boolean).join(' ').toLowerCase(); - if (/(cloud|api|elevenlabs|groq)/.test(text)) return 'Cloud'; - if (/(cpu|metal)/.test(text) && !/(cuda|gpu|vram|rtx|dgx)/.test(text)) return 'CPU'; - if (/(cuda|gpu|vram|rtx|dgx)/.test(text)) return 'CUDA/GPU'; + if (/\b(cloud|api|elevenlabs|groq)\b/.test(text)) return 'Cloud'; + if (/\b(cpu|metal)\b/.test(text) && !/\b(cuda|gpu|vram|rtx|dgx)\b/.test(text)) return 'CPU'; + if (/\b(cuda|gpu|vram|rtx|dgx)\b/.test(text)) return 'CUDA/GPU'; return 'Unknown'; } @@ -240,6 +240,152 @@ function _saveEngineContainerNames() { window._saveEngineLocalUrls = _saveEngineLocalUrls; window._saveEngineContainerNames = _saveEngineContainerNames; + +// ── Settings guidance / tooltips ───────────────────────────────────────── +const SETTINGS_PAGE_GUIDES = { + general: { + icon: 'mdi-palette-outline', + title: 'Start here', + text: 'Choose the theme you prefer. Everything else can stay as-is until you connect or change an engine.' + }, + connections: { + icon: 'mdi-lan-connect', + title: 'Connect engines first', + text: 'Most users only need the Docker Engines page: click Connect, then Use as TTS or Use as STT. Edit URLs here only when a service moved or runs on another host.', + steps: ['Use host.docker.internal for containers on the same Docker host.', 'Use 192.168.x.x when calling another machine on your LAN.', 'After changing URLs, Save settings, then refresh the target page.'] + }, + playback: { + icon: 'mdi-play-circle-outline', + title: 'Recommended playback', + text: 'Auto is the safest default: it streams when the backend supports it and falls back to normal WAV playback when saving or compatibility matters.' + }, + captures: { + icon: 'mdi-record-circle-outline', + title: 'Voice capture defaults', + text: 'These choices affect microphone transcription and STT-to-TTS workflows. Pick a language only if auto-detect makes mistakes often.' + }, + payloads: { + icon: 'mdi-code-json', + title: 'Advanced tuning', + text: 'Leave these as defaults unless a backend needs special parameters. Invalid JSON prevents settings from saving, so change one box at a time.' + }, + storage: { + icon: 'mdi-folder-outline', + title: 'Match your volume mounts', + text: 'These are container paths, not host paths. In your Portainer stack, /voices should point to your real voice folder.' + }, + apikeys: { + icon: 'mdi-key-outline', + title: 'Local-first defaults', + text: 'Local containers usually do not need real keys. Use sk-local only when a compatible server insists on an Authorization header.' + }, + backup: { + icon: 'mdi-backup-restore', + title: 'Back up before big changes', + text: 'Export voices before moving folders, changing stacks, or testing new voice libraries. Keys are intentionally left out.' + }, + logs: { + icon: 'mdi-text-box-outline', + title: 'Use logs when something feels stuck', + text: 'Refresh after a failed request. Error rows usually say which URL, model, or payload needs attention.' + }, + about: { + icon: 'mdi-information-outline', + title: 'Version and support info', + text: 'Use this page to confirm the running app version and open release notes when behavior changed after an update.' + } +}; + +const SETTINGS_FIELD_HELP = { + 's-theme-select': ['Theme', 'Changes only your browser UI. It is saved immediately and does not affect generated audio.'], + 's-tts-url': ['Voice Clone / Base URL', 'Use this for normal cloned WAV voices. Your 8020 Qwen3 voice clone container usually belongs here.'], + 's-voice-design-url': ['Voice Design URL', 'Use this for creating prompt-designed voices. Your 8021 Qwen3 Voice Design container usually belongs here.'], + 's-customvoice-url': ['CustomVoice URL', 'Use this for Qwen3 CustomVoice speaker/style presets. Your 8022 container usually belongs here.'], + 's-tts-stream-url': ['Streaming URL', 'Use this for lower-latency playback. Your 8023 streaming container usually belongs here.'], + 's-kokoro-url': ['Kokoro URL', 'Small, fast OpenAI-compatible TTS. Good as a lightweight fallback, but it does not clone your WAV identities.'], + 's-vibevoice-url': ['VibeVoice URL', 'Simple local TTS service. Good for experiments; not every Voice Creator feature maps to it.'], + 's-xtts-url': ['XTTS v2 URL', 'Use only if an XTTS API server is running. It can clone from short references but has a different voice model than Qwen3.'], + 's-nvidia-router-url': ['NVIDIA router URL', 'Router endpoint that can expose NVIDIA speech services through one URL. Handy when Parakeet and Magpie share a gateway.'], + 's-nvidia-tts-url': ['NVIDIA Magpie TTS URL', 'Direct Magpie TTS endpoint with fixed speakers. Good quality, but not your cloned WAV voice library.'], + 's-nvidia-asr-url': ['NVIDIA Parakeet ASR URL', 'Direct speech-to-text endpoint. Use this for fast local transcription when Parakeet is running.'], + 's-nvidia-zeroshot-url': ['NVIDIA Zeroshot NIM URL', 'Experimental clone endpoint that uses an audio prompt. Leave empty unless that NIM is running.'], + 's-nvidia-flow-url': ['NVIDIA Flow NIM URL', 'Experimental clone endpoint that uses an audio prompt plus transcript. Leave empty unless that NIM is running.'], + 's-whisper-url': ['Active STT URL', 'Main transcription URL used by the app. The quick buttons below copy known engine URLs into this field.'], + 's-faster-whisper-url': ['faster-whisper URL', 'Fast local Whisper endpoint, often the best general-purpose STT choice when GPU acceleration is available.'], + 's-whisper-cpp-url': ['whisper.cpp URL', 'Lightweight Whisper server for CPU or small CUDA setups. Useful fallback when heavier STT is offline.'], + 's-groq-api-key': ['Groq API key', 'Only needed for Groq cloud STT or LLM. Keep empty if you use only local services.'], + 's-tts-stream-mode': ['Playback mode', 'Auto is recommended. Streaming feels faster; buffered is more compatible and better for saving files.'], + 's-tts-backend': ['Request style', 'Choose the payload format expected by the backend connected to the normal TTS URL. Qwen3/OpenAI is the usual local stack default.'], + 's-stt-language': ['Default language', 'Auto-detect is usually fine. Set this when transcription keeps choosing the wrong language.'], + 's-stt-preferred-backend': ['Preferred STT backend', 'Overrides the active STT URL only for capture workflows. Leave default if you want one global STT setting.'], + 's-llm-url': ['LLM base URL', 'OpenAI-compatible chat endpoint used for rewrites, casting, refinement, and voice-design assistance.'], + 's-auto-refine': ['Auto-refine', 'When enabled, the app sends transcripts to the LLM for cleanup automatically. Leave off if you want raw transcripts.'], + 's-refine-model': ['Refinement model', 'Optional model override for transcript cleanup. Leave empty to use the current LLM default.'], + 's-captures-default-voice': ['Default playback voice', 'Preselects a TTS voice in capture workflows so you do not have to choose it every time.'], + 's-tts-extra-voice-clone': ['Voice Clone params', 'Advanced JSON sent to the 8020 backend. Temperature/top_p/seed are common controls.'], + 's-tts-extra-streaming': ['Streaming params', 'Advanced JSON sent to the streaming backend. Keep close to Voice Clone params for comparable sound.'], + 's-tts-extra-customvoice': ['CustomVoice params', 'Advanced JSON sent to CustomVoice. Use only backend-supported fields.'], + 's-tts-extra-voice-design': ['Voice Design params', 'Advanced JSON sent when generating prompt-designed voices.'], + 's-tts-extra-nvidia-magpie': ['Magpie params', 'Usually empty. Magpie uses fixed speakers and may reject unknown fields.'], + 's-tts-extra-nvidia-zeroshot': ['Zeroshot params', 'Optional multipart fields for the clone NIM. The app already sends text, language, and audio prompt.'], + 's-tts-extra-nvidia-flow': ['Flow params', 'Optional multipart fields for Flow. The app also sends reference transcript when available.'], + 's-tts-extra-kokoro': ['Kokoro params', 'Usually empty. The selected Kokoro voice carries most of the useful information.'], + 's-tts-extra-vibevoice': ['VibeVoice params', 'Usually empty. VibeVoice commonly only needs text.'], + 's-voices-scan-dir': ['Voice scan directory', 'Container path that contains active_voices and hidden_voices. Usually /voices.'], + 's-output-dir': ['Active voices directory', 'Container path where new cloned or exported voices are saved. Usually /voices/active_voices.'], + 's-tts-key': ['TTS API key', 'Optional. For local OpenAI-compatible servers, sk-local or empty usually works.'], + 's-vd-key': ['Voice Design API key', 'Optional. Use only if your Voice Design backend requires Authorization.'], + 's-whisper-key': ['Whisper API key', 'Optional. Needed for cloud STT, usually empty for local Whisper-compatible containers.'] +}; + + +function enhanceSettingsHelp(root = document) { + const scope = root && root.querySelectorAll ? root : document; + scope.querySelectorAll('.s-settings-page').forEach(page => { + const key = page.dataset.page; + const guide = SETTINGS_PAGE_GUIDES[key]; + const card = page.querySelector('.card'); + const head = card?.querySelector('.s-page-head'); + if (!guide || !card || !head || card.querySelector('.settings-guide')) return; + const box = document.createElement('div'); + box.className = 'settings-guide'; + box.innerHTML = ` +
+${escHtml(guide.text)}
+ ${guide.steps ? `