import type { ActorCard, BehaviorDriverCard, MainStepKey, NarrativeCard, PurposeCard, SixStepMessage, StepStatus, SubStepKey, } from './types'; const PURPOSE_SEED: { title: string; reason: string }[] = [ { title: '建立品牌权威认知', reason: '通过持续的专业内容输出,塑造行业领导者形象,使核心受众在面对同类品牌时优先想起本品牌,并带来长期信任度' }, { title: '激活核心用户决策路径', reason: '梳理用户从兴趣触达到决策转化的关键触点,缩短决策链路、提升转化效率' }, { title: '强化情感价值连接', reason: '通过故事化叙事激发情绪共鸣,沉淀难以被替代的品牌情感资产' }, ]; const ACTOR_SEED: { title: string; content: string }[] = [ { title: '行业意见领袖(KOL)', content: '在专业垂直领域有持续影响力,可在第一时间撬动核心圈层并带动二次扩散' }, { title: '品牌官方账号矩阵', content: '统一对外传递品牌主张与最新动态,承担信息发布、用户互动与口碑响应' }, { title: '深度内容创作者', content: '产出长图文、视频解读等内容形态,承担引发讨论与口碑沉淀的角色' }, { title: '行业垂直媒体', content: '具备专业背书能力,承担议题设置与权威背书职责' }, { title: '核心用户共创社区', content: '由忠诚用户构成,通过 UGC 形式输出真实使用反馈与场景示范' }, { title: '行业分析机构', content: '通过研究报告与数据支撑品牌主张,加强观点的可信度' }, { title: '品牌代言关键人', content: '与品牌价值观高度契合的代言人或合作方,承担情感投射与信任放大' }, ]; const BEHAVIOR_SEED: { expectedBehavior: string; driver: string }[] = [ { expectedBehavior: '主动转发并附带专业点评', driver: '内容契合自身专业立场,带来圈层认同与社交资本' }, { expectedBehavior: '在专业社区发起延伸讨论', driver: '议题具备争议或洞察价值,能引发同行参与并扩散' }, { expectedBehavior: '将品牌内容沉淀为参考资料', driver: '内容具备结构化、可复用的方法论价值,可在工作中长期引用' }, { expectedBehavior: '主动在直播间或路演中引用品牌观点', driver: '观点具备可解释性,能帮助行为体强化自身专业可信度' }, { expectedBehavior: '产出二次内容(长图文 / 视频)', driver: '原始素材具备可改编空间,能匹配自身受众语境' }, { expectedBehavior: '组织线下闭门交流会', driver: '议题对核心受众具备稀缺性,符合社群运营节奏' }, { expectedBehavior: '在调研报告中将品牌列为典型案例', driver: '品牌案例具备数据支撑、典型且可被结构化引用' }, { expectedBehavior: '在公开演讲中引用品牌叙事框架', driver: '叙事框架具备方法论高度,可被借用以提升自身演讲含金量' }, ]; const NARRATIVE_SEED: { title: string; reason: string }[] = [ { title: '从噪音中识别真实信号', reason: '聚焦行业过度信息的痛点,主张以理性框架回归本质' }, { title: '让专业判断回到决策中心', reason: '强调专业判断在复杂环境下的不可替代性' }, { title: '以长期主义穿越周期', reason: '倡导关注长期价值积累,而非短期爆点' }, { title: '把复杂问题讲简单', reason: '通过结构化表达让专业内容更易被传播与理解' }, { title: '让每一次选择都有迹可循', reason: '强调决策可追溯、可复盘,建立专业信任' }, { title: '与时间做朋友', reason: '把品牌成长锚定在长期视角,淡化短期波动焦虑' }, { title: '相信专业的力量', reason: '通过行为体共同的专业身份认同强化品牌主张' }, { title: '把方法论变成可复用的工具', reason: '将抽象主张沉淀为工具化资产,方便受众反复引用' }, ]; const PURPOSE_THINKING = `根据当前问题语境,需要先厘清品牌战略推演的核心目的: 1. 综合输入素材,识别可能的目标方向; 2. 评估不同目的之间的优先级与互补性; 3. 选择最契合当前阶段的目的组合,作为后续推演基础。`; const ACTOR_THINKING = `围绕已生成的目的,开始识别支撑该目的所需的关键行为体: - 需要明确每个行为体的角色定位 - 评估其对目的的贡献度与覆盖范围 - 避免行为体之间能力重叠或缺位`; const BEHAVIOR_THINKING = `针对每个行为体,推演其在场景中应当展现的预期行为: - 行为需要可观察、可衡量 - 同时识别推动该行为发生的关键驱动因素 - 行为与驱动因素需保持因果一致性`; const NARRATIVE_THINKING = `基于驱动因素,构建用于触发行为的叙事框架: - 叙事需要紧扣驱动因素的情绪或理性触点 - 兼顾品牌主张与受众心智匹配度 - 形成可被复用的叙事模板`; export interface SixStepMockController { message: SixStepMessage; stop: () => void; promise: Promise; } const TYPE_INTERVAL = 28; const STAGE_GAP = 380; function buildPurposeCards(): PurposeCard[] { return PURPOSE_SEED.map((seed, idx) => ({ id: `purpose-${idx + 1}`, index: idx + 1, title: seed.title, reason: seed.reason, })); } function buildActorCards(purposes: PurposeCard[]): ActorCard[] { const cards: ActorCard[] = []; let counter = 0; purposes.forEach((purpose, pIdx) => { const count = pIdx === 0 ? 2 : 1; for (let i = 0; i < count; i += 1) { counter += 1; const seed = ACTOR_SEED[(counter - 1) % ACTOR_SEED.length]; cards.push({ id: `actor-${counter}`, index: counter, purposeId: purpose.id, title: seed.title, content: seed.content, }); } }); return cards; } function buildBehaviorCards(actors: ActorCard[]): BehaviorDriverCard[] { const cards: BehaviorDriverCard[] = []; let counter = 0; actors.forEach((actor, aIdx) => { const count = aIdx % 2 === 0 ? 2 : 1; for (let i = 0; i < count; i += 1) { counter += 1; const seed = BEHAVIOR_SEED[(counter - 1) % BEHAVIOR_SEED.length]; cards.push({ id: `behavior-${counter}`, index: counter, actorId: actor.id, expectedBehavior: seed.expectedBehavior, driver: seed.driver, }); } }); return cards; } function buildNarrativeCards(behaviors: BehaviorDriverCard[]): NarrativeCard[] { const cards: NarrativeCard[] = []; let counter = 0; behaviors.forEach((behavior, bIdx) => { const count = bIdx % 2 === 0 ? 2 : 1; for (let i = 0; i < count; i += 1) { counter += 1; const seed = NARRATIVE_SEED[(counter - 1) % NARRATIVE_SEED.length]; cards.push({ id: `narrative-${counter}`, index: counter, driverId: behavior.id, title: seed.title, reason: seed.reason, }); } }); return cards; } function buildFinalAnswer(): string { return `综合本次 6 步法推演结果,可以得到如下战略要点: 1. **目的**:以品牌权威认知为锚点,在专业人群中建立可信表达。 2. **行为体**:依靠 KOL、官方账号矩阵、深度创作者三类协同发声。 3. **预期行为与驱动因素**:通过专业内容激发主动传播与延伸讨论,形成圈层共振。 4. **叙事**:以"在噪音中识别真实信号"为核心叙事线,串联整个传播节奏。 后续可基于该推演继续生成传播节奏、渠道分工与内容资产清单。`; } export function buildInitialAssistantMessage(): SixStepMessage { return { id: `assistant-${Date.now()}`, role: 'assistant', content: '', timestamp: new Date(), stages: {}, finalAnswer: '', mainStepStatus: { info: 'pending', sixstep: 'pending', final: 'pending' }, subStepStatus: { purpose: 'pending', actor: 'pending', behavior: 'pending', narrative: 'pending' }, }; } interface RunOptions { onUpdate: (message: SixStepMessage) => void; onComplete?: () => void; } /** * 模拟 6 步法推演的全过程:信息准备 → 6 步法(4 个阶段) → 最终结果。 * * 通过分阶段写入 thinking 文本和卡片,模拟真实流式生成效果。 */ export function runSixStepDeduction(message: SixStepMessage, options: RunOptions): SixStepMockController { let cancelled = false; const timers: number[] = []; const wait = (ms: number) => new Promise((resolve) => { const id = window.setTimeout(() => { resolve(); }, ms); timers.push(id); }); const setMain = (key: MainStepKey, status: StepStatus) => { message.mainStepStatus = { ...(message.mainStepStatus ?? { info: 'pending', sixstep: 'pending', final: 'pending' }), [key]: status }; if (status === 'running') { message.currentMainStep = key; } }; const setSub = (key: SubStepKey, status: StepStatus) => { message.subStepStatus = { ...(message.subStepStatus ?? { purpose: 'pending', actor: 'pending', behavior: 'pending', narrative: 'pending' }), [key]: status, }; if (status === 'running') { message.currentSubStep = key; } }; const emit = () => { if (cancelled) return; options.onUpdate({ ...message, stages: { ...message.stages } }); }; const typeInto = async (text: string, write: (chunk: string) => void) => { const step = 4; for (let i = 0; i <= text.length; i += step) { if (cancelled) return; write(text.slice(0, i)); emit(); await wait(TYPE_INTERVAL); } if (!cancelled) { write(text); emit(); } }; const promise = (async () => { setMain('info', 'running'); emit(); await wait(800); if (cancelled) return; setMain('info', 'done'); setMain('sixstep', 'running'); emit(); await wait(STAGE_GAP); setSub('purpose', 'running'); message.stages = { ...message.stages, purpose: { thinking: '', cards: [], complete: false } }; emit(); await typeInto(PURPOSE_THINKING, (chunk) => { message.stages = { ...message.stages, purpose: { ...(message.stages?.purpose as any), thinking: chunk } }; }); if (cancelled) return; const purposes = buildPurposeCards(); for (const card of purposes) { if (cancelled) return; const existing = message.stages?.purpose?.cards ?? []; message.stages = { ...message.stages, purpose: { ...(message.stages?.purpose as any), cards: [...existing, card] } }; emit(); await wait(280); } message.stages = { ...message.stages, purpose: { ...(message.stages?.purpose as any), complete: true } }; setSub('purpose', 'done'); emit(); await wait(STAGE_GAP); setSub('actor', 'running'); message.stages = { ...message.stages, actor: { thinking: '', cards: [], complete: false } }; emit(); await typeInto(ACTOR_THINKING, (chunk) => { message.stages = { ...message.stages, actor: { ...(message.stages?.actor as any), thinking: chunk } }; }); if (cancelled) return; const actors = buildActorCards(purposes); for (const card of actors) { if (cancelled) return; const existing = message.stages?.actor?.cards ?? []; message.stages = { ...message.stages, actor: { ...(message.stages?.actor as any), cards: [...existing, card] } }; emit(); await wait(220); } message.stages = { ...message.stages, actor: { ...(message.stages?.actor as any), complete: true } }; setSub('actor', 'done'); emit(); await wait(STAGE_GAP); setSub('behavior', 'running'); message.stages = { ...message.stages, behavior: { thinking: '', cards: [], complete: false } }; emit(); await typeInto(BEHAVIOR_THINKING, (chunk) => { message.stages = { ...message.stages, behavior: { ...(message.stages?.behavior as any), thinking: chunk } }; }); if (cancelled) return; const behaviors = buildBehaviorCards(actors); for (const card of behaviors) { if (cancelled) return; const existing = message.stages?.behavior?.cards ?? []; message.stages = { ...message.stages, behavior: { ...(message.stages?.behavior as any), cards: [...existing, card] } }; emit(); await wait(200); } message.stages = { ...message.stages, behavior: { ...(message.stages?.behavior as any), complete: true } }; setSub('behavior', 'done'); emit(); await wait(STAGE_GAP); setSub('narrative', 'running'); message.stages = { ...message.stages, narrative: { thinking: '', cards: [], complete: false } }; emit(); await typeInto(NARRATIVE_THINKING, (chunk) => { message.stages = { ...message.stages, narrative: { ...(message.stages?.narrative as any), thinking: chunk } }; }); if (cancelled) return; const narratives = buildNarrativeCards(behaviors); for (const card of narratives) { if (cancelled) return; const existing = message.stages?.narrative?.cards ?? []; message.stages = { ...message.stages, narrative: { ...(message.stages?.narrative as any), cards: [...existing, card] } }; emit(); await wait(200); } message.stages = { ...message.stages, narrative: { ...(message.stages?.narrative as any), complete: true } }; setSub('narrative', 'done'); setMain('sixstep', 'done'); setMain('final', 'running'); emit(); await wait(STAGE_GAP); if (cancelled) return; await typeInto(buildFinalAnswer(), (chunk) => { message.finalAnswer = chunk; }); if (cancelled) return; setMain('final', 'done'); message.currentMainStep = undefined; message.currentSubStep = undefined; emit(); options.onComplete?.(); })(); return { message, stop: () => { cancelled = true; timers.forEach((t) => window.clearTimeout(t)); }, promise, }; }