fill_card_examples.js 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // 为雅思卡片(UserID=2, MiaoguoCardID>=1671933)的 ContentType=2 补充例句
  2. // 例句来源: kylx365_db.Words.ExampleSentence (BookID 212-217, 每词5句)
  3. // 渲染格式参照"其余单词"卡片: 例句:\n[读]英文句[/读]\n中文翻译
  4. import { query } from '../../../src/util/db.js';
  5. import { stringUtils } from '../../../src/util/stringClass.js';
  6. function extractWord(content) {
  7. // 优先从音频URL提取: gettts?...&text=regent&...
  8. let m = content.match(/text=([^&]+)/);
  9. if (m && m[1]) return decodeURIComponent(m[1]).trim();
  10. // 兜底: "regent 的基本中文释义"
  11. m = content.match(/^(.*?)\s*的基本中文释义/);
  12. if (m && m[1]) return m[1].trim();
  13. return null;
  14. }
  15. // 高亮单词(参照 build.test31.js / 已有雅思卡片格式: [线]word[/线])
  16. function highlightWord(sentence, word) {
  17. const forms = stringUtils.getWordAllForms(word);
  18. let sent = sentence;
  19. for (const form of forms) {
  20. if (sent.indexOf(form) >= 0) {
  21. sent = sent.replace(form, '[线]' + form + '[/线]');
  22. break;
  23. }
  24. }
  25. return sent;
  26. }
  27. // 渲染格式与"其余单词"雅思卡片一致: 例句:\n英文(高亮单词)\n中文\n\n...
  28. function buildExampleBlock(sentences, word) {
  29. const lines = sentences.map(s => highlightWord(s.Sentence, word) + '\n' + s.Translate);
  30. return '\n例句:\n' + lines.join('\n\n') + '\n\n';
  31. }
  32. async function run({ dryRun = false } = {}) {
  33. // 1) 取目标卡片
  34. const cards = await query(
  35. 'SELECT MiaoguoCardID FROM kylx365_db.MiaoguoCard where UserID=2 and MiaoguoCardID>=1671933 order by MiaoguoCardID'
  36. );
  37. const ids = cards.map(r => r.MiaoguoCardID);
  38. console.log('目标卡片数:', ids.length);
  39. let updated = 0, skipped = 0, noWord = 0, noSrc = 0;
  40. for (const cid of ids) {
  41. const rows = await query(
  42. 'select Content from kylx365_db.MiaoguoContent where MiaoguoCardID=? and ContentType=2',
  43. [cid]
  44. );
  45. if (!rows.length) { noWord++; console.log(' 跳过(无ContentType=2):', cid); continue; }
  46. let content = rows[0].Content;
  47. if (content.includes('例句:')) { skipped++; continue; }
  48. const word = extractWord(content);
  49. if (!word) { noWord++; console.log(' 跳过(无法提取单词):', cid); continue; }
  50. // 2) 查 Words.ExampleSentence
  51. const ws = await query(
  52. 'select ExampleSentence from kylx365_db.Words where BookID in (212,213,214,215,216,217) and Word=? limit 1',
  53. [word]
  54. );
  55. if (!ws.length || !ws[0].ExampleSentence) { noSrc++; console.log(' 跳过(无例句源):', cid, word); continue; }
  56. let parsed;
  57. try { parsed = JSON.parse(ws[0].ExampleSentence); }
  58. catch (e) { noSrc++; console.log(' 跳过(JSON解析失败):', cid, word); continue; }
  59. const sentences = (parsed.Sentences || []).filter(s => s.Sentence && s.Translate);
  60. if (!sentences.length) { noSrc++; console.log(' 跳过(例句为空):', cid, word); continue; }
  61. const block = buildExampleBlock(sentences, word);
  62. const newContent = content.replace(/\s*$/, '') + block;
  63. if (dryRun) {
  64. console.log(`\n=== [预览] Card ${cid} word=${word} 例句数=${sentences.length} ===`);
  65. console.log(newContent.slice(0, 700));
  66. } else {
  67. await query(
  68. 'update kylx365_db.MiaoguoContent set Content=? where MiaoguoCardID=? and ContentType=2',
  69. [newContent, cid]
  70. );
  71. updated++;
  72. if (updated <= 2) {
  73. console.log(`\n=== [已写] Card ${cid} word=${word} 例句数=${sentences.length} ===`);
  74. console.log(newContent.slice(0, 700));
  75. }
  76. }
  77. }
  78. console.log(`\n完成. updated=${updated} skipped(已有例句)=${skipped} noWord=${noWord} noSrc=${noSrc}`);
  79. process.exit(0);
  80. }
  81. const dryRun = process.argv.includes('--dry');
  82. run({ dryRun }).catch(e => { console.error(e); process.exit(1); });