feat(web): voice input — record, check the recognised text, send
CI / ruff · pytest (pull_request) Successful in 2m24s
CI / ruff · pytest (pull_request) Successful in 2m24s
Microphone button in the chat composer and in free-text steps. The browser
records 16 kHz mono WAV (no server-side ffmpeg), /me/{token}/stt transcribes,
the text lands in the field for the patient to check and edit — never sent
automatically, so safety and scrub() apply on send. Hidden when the server has
voice input off or the browser lacks a microphone API. nginx: 4 MB body limit.
Refs #117
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { AppShell, TopBar } from "../components/AppShell";
|
||||
import { Icon } from "../components/Icon";
|
||||
import { VoiceInput } from "../components/VoiceInput";
|
||||
import { ru } from "../content/ru";
|
||||
import { useDialog } from "../dialog/DialogContext";
|
||||
|
||||
@@ -112,6 +113,11 @@ export function Messages() {
|
||||
onKeyDown={onKeyDown}
|
||||
maxLength={2000}
|
||||
/>
|
||||
<VoiceInput
|
||||
compact
|
||||
disabled={dialog.busy}
|
||||
onText={(text) => setDraft((prev) => (prev.trim() ? `${prev.trim()} ${text}` : text).slice(0, 2000))}
|
||||
/>
|
||||
<button type="submit" className="send" disabled={dialog.busy || !draft.trim()} aria-label={ru.common.send}>
|
||||
<Icon name="send" size={20} />
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user