hard-rules-smoke.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const os = require('os');
  4. const path = require('path');
  5. const { enrichCriteriaWithExperience } = require('../mcp/src/features/tihao-sourcing/experience-rules');
  6. const { rankCreators } = require('../mcp/src/features/tihao-sourcing/ranker');
  7. const { buildSourcingReport } = require('../mcp/src/features/tihao-sourcing/report');
  8. function main() {
  9. const outputDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-hard-rules-'));
  10. const criteria = enrichCriteriaWithExperience({
  11. brand: 'Ulike',
  12. rawText: 'Ulike 脱毛仪,偏女性精致护理场景,不要竞品X,预算 3000-10000。',
  13. category: '美容仪/脱毛仪',
  14. platforms: ['xiaohongshu'],
  15. keywords: ['脱毛仪', '护肤', '女性', '精致'],
  16. stylePreferences: ['女性', '精致', '护肤', '真人出镜'],
  17. referenceSignals: ['女性', '护肤', '护理'],
  18. exclusions: ['竞品X'],
  19. performanceRequirements: ['近30天需有更新', '近30天平均点赞≥100', '复核数据真实性/重复评论风险'],
  20. fanRange: { min: 10000, max: 500000 },
  21. budgetRange: { min: 3000, max: 10000 },
  22. targetCount: 3
  23. });
  24. const ranked = rankCreators([
  25. {
  26. platform: 'xiaohongshu',
  27. platformUserId: 'good-female-care',
  28. displayName: '精致护理真实记录',
  29. profileUrl: 'https://www.xiaohongshu.com/user/profile/good-female-care',
  30. fansCount: 68000,
  31. minPrice: 8000,
  32. contentTags: ['脱毛仪', '护肤', '女性', '精致', '真人出镜'],
  33. personaTags: ['美妆', '生活方式', '护理'],
  34. recentEvidence: ['近期内容是女性精致护理和脱毛仪真实体验']
  35. },
  36. {
  37. platform: 'xiaohongshu',
  38. platformUserId: 'male-generic',
  39. displayName: '男生游戏汽车日常',
  40. profileUrl: 'https://www.xiaohongshu.com/user/profile/male-generic',
  41. fansCount: 90000,
  42. minPrice: 7000,
  43. contentTags: ['男生', '游戏', '汽车', '脱毛仪'],
  44. personaTags: ['男性泛账号', '体育'],
  45. recentEvidence: ['近期以男生游戏汽车内容为主,偶尔提到脱毛仪']
  46. },
  47. {
  48. platform: 'xiaohongshu',
  49. platformUserId: 'competitor-account',
  50. displayName: '竞品X护理测评号',
  51. profileUrl: 'https://www.xiaohongshu.com/user/profile/competitor-account',
  52. fansCount: 75000,
  53. minPrice: 8500,
  54. contentTags: ['脱毛仪', '女性', '精致', '竞品X'],
  55. personaTags: ['美妆', '护理'],
  56. recentEvidence: ['近期多次出现竞品X合作内容']
  57. },
  58. {
  59. platform: 'xiaohongshu',
  60. platformUserId: 'over-budget',
  61. displayName: '高报价精致护理号',
  62. profileUrl: 'https://www.xiaohongshu.com/user/profile/over-budget',
  63. fansCount: 82000,
  64. minPrice: 30000,
  65. contentTags: ['脱毛仪', '护肤', '女性', '精致'],
  66. personaTags: ['美妆', '生活方式'],
  67. recentEvidence: ['近期内容匹配女性护理,但报价明显高于预算']
  68. },
  69. {
  70. platform: 'xiaohongshu',
  71. platformUserId: 'low-homepage-quality',
  72. displayName: '低质封面护理号',
  73. profileUrl: 'https://www.xiaohongshu.com/user/profile/low-homepage-quality',
  74. fansCount: 86000,
  75. minPrice: 7000,
  76. contentTags: ['脱毛仪', '护肤', '女性', '精致', '真人出镜'],
  77. personaTags: ['美妆', '生活方式', '护理'],
  78. recentEvidence: ['近期内容是女性精致护理和脱毛仪真实体验,但封面下沉、封面混乱、排版混乱']
  79. },
  80. {
  81. platform: 'xiaohongshu',
  82. platformUserId: 'stale-fake-data',
  83. displayName: '停更数据异常护理号',
  84. profileUrl: 'https://www.xiaohongshu.com/user/profile/stale-fake-data',
  85. fansCount: 72000,
  86. minPrice: 6500,
  87. recentAverageLikes: 72,
  88. lastPostDaysAgo: 46,
  89. repeatedCommenterCount: 3,
  90. contentTags: ['脱毛仪', '护肤', '女性', '精致', '真人出镜'],
  91. personaTags: ['美妆', '生活方式', '护理'],
  92. recentEvidence: ['近一个月没有发,平均点赞低于100,同一个人评论多篇,封面统一但数据真实性存疑']
  93. },
  94. {
  95. platform: 'douyin',
  96. platformUserId: 'wrong-platform',
  97. displayName: '错平台优质护理号',
  98. profileUrl: 'https://www.douyin.com/user/wrong-platform',
  99. fansCount: 60000,
  100. minPrice: 7000,
  101. contentTags: ['脱毛仪', '女性', '护肤', '精致'],
  102. personaTags: ['美妆'],
  103. recentEvidence: ['平台不符合 brief']
  104. }
  105. ], criteria);
  106. const byId = Object.fromEntries(ranked.map(item => [item.platformUserId, item]));
  107. assert(!byId['wrong-platform'], 'wrong platform creator should be filtered before ranking');
  108. assert(byId['good-female-care'].recommendStatus === '强推荐', 'matching female care creator should be strong recommendation');
  109. assert(byId['male-generic'].recommendStatus !== '强推荐', 'male generic account should not be strong recommendation for beauty device');
  110. assert((byId['male-generic'].implicitRuleViolations || []).length > 0, 'male generic account should carry implicit rule violation');
  111. assert(byId['competitor-account'].recommendStatus === '已剔除', 'explicit competitor exclusion should be removed');
  112. assert((byId['competitor-account'].exclusionHits || []).includes('竞品X'), 'competitor account should record exclusion hit');
  113. assert(byId['over-budget'].recommendStatus !== '强推荐', 'over-budget creator should not be strong recommendation');
  114. assert(String(byId['over-budget'].riskNote || '').includes('报价高于预算'), 'over-budget creator should carry budget risk note');
  115. assert(byId['low-homepage-quality'].recommendStatus !== '强推荐', 'low homepage quality creator should not be strong recommendation');
  116. assert((byId['low-homepage-quality'].homepageQualityRisks || []).includes('封面下沉'), 'low homepage quality creator should carry visual risk signals');
  117. assert(String(byId['low-homepage-quality'].riskNote || '').includes('主页质感风险'), 'low homepage quality creator should explain homepage quality risk');
  118. assert(byId['stale-fake-data'].recommendStatus !== '强推荐', 'stale/fake data creator should not be strong recommendation');
  119. assert((byId['stale-fake-data'].homepageDataRisks || []).some(item => item.includes('近30天')), 'stale creator should carry recent update data risk');
  120. assert(String(byId['stale-fake-data'].riskNote || '').includes('数据真实性/活跃风险'), 'stale creator should explain data authenticity risk');
  121. assert((byId['stale-fake-data'].manualReviewFields || []).includes('近30天更新'), 'stale creator should require recent update review');
  122. assert((byId['stale-fake-data'].manualReviewFields || []).includes('平均点赞'), 'stale creator should require average-like review');
  123. assert((byId['stale-fake-data'].manualReviewFields || []).includes('重复评论/数据真实性'), 'stale creator should require repeated-comment review');
  124. const report = buildSourcingReport({
  125. criteria,
  126. candidates: ranked,
  127. collectionMode: 'sample',
  128. outputDir
  129. });
  130. const csvPath = path.join(outputDir, 'tihao-sourcing-client-list.csv');
  131. const csv = fs.readFileSync(csvPath, 'utf8');
  132. assert(!csv.includes('竞品X护理测评号'), 'excluded competitor should not enter software CSV');
  133. assert(!report.data.candidates.some(item => item.recommendStatus === '已剔除'), 'excluded creators should not enter client-ready candidates');
  134. console.log(JSON.stringify({
  135. ok: true,
  136. outputDir,
  137. strong: ranked.filter(item => item.recommendStatus === '强推荐').length,
  138. excluded: ranked.filter(item => item.recommendStatus === '已剔除').length
  139. }, null, 2));
  140. }
  141. function assert(condition, message) {
  142. if (!condition) throw new Error(message);
  143. }
  144. main();