import-feedback-memory.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const path = require('path');
  4. const { readMemory, applyFeedbackRecordsToMemory } = require('../mcp/src/features/tihao-sourcing/preference-memory');
  5. function main() {
  6. const args = parseArgs(process.argv.slice(2));
  7. if (!args.feedback && !args.feedbackPath) {
  8. throw new Error('Usage: node scripts/import-feedback-memory.js --feedback <csv> --memory <memory.json>');
  9. }
  10. const feedbackPath = path.resolve(args.feedback || args.feedbackPath);
  11. const memoryPath = path.resolve(args.memory || args.memoryPath || 'memory/tihao-preference-memory.json');
  12. const records = readFeedbackCsv(feedbackPath);
  13. const memory = applyFeedbackRecordsToMemory(readMemory(memoryPath), records);
  14. fs.mkdirSync(path.dirname(memoryPath), { recursive: true });
  15. fs.writeFileSync(memoryPath, JSON.stringify(memory, null, 2), 'utf8');
  16. const summary = [
  17. '反馈已导入提号偏好记忆。',
  18. `反馈文件:${feedbackPath}`,
  19. `记忆文件:${memoryPath}`,
  20. `导入记录:${records.length}`,
  21. `累计反馈:${memory.feedbackRecords.length}`,
  22. `拉黑/降权账号:${memory.blockedCreators.length}`,
  23. `个人偏好:${memory.personalPreferences.length}`,
  24. `客户/品牌偏好:${memory.clientBrandPreferences.length}`,
  25. `团队规则候选:${memory.teamRuleCandidates.length}`,
  26. `团队规则升级建议:${(memory.teamRuleSuggestions || []).length}`
  27. ].join('\n');
  28. if (args.assistantMessageOnly) console.log(summary);
  29. else console.log(`TIHAO_FEEDBACK_IMPORT=${JSON.stringify({ status: 'ok', summary, data: { memory }, files: [memoryPath] })}`);
  30. }
  31. function readFeedbackCsv(file) {
  32. const text = fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, '');
  33. const lines = text.split(/\r?\n/).filter(Boolean);
  34. const header = parseCsvLine(lines.shift() || '');
  35. return lines.map(line => {
  36. const cells = parseCsvLine(line);
  37. const row = {};
  38. header.forEach((key, index) => {
  39. row[key] = cells[index] || '';
  40. });
  41. return row;
  42. });
  43. }
  44. function parseCsvLine(line) {
  45. const cells = [];
  46. let current = '';
  47. let quoted = false;
  48. for (let i = 0; i < line.length; i += 1) {
  49. const char = line[i];
  50. if (char === '"' && quoted && line[i + 1] === '"') {
  51. current += '"';
  52. i += 1;
  53. } else if (char === '"') {
  54. quoted = !quoted;
  55. } else if (char === ',' && !quoted) {
  56. cells.push(current);
  57. current = '';
  58. } else {
  59. current += char;
  60. }
  61. }
  62. cells.push(current);
  63. return cells;
  64. }
  65. function parseArgs(argv) {
  66. const args = {};
  67. for (let i = 0; i < argv.length; i += 1) {
  68. const raw = argv[i];
  69. if (!raw.startsWith('--')) continue;
  70. const key = raw.slice(2).replace(/-([a-z])/g, (_, char) => char.toUpperCase());
  71. const next = argv[i + 1];
  72. if (!next || next.startsWith('--')) args[key] = true;
  73. else {
  74. args[key] = next;
  75. i += 1;
  76. }
  77. }
  78. return args;
  79. }
  80. if (require.main === module) {
  81. try {
  82. main();
  83. } catch (error) {
  84. console.error(error && error.stack ? error.stack : String(error));
  85. process.exit(1);
  86. }
  87. }
  88. module.exports = {
  89. readFeedbackCsv
  90. };