Files
writer-work-flow/apps/web/lib/toolbox/aiSummary.ts
Yaojia Wang 33a9b7656c feat(frontend): 五类交互接入 AI 对话留痕 + Workbench 抽屉入口(AC-3)
- RefinePanel/ChapterRewritePanel:结束后 append [author(意见/答复), ai(产出)];
  clarify buffer-until-concluded——澄清 Q&A(原意见→反问→答复)缓冲,随最终产出批
  一起落库同 thread;纯放弃不记。refine ai 行 meta 存 version_no+原选段(每版重锚)。
- ContinuePanel:ai-only(续写无作者输入),每候选一条 ai 气泡 meta{candidate_index}。
- GeneratorRunner:成功后 append [author(字段摘要, meta{tool_key,input_fields}),
  ai(渲染预览, meta{tool_key,output_kind})];空产物不记。lib/toolbox/aiSummary.ts 纯助手+单测。
- InlineToolbox→GeneratorRunner 透传 append+本章号;ToolboxPage 用 silent 直投项目级(chapter_no=null)。
- Workbench:挂 useAiConversation 单实例 + AiConversationDrawer + 底栏「AI 对话」入口(flag 灰度),
  三个 DRAFT-only 再接受回调(替换整章/插入正文/回填选段),成功关抽屉+toast、漂移不盲替换。
2026-07-09 17:27:14 +02:00

34 lines
1.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 工具箱生成留痕的两个纯格式化助手AI 对话记录用):
// - fieldSummary把作者填写的输入字段拼成人读摘要author 气泡 content长文进 content 不进 meta
// - renderPreviewText把结构化预览渲染成人读文本ai 气泡 content不把原始产物塞进 meta
// 确定性纯函数,无 IO供 GeneratorRunner 结束后 append 一批往复。
import type { ToolInputFieldView } from "@/lib/api/types";
import type { FieldValues, PreviewModel } from "./toolbox";
// 输入字段 → 「labelvalue」摘要跳过空值多字段用 · 连接。
export function fieldSummary(
fields: readonly ToolInputFieldView[],
values: FieldValues,
): string {
return fields
.map((f) => ({ label: f.label, value: (values[f.name] ?? "").trim() }))
.filter((entry) => entry.value.length > 0)
.map((entry) => `${entry.label}${entry.value}`)
.join(" · ");
}
// 预览模型 → 人读文本:每项 = heading + 「labelvalue」次要字段 + 正文段,项间空行分隔。
export function renderPreviewText(preview: PreviewModel): string {
return preview.items
.map((item) => {
const lines: string[] = [];
if (item.heading) lines.push(item.heading);
for (const f of item.fields) lines.push(`${f.label}${f.value}`);
if (item.body) lines.push(item.body);
return lines.join("\n");
})
.filter((block) => block.length > 0)
.join("\n\n");
}