generate-lobster-db-repair-sql.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /**
  2. * Generate lobster DB garbled-text repair SQL from catalog + menu map.
  3. * Usage: node java/fs-service/scripts/generate-lobster-db-repair-sql.js
  4. * All Chinese in this file use \\u escapes (Windows-safe).
  5. */
  6. const fs = require('fs');
  7. const path = require('path');
  8. const catalogPath = path.join(__dirname, '../src/main/java/com/fs/company/service/workflow/prompt/LobsterEnginePromptCatalog.java');
  9. const tenantOut = path.join(__dirname, '../../fs-agent/src/main/resources/db/migration/tenant/V20260622_01__lobster_garbled_text_repair.sql');
  10. const masterOut = path.join(__dirname, '../../sql/master/V20260622_01__lobster_garbled_text_repair.sql');
  11. const LOBSTER_MENUS = {
  12. 29900: '\u9f99\u8679\u5f15\u64ce',
  13. 29901: 'AI\u751f\u4ea7\u5de5\u4f5c\u6d41',
  14. 29902: '\u5de5\u4f5c\u6d41\u753b\u5e03',
  15. 29903: '\u5de5\u4f5c\u6d41\u6a21\u677f\u5e93',
  16. 29904: 'AI\u751f\u6210\u5de5\u4f5c\u6d41',
  17. 29905: '\u5b9e\u4f8b\u76d1\u63a7',
  18. 29906: 'AI\u4f18\u5316\u5efa\u8bae',
  19. 29907: '\u63d0\u793a\u8bcd\u7ba1\u7406',
  20. 29908: '\u9500\u51a0\u8bed\u6599\u5b66\u4e60',
  21. 29909: '\u63a5\u53e3\u6ce8\u518c\u4e2d\u5fc3',
  22. 29910: '\u6b7b\u4fe1\u961f\u5217',
  23. 29911: '\u8282\u70b9\u5ba1\u6838',
  24. 29912: '\u805a\u5408\u804a\u5929',
  25. 29913: '\u6a21\u578b\u914d\u7f6e',
  26. 29914: 'Token\u7cfb\u6570\u7ba1\u7406',
  27. 29920: '\u6a21\u62df\u804a\u5929\u6d4b\u8bd5',
  28. 29921: '\u8bc4\u5206\u51c6\u786e\u6027\u9a8c\u8bc1',
  29. 29922: '\u7528\u6237\u753b\u50cf\u914d\u7f6e',
  30. 29924: '\u6d88\u606f\u53bb\u91cd\u914d\u7f6e',
  31. 29925: '\u654f\u611f\u8bcd\u5e93',
  32. 29926: '\u8282\u70b9\u8be6\u60c5',
  33. 29933: '\u79df\u6237\u8bed\u4e49\u5173\u952e\u8bcd',
  34. 29934: '\u8eab\u4efd\u9690\u85cf\u914d\u7f6e',
  35. 29936: '\u6e20\u9053\u63d2\u4ef6',
  36. 29937: 'Token\u6d88\u8017\u7edf\u8ba1',
  37. 29938: '\u5f15\u64ce\u770b\u677f',
  38. 29939: 'AI\u8fdb\u5316\u5f15\u64ce',
  39. 29940: '\u8282\u70b9\u80fd\u529b\u77e9\u9635',
  40. 29941: '\u8bdd\u672f\u4f18\u5316',
  41. 29944: '\u6e20\u9053\u914d\u7f6e',
  42. 29946: '\u591a\u6a21\u578b\u8def\u7531\u914d\u7f6e',
  43. 29947: '\u6267\u884c\u7b56\u7565\u914d\u7f6e',
  44. 29948: '\u4f1a\u8bdd\u6458\u8981',
  45. 29949: '\u5de5\u4f5c\u6d41\u6267\u884c\u4efb\u52a1',
  46. 29950: '\u5ba2\u6237\u753b\u50cf',
  47. 3006: '\u6d4b\u8bd5\u573a\u666f\u7ba1\u7406',
  48. 3007: 'E2E\u8fd0\u884c\u5386\u53f2',
  49. 3008: '\u52a8\u6001\u8282\u70b9\u5ba1\u6279',
  50. 32481: '\u9f99\u8679\u5de5\u4f5c\u6d41'
  51. };
  52. const AI_SCENES = {
  53. workflow_llm: '\u63d0\u793a\u8bcd\u7ba1\u7406',
  54. summary_generation: '\u6458\u8981\u751f\u6210',
  55. workflow_generation: '\u5de5\u4f5c\u6d41\u751f\u6210',
  56. dynamic_node: '\u52a8\u6001\u8282\u70b9',
  57. workflow_evolution: '\u5de5\u4f5c\u6d41\u8fdb\u5316',
  58. quality_scoring: '\u8d28\u91cf\u8bc4\u5206',
  59. semantic_analysis: '\u8bed\u4e49\u5206\u6790'
  60. };
  61. function sqlEscape(s) {
  62. if (s == null) return '';
  63. return String(s).replace(/\\/g, '\\\\').replace(/'/g, "''");
  64. }
  65. function parseCatalog() {
  66. const src = fs.readFileSync(catalogPath, 'utf8');
  67. const simpleRe = /reg\(\s*"([^"]+)"\s*,\s*"([^"]+)"\s*,\s*"([^"]+)"/g;
  68. const rows = [];
  69. let m;
  70. while ((m = simpleRe.exec(src)) !== null) {
  71. rows.push({ key: m[1], name: m[2], category: m[3] });
  72. }
  73. return rows;
  74. }
  75. function garbledCondition(column) {
  76. return `(
  77. ${column} IS NULL OR TRIM(${column}) = ''
  78. OR ${column} LIKE '%?%'
  79. OR HEX(${column}) LIKE '3F3F%'
  80. OR ${column} LIKE 'u5de5%'
  81. OR ${column} LIKE 'u4f5c%'
  82. OR ${column} REGEXP '^u[0-9a-fA-F]{4}(u[0-9a-fA-F]{4})+$'
  83. OR ${column} LIKE '%\\\\u5de5%'
  84. )`;
  85. }
  86. function menuRepairBlock(table) {
  87. const lines = [`-- ${table}: fix lobster menu_name`];
  88. for (const [id, name] of Object.entries(LOBSTER_MENUS)) {
  89. lines.push(
  90. `UPDATE ${table} SET menu_name='${sqlEscape(name)}', update_time=NOW() ` +
  91. `WHERE menu_id=${id} AND menu_name <> '${sqlEscape(name)}' ` +
  92. `AND ${garbledCondition('menu_name')};`
  93. );
  94. }
  95. return lines.join('\n');
  96. }
  97. function promptRepairBlock() {
  98. const rows = parseCatalog();
  99. const lines = ['-- lobster_system_prompt: fix garbled/empty prompt_name & prompt_category'];
  100. for (const row of rows) {
  101. lines.push(
  102. `UPDATE lobster_system_prompt SET prompt_name='${sqlEscape(row.name)}', ` +
  103. `prompt_category='${sqlEscape(row.category)}', update_time=NOW() ` +
  104. `WHERE prompt_key='${sqlEscape(row.key)}' AND company_id IS NULL AND (` +
  105. `${garbledCondition('prompt_name')} OR ${garbledCondition('prompt_category')} ` +
  106. `OR prompt_name <> '${sqlEscape(row.name)}' OR prompt_category <> '${sqlEscape(row.category)}');`
  107. );
  108. }
  109. return lines.join('\n');
  110. }
  111. function aiSceneBlock() {
  112. const lines = ['-- admin_ai_scene: fix lobster-related scene names (master DB only)'];
  113. for (const [code, name] of Object.entries(AI_SCENES)) {
  114. lines.push(
  115. `UPDATE admin_ai_scene SET scene_name='${sqlEscape(name)}', update_time=NOW() ` +
  116. `WHERE scene_code='${sqlEscape(code)}' AND (scene_name <> '${sqlEscape(name)}' OR ${garbledCondition('scene_name')});`
  117. );
  118. }
  119. return lines.join('\n');
  120. }
  121. function unicodeEscapeMenuFix() {
  122. return `-- Fix menu_name stored as literal u5de5... unicode escapes
  123. UPDATE sys_menu SET menu_name = CONVERT(UNHEX('E9BE99E8909DE5BC95E6938E') USING utf8mb4)
  124. WHERE menu_id = 29900 AND (menu_name LIKE 'u9f99u8679%' OR menu_name REGEXP '^u[0-9a-fA-F]{4}(u[0-9a-fA-F]{4})+$');
  125. UPDATE sys_menu SET menu_name = CONVERT(UNHEX('E5B7A5E4BD9CE6B581E6A8A1E69DBF') USING utf8mb4)
  126. WHERE menu_id IN (29903, 32481) OR menu_name LIKE 'u5de5u4f5cu6d41u6a21%';
  127. UPDATE sys_menu SET menu_name = CONVERT(UNHEX('E5B7A5E4BD9CE6B581E689A7E8A18C') USING utf8mb4)
  128. WHERE menu_id = 29949 OR menu_name LIKE 'u5de5u4f5cu6d41u6267%';
  129. UPDATE sys_menu SET menu_name = CONVERT(UNHEX('E5AEA2E688B7E794BBE5838F') USING utf8mb4)
  130. WHERE menu_id = 29950 OR menu_name LIKE 'u5ba2u6237u753b%';
  131. UPDATE company_menu SET menu_name = CONVERT(UNHEX('E5B7A5E4BD9CE6B581E6A8A1E69DBF') USING utf8mb4)
  132. WHERE menu_id IN (29903, 32481) OR menu_name LIKE 'u5de5u4f5cu6d41u6a21%';
  133. UPDATE company_menu SET menu_name = CONVERT(UNHEX('E5B7A5E4BD9CE6B581E689A7E8A18C') USING utf8mb4)
  134. WHERE menu_id = 29949 OR menu_name LIKE 'u5de5u4f5cu6d41u6267%';
  135. UPDATE company_menu SET menu_name = CONVERT(UNHEX('E5AEA2E688B7E794BBE5838F') USING utf8mb4)
  136. WHERE menu_id = 29950 OR menu_name LIKE 'u5ba2u6237u753b%';`;
  137. }
  138. function buildTenantSql() {
  139. return `-- Tenant DB: lobster garbled text repair (auto-generated)
  140. -- Run via Flyway or: mysql -u... tenant_db < this file
  141. ${unicodeEscapeMenuFix()}
  142. ${menuRepairBlock('sys_menu')}
  143. ${menuRepairBlock('company_menu')}
  144. ${promptRepairBlock()}
  145. `;
  146. }
  147. function buildMasterSql() {
  148. return `-- Master DB: lobster garbled text repair (auto-generated)
  149. ${unicodeEscapeMenuFix()}
  150. ${menuRepairBlock('sys_menu')}
  151. ${menuRepairBlock('tenant_sys_menu')}
  152. ${menuRepairBlock('tenant_company_menu')}
  153. ${aiSceneBlock()}
  154. `;
  155. }
  156. fs.writeFileSync(tenantOut, buildTenantSql(), 'utf8');
  157. fs.writeFileSync(masterOut, buildMasterSql(), 'utf8');
  158. console.log('Wrote', tenantOut);
  159. console.log('Wrote', masterOut);
  160. console.log('Catalog prompts:', parseCatalog().length);