feat(transcription): add shared voice input support (#4232)
* feat(webui): add voice transcription input * feat(webui): render ANSI output in code blocks * refactor(webui): isolate voice recorder logic * refactor(transcription): keep websocket ingress thin * refactor(transcription): resolve channel audio settings on demand * style(webui): neutralize voice waveform color * feat(webui): add voice input tooltip * feat(webui): add voice input keyboard shortcut * fix(webui): distinguish voice shortcut platforms * fix(webui): place voice button after model selector * refactor(webui): share voice hold recording helpers * fix(desktop): allow microphone voice input * fix(webui): stabilize token usage month labels * feat(webui): show voice input on settings overview * fix(webui): label voice capability as recognition * fix(webui): align capability overview status * refactor(webui): isolate transcription socket handling * fix(webui): soften silent voice waveform * refactor(audio): clarify transcription service location * docs(transcription): clarify audio and provider boundaries * fix(exec): reduce session output polling flake
This commit is contained in:
@@ -18,6 +18,7 @@ from nanobot.webui.settings_api import (
|
||||
update_agent_settings,
|
||||
update_model_configuration,
|
||||
update_network_safety_settings,
|
||||
update_transcription_settings,
|
||||
)
|
||||
|
||||
|
||||
@@ -243,6 +244,75 @@ def test_settings_payload_includes_network_safety_fields(
|
||||
assert payload["advanced"]["ssrf_whitelist_count"] == 1
|
||||
|
||||
|
||||
def test_settings_payload_includes_effective_transcription_config(
|
||||
tmp_path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
config_path = tmp_path / "config.json"
|
||||
config = Config()
|
||||
config.channels.transcription_provider = "openai"
|
||||
config.channels.transcription_language = "en"
|
||||
config.providers.openai.api_key = "sk-test"
|
||||
save_config(config, config_path)
|
||||
monkeypatch.setattr("nanobot.config.loader._current_config_path", config_path)
|
||||
|
||||
payload = settings_payload()
|
||||
|
||||
assert payload["transcription"]["enabled"] is True
|
||||
assert payload["transcription"]["provider"] == "openai"
|
||||
assert payload["transcription"]["provider_configured"] is True
|
||||
assert payload["transcription"]["model"] == "whisper-1"
|
||||
assert payload["transcription"]["language"] == "en"
|
||||
|
||||
|
||||
def test_update_transcription_settings_writes_top_level_only(
|
||||
tmp_path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
config_path = tmp_path / "config.json"
|
||||
config = Config()
|
||||
config.channels.transcription_provider = "openai"
|
||||
config.channels.transcription_language = "en"
|
||||
config.providers.groq.api_key = "gsk-test"
|
||||
save_config(config, config_path)
|
||||
monkeypatch.setattr("nanobot.config.loader._current_config_path", config_path)
|
||||
|
||||
payload = update_transcription_settings(
|
||||
{
|
||||
"enabled": ["true"],
|
||||
"provider": ["groq"],
|
||||
"model": ["whisper-large-v3-turbo"],
|
||||
"language": ["ko"],
|
||||
"maxDurationSec": ["90"],
|
||||
"maxUploadMb": ["20"],
|
||||
}
|
||||
)
|
||||
|
||||
saved = load_config(config_path)
|
||||
assert saved.channels.transcription_provider == "openai"
|
||||
assert saved.channels.transcription_language == "en"
|
||||
assert saved.transcription.enabled is True
|
||||
assert saved.transcription.provider == "groq"
|
||||
assert saved.transcription.model == "whisper-large-v3-turbo"
|
||||
assert saved.transcription.language == "ko"
|
||||
assert saved.transcription.max_duration_sec == 90
|
||||
assert saved.transcription.max_upload_mb == 20
|
||||
assert payload["transcription"]["provider"] == "groq"
|
||||
assert payload["transcription"]["provider_configured"] is True
|
||||
|
||||
|
||||
def test_update_transcription_settings_validates_language(
|
||||
tmp_path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
config_path = tmp_path / "config.json"
|
||||
save_config(Config(), config_path)
|
||||
monkeypatch.setattr("nanobot.config.loader._current_config_path", config_path)
|
||||
|
||||
with pytest.raises(WebUISettingsError, match="transcription language"):
|
||||
update_transcription_settings({"language": ["en-US"]})
|
||||
|
||||
|
||||
def test_settings_payload_includes_token_usage_summary(
|
||||
tmp_path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
|
||||
Reference in New Issue
Block a user