Commit d7c3c3e2 by luoqi

feat(web): 深度档 AI 生成把自检问题明细展示出来(section/problem/fix)

deep 策略 verify 阶段把 issues[] 透传到 stream 事件;前端会话过程区展开每条问题的 段落/问题/修法。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
parent e75f756d
...@@ -29,6 +29,8 @@ export interface DeepStepDetail { ...@@ -29,6 +29,8 @@ export interface DeepStepDetail {
pass?: boolean; // verify done pass?: boolean; // verify done
quality?: DeepVerify['quality'] | null; // verify done:质量分 quality?: DeepVerify['quality'] | null; // verify done:质量分
issuesCount?: number; // verify done:发现问题数 / repair running:待修问题数 issuesCount?: number; // verify done:发现问题数 / repair running:待修问题数
// verify done / repair running:逐条问题明细(section=出问题的段 · problem=哪里不对 · fix=改法)
issues?: { section: string; problem: string; fix: string }[];
} }
/** runStream 逐步 yield 的事件(step 状态切换 + write 逐字 partial)*/ /** runStream 逐步 yield 的事件(step 状态切换 + write 逐字 partial)*/
...@@ -220,13 +222,26 @@ export class DeepScriptStrategy { ...@@ -220,13 +222,26 @@ export class DeepScriptStrategy {
kind: 'step', kind: 'step',
step: 'verify', step: 'verify',
status: 'done', status: 'done',
detail: { pass: issues.length === 0, quality, issuesCount: issues.length }, detail: {
pass: issues.length === 0,
quality,
issuesCount: issues.length,
issues: issues.map((i) => ({ section: i.section, problem: i.problem, fix: i.fix })),
},
}; };
// ── repair(≤1 轮)── // ── repair(≤1 轮)──
if (issues.length > 0) { if (issues.length > 0) {
ensureLive(); ensureLive();
yield { kind: 'step', step: 'repair', status: 'running', detail: { issuesCount: issues.length } }; yield {
kind: 'step',
step: 'repair',
status: 'running',
detail: {
issuesCount: issues.length,
issues: issues.map((i) => ({ section: i.section, problem: i.problem, fix: i.fix })),
},
};
const w2 = yield* this.streamWrite({ ctx, plan, repairIssues: issues, prevDraft: draft }, runCtx, acc); const w2 = yield* this.streamWrite({ ctx, plan, repairIssues: issues, prevDraft: draft }, runCtx, acc);
draft = w2.output; draft = w2.output;
invocationId = w2.invocationId; invocationId = w2.invocationId;
......
...@@ -36,6 +36,7 @@ export type PlanScriptStreamEvent = ...@@ -36,6 +36,7 @@ export type PlanScriptStreamEvent =
pass?: boolean; pass?: boolean;
quality?: { natural: number; warmth: number; focus: number; nonPushy: number; overall: number } | null; quality?: { natural: number; warmth: number; focus: number; nonPushy: number; overall: number } | null;
issuesCount?: number; issuesCount?: number;
issues?: { section: string; problem: string; fix: string }[];
}; };
} }
| { | {
......
...@@ -114,16 +114,46 @@ function StepDetail({ step: s }: { step: DeepStep }) { ...@@ -114,16 +114,46 @@ function StepDetail({ step: s }: { step: DeepStep }) {
if (s.step === 'verify') { if (s.step === 'verify') {
const q = d.quality?.overall; const q = d.quality?.overall;
return ( return (
<div className="space-y-1">
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] text-slate-500"> <div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] text-slate-500">
<span>接地 + 安全 {d.pass ? '通过' : `${d.issuesCount ?? 0} 处待修`}</span> <span>接地 + 安全 {d.pass ? '通过' : `${d.issuesCount ?? 0} 处待修`}</span>
{typeof q === 'number' && <span>· 质量 {q.toFixed(1)} / 5</span>} {typeof q === 'number' && <span>· 质量 {q.toFixed(1)} / 5</span>}
</div> </div>
<IssueList issues={d.issues} />
</div>
); );
} }
if (s.step === 'repair' && typeof d.issuesCount === 'number') { if (s.step === 'repair' && typeof d.issuesCount === 'number') {
return <div className="text-[11px] text-slate-500">针对 {d.issuesCount} 处问题重写</div>; return (
<div className="space-y-1">
<div className="text-[11px] text-slate-500">针对 {d.issuesCount} 处问题重写</div>
<IssueList issues={d.issues} />
</div>
);
} }
return null; return null;
} }
/** 逐条问题明细:出问题的段 + 哪里不对 + 改法。 */
function IssueList({
issues,
}: {
issues?: { section: string; problem: string; fix: string }[];
}) {
if (!issues?.length) return null;
return (
<ul className="space-y-1">
{issues.map((it, i) => (
<li key={i} className="rounded border border-slate-100 bg-white px-2 py-1 text-[11px] leading-snug">
<div className="font-medium text-slate-600">{it.section || `问题 ${i + 1}`}</div>
<div className="break-words text-slate-500">{it.problem}</div>
{it.fix && (
<div className="mt-0.5 break-words text-teal-600">改法:{it.fix}</div>
)}
</li>
))}
</ul>
);
}
...@@ -39,6 +39,7 @@ export interface DeepStep { ...@@ -39,6 +39,7 @@ export interface DeepStep {
pass?: boolean; pass?: boolean;
quality?: { natural: number; warmth: number; focus: number; nonPushy: number; overall: number } | null; quality?: { natural: number; warmth: number; focus: number; nonPushy: number; overall: number } | null;
issuesCount?: number; issuesCount?: number;
issues?: { section: string; problem: string; fix: string }[];
}; };
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment