Start STT immediately and drop answers

This commit is contained in:
dsyoon
2026-01-28 22:50:10 +09:00
parent 7ce9a73793
commit 19cc1c1360

View File

@@ -1,7 +1,6 @@
import { useEffect, useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
import './App.css' import './App.css'
import TranscriptPanel from './components/TranscriptPanel' import TranscriptPanel from './components/TranscriptPanel'
import AnswerPanel from './components/AnswerPanel'
import MeetingList from './components/MeetingList' import MeetingList from './components/MeetingList'
import { import {
createMeeting, createMeeting,
@@ -19,7 +18,6 @@ function App() {
const [transcriptLines, setTranscriptLines] = useState< const [transcriptLines, setTranscriptLines] = useState<
{ id: number; ts: string; text: string; isFinal: boolean }[] { id: number; ts: string; text: string; isFinal: boolean }[]
>([]) >([])
const [answerSuggestions, setAnswerSuggestions] = useState<string[]>([])
const [meetingsList, setMeetingsList] = useState< const [meetingsList, setMeetingsList] = useState<
{ id: number; started_at: string; ended_at: string | null; title: string | null }[] { id: number; started_at: string; ended_at: string | null; title: string | null }[]
>([]) >([])
@@ -32,6 +30,7 @@ function App() {
const liveTextRef = useRef('') const liveTextRef = useRef('')
const lineIdRef = useRef(1) const lineIdRef = useRef(1)
const meetingIdRef = useRef<number | null>(null) const meetingIdRef = useRef<number | null>(null)
const pendingUtterancesRef = useRef<{ ts: string; text: string }[]>([])
const isRecordingRef = useRef(false) const isRecordingRef = useRef(false)
const lastResultAtRef = useRef<number>(Date.now()) const lastResultAtRef = useRef<number>(Date.now())
const restartLockRef = useRef(false) const restartLockRef = useRef(false)
@@ -61,7 +60,6 @@ function App() {
}, [isRecording]) }, [isRecording])
const commitLiveIfAny = async () => { const commitLiveIfAny = async () => {
if (!meetingIdRef.current) return
const text = liveTextRef.current.trim() const text = liveTextRef.current.trim()
if (!text) return if (!text) return
const ts = new Date().toISOString() const ts = new Date().toISOString()
@@ -75,6 +73,10 @@ function App() {
} }
return [...prev, { id: lineIdRef.current++, ts, text, isFinal: true }] return [...prev, { id: lineIdRef.current++, ts, text, isFinal: true }]
}) })
if (!meetingIdRef.current) {
pendingUtterancesRef.current.push({ ts, text })
return
}
try { try {
await saveUtterance(meetingIdRef.current, text, ts) await saveUtterance(meetingIdRef.current, text, ts)
} catch (err) { } catch (err) {
@@ -173,7 +175,6 @@ function App() {
} }
const handleFinalTranscript = async (text: string) => { const handleFinalTranscript = async (text: string) => {
if (!meetingIdRef.current) return
const trimmed = text.trim() const trimmed = text.trim()
if (!trimmed) return if (!trimmed) return
if (finalizeTimerRef.current) { if (finalizeTimerRef.current) {
@@ -200,6 +201,10 @@ function App() {
return nextLines return nextLines
}) })
if (!meetingIdRef.current) {
pendingUtterancesRef.current.push({ ts, text: trimmed })
return
}
try { try {
await saveUtterance(meetingIdRef.current, trimmed, ts) await saveUtterance(meetingIdRef.current, trimmed, ts)
} catch (err) { } catch (err) {
@@ -210,17 +215,24 @@ function App() {
const handleStart = async () => { const handleStart = async () => {
setErrorMessage(null) setErrorMessage(null)
lineIdRef.current = 1
pendingUtterancesRef.current = []
setTranscriptLines([])
meetingIdRef.current = null
setCurrentMeetingId(null)
setIsRecording(true)
isRecordingRef.current = true
lastResultAtRef.current = Date.now()
startRecognition()
try { try {
const result = await createMeeting(new Date().toISOString()) const result = await createMeeting(new Date().toISOString())
meetingIdRef.current = result.id meetingIdRef.current = result.id
setCurrentMeetingId(result.id) setCurrentMeetingId(result.id)
lineIdRef.current = 1 const pending = [...pendingUtterancesRef.current]
setTranscriptLines([]) pendingUtterancesRef.current = []
setAnswerSuggestions([]) await Promise.all(
setIsRecording(true) pending.map((item) => saveUtterance(result.id, item.text, item.ts))
isRecordingRef.current = true )
lastResultAtRef.current = Date.now()
startRecognition()
} catch (err) { } catch (err) {
setErrorMessage((err as Error).message) setErrorMessage((err as Error).message)
} }
@@ -284,8 +296,6 @@ function App() {
isFinal: true, isFinal: true,
})) }))
) )
const lastAnswer = data.answers[data.answers.length - 1]
setAnswerSuggestions(lastAnswer?.suggestions || [])
} catch (err) { } catch (err) {
setErrorMessage((err as Error).message) setErrorMessage((err as Error).message)
} }
@@ -324,7 +334,6 @@ function App() {
setCurrentMeetingId(null) setCurrentMeetingId(null)
meetingIdRef.current = null meetingIdRef.current = null
setTranscriptLines([]) setTranscriptLines([])
setAnswerSuggestions([])
} }
} catch (err) { } catch (err) {
setErrorMessage((err as Error).message) setErrorMessage((err as Error).message)
@@ -336,7 +345,6 @@ function App() {
<div className="left-panel"> <div className="left-panel">
{errorMessage && <div className="error-banner">{errorMessage}</div>} {errorMessage && <div className="error-banner">{errorMessage}</div>}
<TranscriptPanel transcriptLines={transcriptLines} /> <TranscriptPanel transcriptLines={transcriptLines} />
<AnswerPanel suggestions={answerSuggestions} />
<div className="controls"> <div className="controls">
<button <button
type="button" type="button"