|
@@ -49,7 +49,11 @@ async function* parseSSEStream(reader: ReadableStreamDefaultReader<Uint8Array>):
|
|
|
try {
|
|
try {
|
|
|
const parsed = JSON.parse(data)
|
|
const parsed = JSON.parse(data)
|
|
|
if (eventType === 'transcript') {
|
|
if (eventType === 'transcript') {
|
|
|
- yield { type: 'transcript', text: parsed.text }
|
|
|
|
|
|
|
+ yield {
|
|
|
|
|
+ type: 'transcript',
|
|
|
|
|
+ text: parsed.text,
|
|
|
|
|
+ audioDuration: parsed.audioDuration ?? null,
|
|
|
|
|
+ }
|
|
|
} else if (eventType === 'token') {
|
|
} else if (eventType === 'token') {
|
|
|
yield { type: 'token', text: parsed.content ?? parsed.text }
|
|
yield { type: 'token', text: parsed.content ?? parsed.text }
|
|
|
} else if (eventType === 'done') {
|
|
} else if (eventType === 'done') {
|
|
@@ -90,6 +94,7 @@ interface BackendRound {
|
|
|
role: 'ai' | 'student'
|
|
role: 'ai' | 'student'
|
|
|
content: string
|
|
content: string
|
|
|
audioUrl: string | null
|
|
audioUrl: string | null
|
|
|
|
|
+ audioDuration: number | null // NEW: 秒,由后端 /report 透传
|
|
|
evaluation?: BackendEvaluation
|
|
evaluation?: BackendEvaluation
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -140,6 +145,7 @@ function adaptReport(raw: BackendReportResponse): DialogueReport {
|
|
|
role: r.role,
|
|
role: r.role,
|
|
|
content: r.content,
|
|
content: r.content,
|
|
|
audioUrl: r.audioUrl ?? undefined,
|
|
audioUrl: r.audioUrl ?? undefined,
|
|
|
|
|
+ audioDuration: r.audioDuration ?? undefined,
|
|
|
score: pronunciation
|
|
score: pronunciation
|
|
|
? Math.round((pronunciation.accuracy + pronunciation.fluency + pronunciation.intonation + pronunciation.stress) / 4)
|
|
? Math.round((pronunciation.accuracy + pronunciation.fluency + pronunciation.intonation + pronunciation.stress) / 4)
|
|
|
: undefined,
|
|
: undefined,
|