Files
deerflow-code/web-code/components/angentchat/mockData.ts
T
2026-05-28 18:29:37 +08:00

347 lines
14 KiB
TypeScript
Raw 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.
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<void>;
}
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<void>((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,
};
}