Summary: - Implement Prompt management infrastructure and core services - Build admin portal frontend with light theme - Integrate CodeMirror 6 editor for non-technical users Phase 3.5.1: Infrastructure Setup - Create capability_schema for Prompt storage - Add prompt_templates and prompt_versions tables - Add prompt:view/edit/debug/publish permissions - Migrate RVW prompts to database (RVW_EDITORIAL, RVW_METHODOLOGY) Phase 3.5.2: PromptService Core - Implement gray preview logic (DRAFT for debuggers, ACTIVE for users) - Module-level debug control (setDebugMode) - Handlebars template rendering - Variable extraction and validation (extractVariables, validateVariables) - Three-level disaster recovery (database -> cache -> hardcoded fallback) Phase 3.5.3: Management API - 8 RESTful endpoints (/api/admin/prompts/*) - Permission control (PROMPT_ENGINEER can edit, SUPER_ADMIN can publish) Phase 3.5.4: Frontend Management UI - Build admin portal architecture (AdminLayout, OrgLayout) - Add route system (/admin/*, /org/*) - Implement PromptListPage (filter, search, debug switch) - Implement PromptEditor (CodeMirror 6 simplified for clinical users) - Implement PromptEditorPage (edit, save, publish, test, version history) Technical Details: - Backend: 6 files, ~2044 lines (prompt.service.ts 596 lines) - Frontend: 9 files, ~1735 lines (PromptEditorPage.tsx 399 lines) - CodeMirror 6: Line numbers, auto-wrap, variable highlight, search, undo/redo - Chinese-friendly: 15px font, 1.8 line-height, system fonts Next Step: Phase 3.5.5 - Integrate RVW module with PromptService Tested: Backend API tests passed (8/8), Frontend pending user testing Status: Ready for Phase 3.5.5 RVW integration
109 lines
4.8 KiB
TypeScript
109 lines
4.8 KiB
TypeScript
/**
|
||
* 测试 PromptService
|
||
*/
|
||
|
||
import { PrismaClient } from '@prisma/client';
|
||
import { getPromptService } from '../src/common/prompt/index.js';
|
||
|
||
const prisma = new PrismaClient();
|
||
|
||
async function main() {
|
||
console.log('🧪 测试 PromptService...\n');
|
||
|
||
const promptService = getPromptService(prisma);
|
||
|
||
// 1. 测试获取 ACTIVE Prompt
|
||
console.log('═══════════════════════════════════════════════════════');
|
||
console.log('📋 Test 1: 获取 ACTIVE Prompt (RVW_EDITORIAL)\n');
|
||
|
||
const editorial = await promptService.get('RVW_EDITORIAL');
|
||
console.log(` 版本: v${editorial.version}`);
|
||
console.log(` 是否草稿: ${editorial.isDraft}`);
|
||
console.log(` 模型配置: ${JSON.stringify(editorial.modelConfig)}`);
|
||
console.log(` 内容长度: ${editorial.content.length} 字符`);
|
||
console.log(` 内容预览: ${editorial.content.substring(0, 100)}...`);
|
||
|
||
// 2. 测试变量提取
|
||
console.log('\n═══════════════════════════════════════════════════════');
|
||
console.log('📋 Test 2: 变量提取\n');
|
||
|
||
const template = '请评估以下稿件:{{title}}\n作者:{{author}}\n{{#if abstract}}摘要:{{abstract}}{{/if}}';
|
||
const variables = promptService.extractVariables(template);
|
||
console.log(` 模板: ${template}`);
|
||
console.log(` 提取的变量: [${variables.join(', ')}]`);
|
||
|
||
// 3. 测试变量校验
|
||
console.log('\n═══════════════════════════════════════════════════════');
|
||
console.log('📋 Test 3: 变量校验\n');
|
||
|
||
const validation = promptService.validateVariables(template, { title: '测试标题' });
|
||
console.log(` 有效: ${validation.isValid}`);
|
||
console.log(` 缺失变量: [${validation.missingVariables.join(', ')}]`);
|
||
console.log(` 多余变量: [${validation.extraVariables.join(', ')}]`);
|
||
|
||
// 4. 测试模板渲染
|
||
console.log('\n═══════════════════════════════════════════════════════');
|
||
console.log('📋 Test 4: 模板渲染\n');
|
||
|
||
const rendered = promptService.render(template, {
|
||
title: '测试论文标题',
|
||
author: '张三',
|
||
abstract: '这是摘要内容',
|
||
});
|
||
console.log(` 渲染结果:\n${rendered}`);
|
||
|
||
// 5. 测试调试模式
|
||
console.log('\n═══════════════════════════════════════════════════════');
|
||
console.log('📋 Test 5: 调试模式\n');
|
||
|
||
const testUserId = 'test-user-123';
|
||
|
||
console.log(` 设置调试模式: userId=${testUserId}, modules=[RVW]`);
|
||
promptService.setDebugMode(testUserId, ['RVW'], true);
|
||
|
||
const isDebugging = promptService.isDebugging(testUserId, 'RVW_EDITORIAL');
|
||
console.log(` 是否在调试 RVW_EDITORIAL: ${isDebugging}`);
|
||
|
||
const isDebuggingASL = promptService.isDebugging(testUserId, 'ASL_SCREENING');
|
||
console.log(` 是否在调试 ASL_SCREENING: ${isDebuggingASL}`);
|
||
|
||
const debugState = promptService.getDebugState(testUserId);
|
||
console.log(` 调试状态: modules=[${Array.from(debugState?.modules || []).join(', ')}]`);
|
||
|
||
console.log(` 关闭调试模式`);
|
||
promptService.setDebugMode(testUserId, [], false);
|
||
|
||
// 6. 测试列表模板
|
||
console.log('\n═══════════════════════════════════════════════════════');
|
||
console.log('📋 Test 6: 列表所有模板\n');
|
||
|
||
const templates = await promptService.listTemplates();
|
||
console.log(` 共 ${templates.length} 个模板:`);
|
||
for (const t of templates) {
|
||
const latest = t.versions[0];
|
||
console.log(` - ${t.code} (${t.name}) - v${latest?.version || 0} ${latest?.status || 'N/A'}`);
|
||
}
|
||
|
||
// 7. 测试兜底 Prompt
|
||
console.log('\n═══════════════════════════════════════════════════════');
|
||
console.log('📋 Test 7: 兜底 Prompt\n');
|
||
|
||
try {
|
||
// 测试不存在且无兜底的 Prompt(应该抛错)
|
||
await promptService.get('NON_EXISTENT_CODE');
|
||
console.log(' ❌ 应该抛出错误但没有');
|
||
} catch (e) {
|
||
console.log(' ✅ 正确抛出错误:不存在的Prompt且无兜底');
|
||
}
|
||
|
||
// 测试有兜底的 ASL_SCREENING (虽然DB里有,但演示兜底机制)
|
||
console.log(' 兜底Prompt列表: RVW_EDITORIAL, RVW_METHODOLOGY, ASL_SCREENING');
|
||
|
||
console.log('\n✅ 所有测试完成!');
|
||
}
|
||
|
||
main()
|
||
.catch(console.error)
|
||
.finally(() => prisma.$disconnect());
|
||
|