新 lib/workbench/directive.ts (STYLE_PRESETS + composeDirective 纯函数+测);useDraftStream.start 加 directive 参数(非空时 POST JSON body);Workbench 加「本章指令」textarea + 风格预设 chips,写本章时 composeDirective 传入。TDD: directive 测。前端门禁绿。docs(progress): 记 Tier4 完成。
42 lines
1.5 KiB
TypeScript
42 lines
1.5 KiB
TypeScript
// T4-b · 本章指令组装(纯逻辑,UX §3)。
|
||
// 作者自由文本 + 风格快捷预设 → 单条 directive 串,传入 draft 生成(直通后端 volatile)。
|
||
// 组件只渲染 chips/textarea;预设清单与组装规则集中在此,确定性、不可变。
|
||
|
||
export interface StylePreset {
|
||
id: string;
|
||
label: string;
|
||
text: string;
|
||
}
|
||
|
||
// 风格快捷预设(点选拼入指令开头,引导本章文风)。
|
||
export const STYLE_PRESETS: readonly StylePreset[] = [
|
||
{ id: "less-ai", label: "减少AI味", text: "减少 AI 腔,去掉套话与排比堆砌" },
|
||
{ id: "colloquial", label: "口语化", text: "用更口语、贴近人物的表达" },
|
||
{ id: "fast-pace", label: "快节奏", text: "加快节奏,少铺垫多冲突推进" },
|
||
];
|
||
|
||
const PRESET_BY_ID: ReadonlyMap<string, StylePreset> = new Map(
|
||
STYLE_PRESETS.map((preset) => [preset.id, preset]),
|
||
);
|
||
|
||
const SEPARATOR = ";";
|
||
|
||
// 组合选中预设文案(按 STYLE_PRESETS 原序)+ 自由文本为一条指令。空 → ""。
|
||
export function composeDirective(
|
||
freeText: string,
|
||
presetIds: readonly string[],
|
||
): string {
|
||
const selected = new Set(presetIds);
|
||
const presetTexts = STYLE_PRESETS.filter((preset) =>
|
||
selected.has(preset.id),
|
||
).map((preset) => preset.text);
|
||
const trimmedFree = freeText.trim();
|
||
const parts = trimmedFree ? [...presetTexts, trimmedFree] : presetTexts;
|
||
return parts.join(SEPARATOR);
|
||
}
|
||
|
||
// 仅暴露给测试/组件的辅助:id 是否为已知预设。
|
||
export function isKnownPreset(id: string): boolean {
|
||
return PRESET_BY_ID.has(id);
|
||
}
|