// 投放目标 → 选号策略映射 + 提号 SOP 规则 // 结构化自《01-资源寻找方法(更新版).docx》STEP06(没有参考账号时,按投放目标反推账号类型) // 以及《AI提号需求列表》SOP 提号规则(默认 1.5 倍提号、前 10 篇 80% 风格匹配、优先响应明确数量)。 // 投放目标 → 账号类型映射。signals 用于从 brief 文本识别投放目标。 const GOAL_STRATEGIES = { seed_conversion: { zh: '种草转化', signals: ['种草', '转化', '带货', 'ROI', '卖货', '成交', '下单', '电商', '销售', '促转化', '转化率', '转化效果'], accountTypes: ['真实测评账号', '垂类KOC', '素人真实体验'], tierHint: '偏尾部KOC与素人,重真实体验与转化,不要只看粉丝量', note: '重转化时优先真实测评、垂类KOC、素人真实体验;转化链路看 CPE/CPV 与评论区购买意图。' }, brand_exposure: { zh: '品牌曝光', signals: ['曝光', '品牌', '声量', '认知', '知名度', '破圈', '泛流量', '打爆', '传播', '话题', '热度', '出圈'], accountTypes: ['垂类头部腰部KOL', '泛流量账号'], tierHint: '偏头部腰部KOL,重覆盖与声量,兼顾垂类可信度', note: '重曝光时优先垂类头部腰部KOL与泛流量账号,兼顾专业背书与覆盖。' }, search_drain: { zh: '搜索引流', signals: ['搜索', '引流', '关键词', '小蓝词', '沉淀', 'SEO', '搜索词', '蓝词', '长尾', '卡位', '收录'], accountTypes: ['带关键词账号', '可沉淀内容账号', '小蓝词卡位账号'], tierHint: '内容必须带目标搜索关键词、可长期沉淀,卡搜索词/小蓝词', note: '搜索引流看重内容能否带目标关键词、能否长期沉淀,优先能卡搜索词/小蓝词的账号。' }, campaign_volume: { zh: '活动冲量', signals: ['冲量', '活动', '铺量', '同城', '本地', '促销', '大促', '节点', '爆发', '批量', '拉新', '引流到店', '到店'], accountTypes: ['铺量素人', '同城本地账号'], tierHint: '铺量素人 + 同城本地,重数量与节点节奏', note: '活动冲量偏铺量素人与同城本地账号,重数量和节点节奏。' } }; // 提号 SOP 规则(喂给 AI 提升选中率的硬规则) const SUGGESTION_RULES = [ { id: 'suggest-1.5x', title: '默认提号数量 = 需求数量的 1.5 倍以上', multiplier: 1.5, description: '默认提号数量按需求数量的 1.5 倍以上输出,给客户更充分的选择与替换空间。' }, { id: 'style-match-80', title: '前 10 篇笔记至少 80% 风格匹配', threshold: 0.8, description: '候选账号最近 10 篇内容至少 80% 匹配 Brief 调性,否则降级为需复核。' }, { id: 'respond-explicit-count', title: '优先响应明确数量与平台分布', description: 'Brief 明确写了提号数量/平台分布时,严格按数量响应,不自行缩减。' } ]; function detectGoal(text) { const scores = {}; for (const [goal, strategy] of Object.entries(GOAL_STRATEGIES)) { scores[goal] = strategy.signals.filter(signal => String(text || '').includes(signal)).length; } let best = 'brand_exposure'; let bestScore = -1; for (const [goal, score] of Object.entries(scores)) { if (score > bestScore) { best = goal; bestScore = score; } } return best; } function buildGoalStrategy(criteria = {}) { const text = [ criteria.rawText, criteria.brand, criteria.category, ...(criteria.keywords || []) ].filter(Boolean).join(' '); const goal = detectGoal(text); const strategy = GOAL_STRATEGIES[goal] || GOAL_STRATEGIES.brand_exposure; const targetCount = Number(criteria.targetCount || 0); const suggestionCount = targetCount ? Math.ceil(targetCount * 1.5) : 15; return { goal, goalLabel: strategy.zh, accountTypes: strategy.accountTypes, tierHint: strategy.tierHint, note: strategy.note, suggestionCount, suggestionRules: SUGGESTION_RULES, suggestionNote: targetCount ? `Brief 目标 ${targetCount} 位,按 1.5 倍规则建议默认提号 ${suggestionCount} 位以上。` : 'Brief 未明确目标人数,建议默认提号 15 位以上供客户选择。' }; } module.exports = { GOAL_STRATEGIES, SUGGESTION_RULES, detectGoal, buildGoalStrategy };