Render live STT without finalize
This commit is contained in:
@@ -58,20 +58,7 @@ function App() {
|
|||||||
return () => window.clearInterval(intervalId)
|
return () => window.clearInterval(intervalId)
|
||||||
}, [isRecording])
|
}, [isRecording])
|
||||||
|
|
||||||
const commitLiveIfAny = async () => {
|
const persistFinal = async (ts: string, text: string) => {
|
||||||
const text = liveTextRef.current.trim()
|
|
||||||
if (!text) return
|
|
||||||
const ts = new Date().toISOString()
|
|
||||||
setTranscriptLines((prev) => {
|
|
||||||
const last = prev[prev.length - 1]
|
|
||||||
if (last && !last.isFinal) {
|
|
||||||
return [
|
|
||||||
...prev.slice(0, -1),
|
|
||||||
{ ...last, text, ts, isFinal: true },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return [...prev, { id: lineIdRef.current++, ts, text, isFinal: true }]
|
|
||||||
})
|
|
||||||
if (!meetingIdRef.current) {
|
if (!meetingIdRef.current) {
|
||||||
pendingUtterancesRef.current.push({ ts, text })
|
pendingUtterancesRef.current.push({ ts, text })
|
||||||
return
|
return
|
||||||
@@ -83,6 +70,29 @@ function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateTranscript = (text: string, isFinal: boolean) => {
|
||||||
|
const trimmed = text.trim()
|
||||||
|
if (!trimmed) return
|
||||||
|
const ts = new Date().toISOString()
|
||||||
|
liveTextRef.current = isFinal ? '' : trimmed
|
||||||
|
setTranscriptLines((prev) => {
|
||||||
|
const last = prev[prev.length - 1]
|
||||||
|
if (last && !last.isFinal) {
|
||||||
|
return [
|
||||||
|
...prev.slice(0, -1),
|
||||||
|
{ ...last, text: trimmed, ts, isFinal },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
if (last && last.isFinal && isFinal && last.text.trim() === trimmed) {
|
||||||
|
return prev
|
||||||
|
}
|
||||||
|
return [...prev, { id: lineIdRef.current++, ts, text: trimmed, isFinal }]
|
||||||
|
})
|
||||||
|
if (isFinal) {
|
||||||
|
void persistFinal(ts, trimmed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const startRecognition = () => {
|
const startRecognition = () => {
|
||||||
const SpeechRecognitionConstructor =
|
const SpeechRecognitionConstructor =
|
||||||
window.SpeechRecognition || window.webkitSpeechRecognition
|
window.SpeechRecognition || window.webkitSpeechRecognition
|
||||||
@@ -100,34 +110,10 @@ function App() {
|
|||||||
|
|
||||||
recognition.onresult = (event) => {
|
recognition.onresult = (event) => {
|
||||||
lastResultAtRef.current = Date.now()
|
lastResultAtRef.current = Date.now()
|
||||||
let interim = ''
|
|
||||||
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
||||||
const result = event.results[i]
|
const result = event.results[i]
|
||||||
const text = result[0].transcript
|
const text = result[0].transcript
|
||||||
if (result.isFinal) {
|
updateTranscript(text, result.isFinal)
|
||||||
handleFinalTranscript(text)
|
|
||||||
} else {
|
|
||||||
interim += text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const interimText = interim.trim()
|
|
||||||
if (interimText) {
|
|
||||||
liveTextRef.current = interimText
|
|
||||||
setTranscriptLines((prev) => {
|
|
||||||
const last = prev[prev.length - 1]
|
|
||||||
if (last && !last.isFinal) {
|
|
||||||
return [...prev.slice(0, -1), { ...last, text: interimText }]
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
...prev,
|
|
||||||
{
|
|
||||||
id: lineIdRef.current++,
|
|
||||||
ts: new Date().toISOString(),
|
|
||||||
text: interimText,
|
|
||||||
isFinal: false,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,41 +147,6 @@ function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFinalTranscript = async (text: string) => {
|
|
||||||
const trimmed = text.trim()
|
|
||||||
if (!trimmed) return
|
|
||||||
lastResultAtRef.current = Date.now()
|
|
||||||
const ts = new Date().toISOString()
|
|
||||||
liveTextRef.current = ''
|
|
||||||
let nextLines: { id: number; ts: string; text: string; isFinal: boolean }[] = []
|
|
||||||
setTranscriptLines((prev) => {
|
|
||||||
const last = prev[prev.length - 1]
|
|
||||||
if (last && !last.isFinal) {
|
|
||||||
nextLines = [
|
|
||||||
...prev.slice(0, -1),
|
|
||||||
{ ...last, text: trimmed, ts, isFinal: true },
|
|
||||||
]
|
|
||||||
return nextLines
|
|
||||||
}
|
|
||||||
nextLines = [
|
|
||||||
...prev,
|
|
||||||
{ id: lineIdRef.current++, ts, text: trimmed, isFinal: true },
|
|
||||||
]
|
|
||||||
return nextLines
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!meetingIdRef.current) {
|
|
||||||
pendingUtterancesRef.current.push({ ts, text: trimmed })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await saveUtterance(meetingIdRef.current, trimmed, ts)
|
|
||||||
} catch (err) {
|
|
||||||
setErrorMessage((err as Error).message)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleStart = async () => {
|
const handleStart = async () => {
|
||||||
setErrorMessage(null)
|
setErrorMessage(null)
|
||||||
lineIdRef.current = 1
|
lineIdRef.current = 1
|
||||||
@@ -225,7 +176,6 @@ function App() {
|
|||||||
if (!meetingIdRef.current) return
|
if (!meetingIdRef.current) return
|
||||||
setErrorMessage(null)
|
setErrorMessage(null)
|
||||||
recognitionRef.current?.stop()
|
recognitionRef.current?.stop()
|
||||||
await commitLiveIfAny()
|
|
||||||
liveTextRef.current = ''
|
liveTextRef.current = ''
|
||||||
setIsRecording(false)
|
setIsRecording(false)
|
||||||
isRecordingRef.current = false
|
isRecordingRef.current = false
|
||||||
|
|||||||
Reference in New Issue
Block a user