/** * 从 LobsterEnginePromptCatalog.java 提取 reg(...) 并生成 SQL 初始化脚本。 * 用法: node java/fs-service/scripts/generate-lobster-engine-prompt-sql.js */ const fs = require('fs'); const path = require('path'); const catalogPath = path.join(__dirname, '../src/main/java/com/fs/company/service/workflow/prompt/LobsterEnginePromptCatalog.java'); const guardrailsPath = path.join(__dirname, '../src/main/java/com/fs/company/service/workflow/prompt/LobsterPromptGuardrails.java'); const outPath = path.join(__dirname, '../../sql/lobster_engine_prompt_init.sql'); const src = fs.readFileSync(catalogPath, 'utf8'); const guardrailsSrc = fs.readFileSync(guardrailsPath, 'utf8'); function loadGuardrailConstants() { const map = {}; const re = /public static final String (\w+) = ([\s\S]*?);/g; let m; while ((m = re.exec(guardrailsSrc)) !== null) { try { map[m[1]] = evalConcat(m[2]); } catch (_) { /* skip non-string constants */ } } return map; } const GUARDRAILS = loadGuardrailConstants(); function unescapeJavaString(s) { return s .replace(/\\n/g, '\n') .replace(/\\t/g, '\t') .replace(/\\"/g, '"') .replace(/\\\\/g, '\\'); } function evalConcat(expr) { const parts = []; let rest = expr.trim(); while (rest.length > 0) { while (rest.length && /\s/.test(rest[0])) rest = rest.slice(1); if (!rest.length) break; if (rest[0] === '+') { rest = rest.slice(1).trim(); continue; } if (rest[0] === '"') { let j = 1; let buf = ''; while (j < rest.length) { if (rest[j] === '\\' && j + 1 < rest.length) { const esc = rest[j + 1]; if (esc === 'n') buf += '\n'; else if (esc === 't') buf += '\t'; else if (esc === 'r') buf += '\r'; else if (esc === '"') buf += '"'; else if (esc === '\\') buf += '\\'; else buf += esc; j += 2; continue; } if (rest[j] === '"') break; buf += rest[j++]; } parts.push(buf); rest = rest.slice(j + 1).trim(); continue; } if (rest.startsWith('null')) { parts.push(''); rest = rest.slice(4).trim(); continue; } const guardMatch = rest.match(/^LobsterPromptGuardrails\.(\w+)/); if (guardMatch) { parts.push(GUARDRAILS[guardMatch[1]] || ''); rest = rest.slice(guardMatch[0].length).trim(); continue; } throw new Error('Cannot parse expr fragment: ' + rest.slice(0, 60)); } return parts.join(''); } function sqlEscape(s) { if (s == null) return null; return s .replace(/\\/g, '\\\\') .replace(/'/g, "''") .replace(/\n/g, '\\n') .replace(/\r/g, '\\r'); } const regRe = /reg\(\s*"([^"]+)"\s*,\s*"([^"]+)"\s*,\s*"([^"]+)"\s*,\s*([\s\S]*?)\s*,\s*(null|"[^"]*"|LobsterPromptGuardrails\.\w+)\s*,\s*(null|"[^"]*")\s*,\s*(null|"[^"]*")\s*,\s*(?:\+\+o|\d+)\s*\)\s*;/g; const rows = []; let m; while ((m = regRe.exec(src)) !== null) { const [, key, name, category, contentExpr, systemRoleExpr, modelExpr] = m; const content = evalConcat(contentExpr); let systemRole = null; if (systemRoleExpr.startsWith('LobsterPromptGuardrails.')) { const gName = systemRoleExpr.replace('LobsterPromptGuardrails.', ''); systemRole = GUARDRAILS[gName] || null; } else if (systemRoleExpr !== 'null') { systemRole = unescapeJavaString(systemRoleExpr.slice(1, -1)); } const modelName = modelExpr === 'null' ? null : unescapeJavaString(modelExpr.slice(1, -1)); rows.push({ key, name, category, content, systemRole, modelName, sort: rows.length + 1 }); } if (rows.length === 0) { console.error('No prompts parsed from catalog'); process.exit(1); } const lines = []; lines.push('-- 数字员工级提示词初始化(平台默认,company_id=NULL)'); lines.push('-- 生成自 LobsterEnginePromptCatalog,共 ' + rows.length + ' 条'); lines.push('-- 执行: mysql -u用户 -p 数据库名 < lobster_engine_prompt_init.sql'); lines.push('-- 已存在相同 prompt_key 时跳过(不覆盖已编辑内容)'); lines.push(''); for (const r of rows) { const sys = r.systemRole != null ? `'${sqlEscape(r.systemRole)}'` : 'NULL'; const model = r.modelName != null ? `'${sqlEscape(r.modelName)}'` : 'NULL'; lines.push(`INSERT IGNORE INTO lobster_system_prompt (`); lines.push(` prompt_key, prompt_name, prompt_category, prompt_content,`); lines.push(` model_name, system_role, company_id, industry_type, enabled, sort_order, create_by`); lines.push(`) VALUES (`); lines.push(` '${sqlEscape(r.key)}',`); lines.push(` '${sqlEscape(r.name)}',`); lines.push(` '${sqlEscape(r.category)}',`); lines.push(" '" + sqlEscape(r.content) + "',"); lines.push(` ${model},`); lines.push(` ${sys},`); lines.push(` NULL, NULL, 1, ${r.sort}, 'system'`); lines.push(`);`); lines.push(''); } fs.writeFileSync(outPath, lines.join('\n'), 'utf8'); console.log('Wrote ' + rows.length + ' prompts -> ' + outPath);