Skip to content

Commit 9097e8f

Browse files
committed
fix(classroom): 识别中 partial 按句读拆多行灰斜体
1 parent e2e4137 commit 9097e8f

1 file changed

Lines changed: 92 additions & 32 deletions

File tree

‎app/src/components/LiveActivityPanel.tsx‎

Lines changed: 92 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
* @ai-context: 用户要求"转写流要简要"——设计原则:单行紧凑卡片、色点区分来源
55
* (字幕=绿、语音=灰、画面=蓝)、无冗余装饰;列表超限截断(计数保留);
66
* 新内容自动跟随滚动。
7-
* @ai-context: 2026-08 用户需求:ASR 流式返回显示**所有未沉淀行**(识别中 partial +
8-
* 已定稿待沉淀 committed),不再折叠为单行——连续定稿(快速短句)
9-
* 时各行并存不被覆盖丢失;新句首个 partial 到达时统一沉淀。
7+
* @ai-context: 2026-08 用户需求:ASR 流式返回显示**所有未沉淀行**——识别中的
8+
* partial 按句读切分为多行灰斜体全部显示(不再一行越滚越长);
9+
* 已定稿待沉淀 committed 行黑色并存(连续定稿不互相覆盖丢失);
10+
* 新句首个 partial 到达时统一沉淀入列表。
1011
* @ai-context: 状态机:初始化(模型加载)→ 采集中 → 停止中 → 融合中 → 完成/失败,
1112
* 由 live:status / session:fusing/fused/failed 事件推导,父组件控制显隐。
1213
*/
@@ -64,6 +65,29 @@ function fmtTime(ms: number): string {
6465
return `${String(Math.floor(s / 60)).padStart(2, "0")}:${String(s % 60).padStart(2, "0")}`;
6566
}
6667

68+
/**
69+
* 中文句读切分(识别中行展示用,2026-08 用户需求:识别中的灰斜体内容全部显示)。
70+
*
71+
* @ai-context: 流式 partial 是整句候选且可能含多个句子(zipformer 中文模型输出
72+
* 带句读;asr_clean 的跨标点重复/纯标点幻觉处理即依赖此事实)——
73+
* 现状整句挤在一行灰斜里越滚越长;按句读切分后每句一行,全部可见。
74+
* 句读保留在句尾;无句读尾段为"残余"(调用方加 … 表示仍在识别)。
75+
* 不切英文句点(Mr./U.S. 缩写防误切)与逗号(句内成分不拆行)。
76+
*/
77+
function splitBySentence(text: string): string[] {
78+
const parts: string[] = [];
79+
let buf = "";
80+
for (const ch of text) {
81+
buf += ch;
82+
if ("。!?!?…".includes(ch)) {
83+
parts.push(buf);
84+
buf = "";
85+
}
86+
}
87+
if (buf.trim().length > 0) parts.push(buf);
88+
return parts;
89+
}
90+
6791
export default function LiveActivityPanel({ sessionId }: { sessionId?: number | null }) {
6892
const [tab, setTab] = useState<"transcript" | "ocr">("transcript");
6993
// 状态机(简要徽标文本)
@@ -287,37 +311,73 @@ export default function LiveActivityPanel({ sessionId }: { sessionId?: number |
287311
⋯ 共 {totalTranscript} 段,仅显示最近 {SHOW_TRANSCRIPT_LINES} 条(会话页可看全部)
288312
</p>
289313
)}
290-
{/* 2026-08 用户需求:ASR 未沉淀行全部展示(识别中灰斜 + 已定稿待沉淀黑),
291-
连续定稿各行并存;新句首个 partial 到达时统一沉淀入上方列表 */}
292-
{partials.map((p) => (
293-
<div
294-
key={p.id}
295-
style={{
296-
display: "flex",
297-
gap: 8,
298-
alignItems: "baseline",
299-
fontSize: 13,
300-
color: p.committed ? "#374151" : "#9ca3af",
301-
fontStyle: p.committed ? "normal" : "italic",
302-
}}
303-
>
304-
<span style={{ fontSize: 11, width: 44, flexShrink: 0, fontVariantNumeric: "tabular-nums" }}>
305-
{p.committed ? fmtTime(p.time) : fmtTime(elapsedMs)}
306-
</span>
307-
<span
308-
title={p.committed ? "已定稿待沉淀" : "识别中"}
314+
{/* 2026-08 用户需求:ASR 未沉淀行全部展示——识别中(灰斜)按句读拆多行
315+
全部显示;已定稿待沉淀(黑)一行;连续定稿各行并存;新句首个
316+
partial 到达时统一沉淀入上方列表 */}
317+
{partials.map((p) => {
318+
if (p.committed) {
319+
return (
320+
<div
321+
key={p.id}
322+
style={{
323+
display: "flex",
324+
gap: 8,
325+
alignItems: "baseline",
326+
fontSize: 13,
327+
color: "#374151",
328+
}}
329+
>
330+
<span style={{ fontSize: 11, width: 44, flexShrink: 0, fontVariantNumeric: "tabular-nums" }}>
331+
{fmtTime(p.time)}
332+
</span>
333+
<span
334+
title="已定稿待沉淀"
335+
style={{
336+
width: 8,
337+
height: 8,
338+
borderRadius: 4,
339+
flexShrink: 0,
340+
alignSelf: "center",
341+
background: "#9ca3af",
342+
}}
343+
/>
344+
<span>{p.text}</span>
345+
</div>
346+
);
347+
}
348+
// 识别中:整句候选按句读切分多行灰斜体——"识别中的内容全部显示";
349+
// 首行带时间,后续行对齐留空;残余段(无句读尾段)加 …
350+
const segs = splitBySentence(p.text);
351+
return segs.map((seg, i) => (
352+
<div
353+
key={`${p.id}-${i}`}
309354
style={{
310-
width: 8,
311-
height: 8,
312-
borderRadius: 4,
313-
flexShrink: 0,
314-
alignSelf: "center",
315-
background: p.committed ? "#9ca3af" : "#d1d5db",
355+
display: "flex",
356+
gap: 8,
357+
alignItems: "baseline",
358+
fontSize: 13,
359+
color: "#9ca3af",
360+
fontStyle: "italic",
316361
}}
317-
/>
318-
<span>{p.text}{p.committed ? "" : "…"}</span>
319-
</div>
320-
))}
362+
>
363+
<span style={{ fontSize: 11, width: 44, flexShrink: 0, fontVariantNumeric: "tabular-nums" }}>
364+
{i === 0 ? fmtTime(elapsedMs) : ""}
365+
</span>
366+
<span
367+
title="识别中"
368+
style={{
369+
width: 8,
370+
height: 8,
371+
borderRadius: 4,
372+
flexShrink: 0,
373+
alignSelf: "center",
374+
background: "#d1d5db",
375+
}}
376+
/>
377+
<span>{seg}{i === segs.length - 1 ? "…" : ""}</span>
378+
</div>
379+
));
380+
})}
321381
</div>
322382
) : (
323383
<div style={{ display: "flex", flexDirection: "column", gap: 3 }}>

0 commit comments

Comments
 (0)