reference-rules-smoke.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const os = require('os');
  4. const path = require('path');
  5. const { runTihaoSourcing } = require('../mcp/src/tools/tihao-brief-sourcing-run');
  6. const { rankCreators } = require('../mcp/src/features/tihao-sourcing/ranker');
  7. async function main() {
  8. const output = fs.mkdtempSync(path.join(os.tmpdir(), 'tihao-reference-rules-'));
  9. const result = await runTihaoSourcing({
  10. collectionMode: 'sample',
  11. briefText: [
  12. '客户名称:花漾肌研',
  13. '产品:敏感肌屏障修护精华',
  14. '平台:小红书',
  15. '参考账号:一个是专业成分科普,一个是轻娱乐剧情种草。',
  16. '关键词:敏感肌、屏障、修护、成分党、真实体验',
  17. '偏好真实体验、素人感、成分拆解,不要硬广。'
  18. ].join('\n'),
  19. referenceStyleFingerprints: [
  20. {
  21. referenceId: 'ref-professional-science',
  22. url: 'https://www.xiaohongshu.com/explore/ref-professional-science',
  23. platform: 'xiaohongshu',
  24. contentType: 'image_text',
  25. accountName: '专业成分科普号',
  26. personaType: '专业成分党',
  27. contentStructure: '成分解释-功效边界-使用建议',
  28. tone: '理性科普、低情绪',
  29. title: '敏感肌屏障修护怎么选'
  30. },
  31. {
  32. referenceId: 'ref-light-entertainment',
  33. url: 'https://www.xiaohongshu.com/explore/ref-light-entertainment',
  34. platform: 'xiaohongshu',
  35. contentType: 'video',
  36. accountName: '轻娱乐剧情种草号',
  37. personaType: '剧情生活方式',
  38. contentStructure: '剧情冲突-夸张反应-种草转折',
  39. tone: '轻娱乐、情绪化、剧情感',
  40. title: '办公室女孩的护肤翻车剧情',
  41. asrText: '用剧情方式展示护肤翻车和修护体验',
  42. frameUrls: ['https://cdn.example.test/reference-frame.jpg']
  43. }
  44. ],
  45. output
  46. });
  47. assert(result.status === 'ok', 'reference rules sample should run ok');
  48. const usability = result.data.criteria.referenceUsability || {};
  49. assert(usability.status === 'reference_conflict', 'conflicting reference fingerprints should be marked as reference_conflict');
  50. assert(usability.conflict === true, 'reference usability should mark conflict=true');
  51. assert(String(usability.note || '').includes('不能强行合并'), 'reference conflict note should prevent forced unified standard');
  52. const reportPath = path.join(output, 'tihao-sourcing-report.md');
  53. const report = fs.readFileSync(reportPath, 'utf8');
  54. assert(report.includes('reference_conflict'), 'report should expose reference conflict status');
  55. assert(report.includes('不能强行合并为单一调性标准'), 'report should explain that conflicting references cannot be merged');
  56. const strong = (result.data.candidates || []).filter(item => item.recommendStatus === '强推荐');
  57. assert(strong.length >= 1, 'sample should still produce strong candidates');
  58. assert(strong.every(item => (item.briefHitConditions || []).length >= 2), 'strong candidates should have at least two brief hit conditions');
  59. assert(strong.every(item => ((item.referenceStyleHitPoints || []).length + (item.homepageEvidenceHitPoints || []).length) >= 1), 'strong candidates should have reference style or homepage evidence');
  60. assert(strong.every(item => !(item.referenceStyleHitPoints || []).some(point => /待补|需补/.test(String(point)))), 'strong reference style hit points should not contain placeholder evidence');
  61. assert(strong.every(item => String(item.recommendReason || '').includes('参考/风格命中')), 'strong candidate reasons should explain reference/style evidence');
  62. assert(strong.every(item => String(item.recommendReason || '').includes('主页证据命中')), 'strong candidate reasons should explain homepage evidence');
  63. const weakReferenceOnly = rankCreators([{
  64. platform: 'xiaohongshu',
  65. platformUserId: 'weak-reference-placeholder',
  66. displayName: '泛生活方式弱参考号',
  67. profileUrl: 'https://www.xiaohongshu.com/user/profile/weak-reference-placeholder',
  68. fansCount: 90000,
  69. minPrice: 7000,
  70. contentTags: ['护肤', '女性', '生活方式'],
  71. personaTags: ['好物分享'],
  72. recentEvidence: ['近期内容泛生活方式,没有命中参考账号调性']
  73. }], {
  74. brand: '花漾肌研',
  75. category: '护肤',
  76. platforms: ['xiaohongshu'],
  77. keywords: ['护肤', '女性'],
  78. stylePreferences: [],
  79. referenceSignals: ['专业成分党', '低情绪理性科普'],
  80. referenceLinks: [{ url: 'https://www.xiaohongshu.com/user/profile/ref-account', platform: 'xiaohongshu' }],
  81. fanRange: { min: 10000, max: 500000 },
  82. budgetRange: { min: 3000, max: 10000 }
  83. })[0];
  84. assert((weakReferenceOnly.referenceFallbackHitPoints || []).some(point => /需补/.test(String(point))), 'weak reference candidate should keep fallback reference hint');
  85. assert((weakReferenceOnly.referenceStyleHitPoints || []).length === 0, 'fallback reference hints should not enter concrete reference style hit points');
  86. assert(weakReferenceOnly.referenceEvidenceConcrete === false, 'weak reference candidate should mark reference evidence as non-concrete');
  87. assert(weakReferenceOnly.recommendStatus !== '强推荐', 'weak placeholder reference evidence should not be enough for strong recommendation');
  88. console.log(JSON.stringify({
  89. ok: true,
  90. output,
  91. referenceStatus: usability.status,
  92. strong: strong.length
  93. }, null, 2));
  94. }
  95. function assert(condition, message) {
  96. if (!condition) throw new Error(message);
  97. }
  98. main().catch(error => {
  99. console.error(error && error.stack ? error.stack : String(error));
  100. process.exit(1);
  101. });