Files
AIclinicalresearch/backend/scripts/test-prompt-service.ts
HaHafeng 5523ef36ea feat(admin): Complete Phase 3.5.1-3.5.4 Prompt Management System (83%)
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
2026-01-11 21:25:16 +08:00

109 lines
4.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 测试 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());