From ce1a17b4f29ded697f7e1d73a05b9587e1da00fe Mon Sep 17 00:00:00 2001 From: Developer Date: Tue, 9 Jun 2026 16:26:19 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E6=B8=85=E7=90=86=E5=86=97=E4=BD=99?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=95=B0=E6=8D=AE=EF=BC=88server/scripts=20+?= =?UTF-8?q?=20QA=E8=84=9A=E6=9C=AC=20+=20=E6=88=AA=E5=9B=BE=20+=20e2e?= =?UTF-8?q?=E4=BA=A7=E7=89=A9=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/scripts/batch-add-questions.cjs | 147 ------- server/scripts/check_db_v2.js | 11 - server/scripts/check_models.js | 12 - server/scripts/check_schema.js | 12 - server/scripts/debug_es.js | 47 -- server/scripts/pdf_to_images.py | 60 --- server/scripts/reset-admin.mjs | 24 -- server/scripts/seed-ide-questions.js | 476 --------------------- server/scripts/test-error-handling.d.ts | 2 - server/scripts/test-error-handling.js | 180 -------- server/scripts/test-error-handling.js.map | 1 - server/scripts/test-error-handling.ts | 179 -------- server/scripts/test-local-import.d.ts | 1 - server/scripts/test-local-import.js | 137 ------ server/scripts/test-local-import.js.map | 1 - server/scripts/test-local-import.ts | 126 ------ server/scripts/test-vision-pipeline.d.ts | 2 - server/scripts/test-vision-pipeline.js | 139 ------ server/scripts/test-vision-pipeline.js.map | 1 - server/scripts/test-vision-pipeline.ts | 145 ------- server/scripts/text_to_speech.py | 22 - 21 files changed, 1725 deletions(-) delete mode 100644 server/scripts/batch-add-questions.cjs delete mode 100644 server/scripts/check_db_v2.js delete mode 100644 server/scripts/check_models.js delete mode 100644 server/scripts/check_schema.js delete mode 100644 server/scripts/debug_es.js delete mode 100644 server/scripts/pdf_to_images.py delete mode 100644 server/scripts/reset-admin.mjs delete mode 100644 server/scripts/seed-ide-questions.js delete mode 100644 server/scripts/test-error-handling.d.ts delete mode 100644 server/scripts/test-error-handling.js delete mode 100644 server/scripts/test-error-handling.js.map delete mode 100644 server/scripts/test-error-handling.ts delete mode 100644 server/scripts/test-local-import.d.ts delete mode 100644 server/scripts/test-local-import.js delete mode 100644 server/scripts/test-local-import.js.map delete mode 100644 server/scripts/test-local-import.ts delete mode 100644 server/scripts/test-vision-pipeline.d.ts delete mode 100644 server/scripts/test-vision-pipeline.js delete mode 100644 server/scripts/test-vision-pipeline.js.map delete mode 100644 server/scripts/test-vision-pipeline.ts delete mode 100644 server/scripts/text_to_speech.py diff --git a/server/scripts/batch-add-questions.cjs b/server/scripts/batch-add-questions.cjs deleted file mode 100644 index b3e3ad0..0000000 --- a/server/scripts/batch-add-questions.cjs +++ /dev/null @@ -1,147 +0,0 @@ -const D = require('better-sqlite3'), p = require('path'); -const db = new D(p.join(__dirname, '../data/metadata.db')); -const { randomUUID } = require('crypto'); -const BANK = '984632e0-b35d-486d-9a19-27a14845db37'; - -const insert = db.prepare(`INSERT INTO question_bank_items (id, bank_id, question_text, questionType, options, correctAnswer, key_points, difficulty, dimension, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, 'STANDARD', ?, 'PUBLISHED', datetime('now'), datetime('now'))`); - -function sa(q, dim, kp) { - return { questionText: q, questionType: 'SHORT_ANSWER', dimension: dim, options: null, correctAnswer: null, keyPoints: kp }; -} -function mcTF(q, ans, dim) { - return { questionText: q, questionType: 'MULTIPLE_CHOICE', dimension: dim, options: ['TRUE', 'FALSE'], correctAnswer: ans, keyPoints: [] }; -} - -const questions = [ - // ====== IDE题库 ====== - // 一、GitHub Copilot — 智能代码补全 - mcTF('看到 Copilot 给出的灰色补全建议后,按 Tab 键可以接受建议。', 'TRUE', 'IDE'), - mcTF('看到 Copilot 给出的补全建议后,按 Esc 键可以拒绝这个建议。', 'TRUE', 'IDE'), - mcTF('写函数开头后,Copilot 会自动逐行补全后续逻辑。', 'TRUE', 'IDE'), - sa('小张用Copilot智能补全生成了一段代码,看起来功能正常。在正式使用这段代码前,他应该先做什么?', 'IDE', ['审查代码逻辑', '确认没有语法错误或逻辑漏洞', 'AI生成的代码需要人工审核']), - - // 二、GitHub Copilot — Chat 三种模式 - sa('小张接手了一个老项目,打开OrderService.java发现有段逻辑看不太懂。他应该用Copilot Chat的哪种模式(Ask/Plan/Agent)?', 'IDE', ['Ask模式', 'Ask只回答问题不修改代码']), - sa('小李需要在三个文件中新增一个批量删除用户的功能,希望AI直接帮他完成。应该用Copilot Chat的哪种模式?', 'IDE', ['Agent模式', 'Agent可以自动跨文件修改代码']), - sa('小赵想在项目中新增一个功能,但不知道涉及哪些文件,想让AI先扫描整个项目给出方案。应该用哪种模式?', 'IDE', ['Plan模式', 'Plan只出方案不动代码']), - mcTF('Ask模式下Copilot只会回答问题,不会修改用户的代码。', 'TRUE', 'IDE'), - mcTF('Agent模式下Copilot可以跨多个文件修改代码。', 'TRUE', 'IDE'), - - // 三、GitHub Copilot — CLI 使用 - sa('小刘想用Copilot CLI重构一个Python脚本,过程中要多次对话逐步调优。应该用交互模式还是非交互模式?', 'IDE', ['交互模式', '交互模式支持多轮对话']), - sa('小钱想用Copilot CLI快速解释一下git diff的结果,不想进入交互式对话。应该用哪种方式?', 'IDE', ['非交互模式', 'copilot -p指令适合一次性任务']), - sa('小赵在Copilot CLI交互模式中,想清空当前对话上下文重新开始。应该用哪个命令?', 'IDE', ['/clear命令']), - - // 四、Claude Code — 交互方式 - mcTF('在Claude Code中输入@src/utils.js可以让AI读取该文件。', 'TRUE', 'IDE'), - mcTF('在Claude Code中输入/clear可以清空当前对话。', 'TRUE', 'IDE'), - mcTF('在Claude Code中输入!git status可以查看Git状态。', 'TRUE', 'IDE'), - mcTF('在Claude Code中所有操作都必须用特殊符号,自然语言输入不能完成任何功能。', 'FALSE', 'IDE'), - mcTF('在Claude Code中输入!npm run dev可以启动开发服务器。', 'TRUE', 'IDE'), - mcTF('在Claude Code中输入/help可以查看所有可用命令。', 'TRUE', 'IDE'), - - // 五、Claude Code — 模型选择 - sa('Claude Code的三个模型:Sonnet(日常编码)、Haiku(快速简单)、Opus(复杂难题)。修复复杂系统架构Bug该用哪个?', 'IDE', ['Opus', 'Opus处理最复杂的难题']), - sa('日常CRUD接口开发该用Claude Code的哪个模型?', 'IDE', ['Sonnet', 'Sonnet是日常编码首选']), - sa('快速查一下某个JavaScript数组方法的语法,该用Claude Code的哪个模型?', 'IDE', ['Haiku', 'Haiku响应快成本低']), - - // 六、Claude Code — CLI 命令 - sa('小赵的Claude Code会话意外关闭了,想接着刚才的对话继续。该用哪个命令?', 'IDE', ['claude --continue', '或claude -c恢复上次会话']), - sa('小钱想用Claude Code快速解释git diff结果,不想进入交互式对话。该用哪个命令?', 'IDE', ['claude -p指令', '-p参数用于一次性任务']), - mcTF('claude --resume可以从历史会话列表中选择恢复。', 'TRUE', 'IDE'), - - // 七、OpenCode — 整体认知 - mcTF('OpenCode可以直接读取项目文件、修改代码、执行命令。', 'TRUE', 'IDE'), - mcTF('传统AI像远程顾问给你建议但需要你动手;OpenCode可以直接帮你操作。', 'TRUE', 'IDE'), - sa('小周想用OpenCode读取包含客户个人信息的代码文件让AI优化。这种做法合适吗?为什么?', 'IDE', ['不合适', '客户信息是敏感数据不能输入公共AI', '应先脱敏处理']), - - // 八、OpenCode — 安装与使用方式 - sa('OpenCode有终端版/桌面应用/IDE扩展/Web版四种方式。新手不想用命令行的该选哪个?', 'IDE', ['桌面应用', '界面直观适合新手']), - sa('用VS Code写代码希望不离开编辑器用OpenCode该选哪种?', 'IDE', ['IDE扩展', '深度绑定编辑器']), - sa('需要在远程服务器上开发只能通过命令行操作该选哪种?', 'IDE', ['终端版', '轻量启动快适合有基础的用户']), - mcTF('在终端中输入opencode可以启动OpenCode。', 'TRUE', 'IDE'), - - // 九、OpenCode — Plan/Build 模式 - sa('小周接手新项目想先让OpenCode分析结构,还不想修改任何文件。该选Plan还是Build?', 'IDE', ['Plan模式', 'Plan只能读取文件不会修改代码']), - sa('小周确认了修改方案想让OpenCode开始实际修改代码。该选Plan还是Build?', 'IDE', ['Build模式', 'Build可以编辑文件和执行命令']), - mcTF('Plan模式下AI只能读取文件,不会修改任何代码。', 'TRUE', 'IDE'), - mcTF('Build模式下AI可以编辑文件和执行命令。', 'TRUE', 'IDE'), - sa('小周让OpenCode在Build模式下修改了多个文件。修改完成后他应该先做什么?', 'IDE', ['审查AI修改的代码', '确认逻辑正确后再使用', 'AI代码不能直接部署到生产']), - - // 十、OpenCode — 常用命令 - sa('小周用OpenCode修改代码后发现改错了想撤销。该用哪个命令?', 'IDE', ['/undo']), - sa('小周撤销后又觉得还是刚才改得好想恢复回来。该用哪个命令?', 'IDE', ['/redo']), - sa('小周想在新项目目录中创建AGENTS.md让OpenCode了解项目结构。该用哪个命令?', 'IDE', ['/init']), - sa('小周想看看OpenCode当前有哪些可用的斜杠命令和快捷键。该用哪个命令?', 'IDE', ['/help']), - sa('小周想切换OpenCode正在使用的AI模型。该用哪个命令?', 'IDE', ['/models']), - - // 十一、OpenCode — 模型选择 - mcTF('OpenCode内置多款免费模型,启动后可直接选择使用,无需配置API密钥。', 'TRUE', 'IDE'), - mcTF('使用第三方LLM提供商需要自行承担API费用。', 'TRUE', 'IDE'), - - // 十二、Debug — 调试助手 - sa('小吴代码报错了不知道问题在哪,想用Copilot Chat定位和解决Bug。该用哪个命令?', 'IDE', ['/debug', '专用于定位和解决Bug']), - sa('小吴知道问题在哪了,想让Copilot直接修复选中的代码。该用哪个命令?', 'IDE', ['/fix', '用于自动修复代码问题']), - mcTF('在Copilot Chat中输入/tests可以生成选中代码的单元测试。', 'TRUE', 'IDE'), - mcTF('在Copilot Chat中输入/explain可以让AI解释选中代码的逻辑。', 'TRUE', 'IDE'), - mcTF('/debug命令可以帮助定位和解决Bug。', 'TRUE', 'IDE'), - sa('小吴用/fix让Copilot自动修复了代码。修复完成后他应该先做什么?', 'IDE', ['审查修复后的代码', '确认修改正确逻辑无误后再使用']), - sa('小吴想把包含数据库连接串的配置文件贴到Copilot Chat中用/debug分析。这种做法合适吗?', 'IDE', ['不合适', '数据库连接串是敏感信息', '应该用脱敏数据替代']), - - // ====== PROMPT补全 ====== - // 基于提示词工程.md - sa('小王用AI写邮件时只写了"写一封邮件给客户",AI反复追问细节。他在Prompt中缺少哪些要素?', 'PROMPT', ['缺少角色、背景和执行要求', '好的Prompt应包含六要素']), - mcTF('Prompt越长越详细越好,不存在过长的问题。', 'FALSE', 'PROMPT'), - sa('小李在Prompt中用了"非常好""很专业"这类模糊描述,AI的输出总是不符合预期。问题出在哪?', 'PROMPT', ['模糊描述导致AI理解偏差', '应使用具体可量化的要求', '如字数限制/格式要求/示例参考']), - sa('小赵写了一篇很长的Prompt,但AI只关注了前半部分。这是什么原因?', 'PROMPT', ['上下文压缩', '长Prompt中尾部信息可能被忽略', '关键要求应放在Prompt开头']), - sa('小张在Prompt中写了"不要使用过期API",但AI还是用了。问题可能出在哪?', 'PROMPT', ['否定指令容易被AI忽略', '应正面表述要做什么', '改为"使用最新稳定版API"']), - mcTF('给AI设定角色身份可以帮助AI更准确地理解任务。', 'TRUE', 'PROMPT'), - sa('小刘想让AI输出表格数据,但AI每次格式都不一样。他应该在Prompt中加什么?', 'PROMPT', ['明确指定输出格式', '给出表格示例', '使用输出格式约束']), - sa('小陈和AI对话了10轮后发现AI开始偏离最初的任务。这是为什么?怎么避免?', 'PROMPT', ['长对话中AI会模糊最初目标', '定期重申核心任务', '必要时开新窗口重写Prompt']), - mcTF('发现AI偏离任务时,最好的做法是在当前对话中纠正它。', 'FALSE', 'PROMPT'), - sa('小周想让AI修改一段代码,但AI只能看到当前对话的内容。他应该怎么做才能让AI充分理解项目背景?', 'PROMPT', ['提供项目相关上下文', '描述代码所在模块的功能', '给出完整的需求说明']), - sa('小吴的Prompt总是很长,他发现AI回复质量随着Prompt长度增加而下降。最可能的原因是什么?', 'PROMPT', ['上下文窗口有限', '过长信息会被压缩或丢弃', '应精简Prompt保留关键信息']), - mcTF('在Prompt中使用分隔符(如===、---)可以帮助AI更好地理解结构。', 'TRUE', 'PROMPT'), - - // ====== LLM补全 ====== - // 基于大语言模型入门.md + AI安全使用指南.md - sa('小赵让AI分析公司年度财报,AI给出了详细的分析报告。有什么安全问题需要注意?', 'LLM', ['财报属于公司机密', '不应输入公共AI工具', '应使用脱敏后的模拟数据']), - mcTF('AI的工作原理是根据上文猜下文,不是查资料找答案。', 'TRUE', 'LLM'), - sa('小孙问AI一个关于最新API的问题,AI回答得很详细但用的API版本已经过时了。为什么?', 'LLM', ['AI的知识截止于训练日期', '不知道训练后发生的新事件', '应提供最新的API文档给AI']), - sa('小李让AI同一道题回答了三遍,每次答案都不一样。这是正常的吗?为什么?', 'LLM', ['正常', 'AI是概率模型每次生成有随机性', '设置低temperature可让输出更稳定']), - mcTF('AI的输出完全正确可靠,不需要人工验证。', 'FALSE', 'LLM'), - sa('小钱让AI生成了一份产品需求文档,AI写得很专业但引用了一些不存在的市场数据。这是什么问题?', 'LLM', ['AI产生了幻觉', 'AI会编造看似合理但不存在的內容', '应要求AI只基于提供的数据回答']), - sa('小周把客户数据库导出为CSV后上传给AI让它做数据分析。这个做法有什么风险?', 'LLM', ['客户数据不能输入公共AI', '可能造成数据泄露', '应使用脱敏数据']), - mcTF('AI的"幻觉"是指AI会编造看似合理但实际错误的内容。', 'TRUE', 'LLM'), - sa('小吴让AI翻译一份合同,AI翻译得很好但保留了原文中的客户签名信息。这有什么问题?', 'LLM', ['签名信息属于敏感数据', '不应输入公共AI工具', '应在输入前先脱敏']), - sa('小郑想让AI基于公司内部培训材料出一份试题。但培训材料中包含未公开的产品计划。能直接把材料给AI吗?', 'LLM', ['不能', '未公开的产品计划属于公司机密', '应使用虚拟场景代替']), - mcTF('AI训练数据的截止日期意味着AI不知道之后发生的事件。', 'TRUE', 'LLM'), - - // ====== DEV_PATTERN补全 ====== - // 基于开发范式与个人实践指南.md - sa('小王用AI快速写完了一个功能,比预期快了3天。他应该把这3天用在做什么?', 'DEV_PATTERN', ['做更充分的测试', '审查AI代码质量', '优化代码结构']), - mcTF('AI时代开发速度加快,质量保证流程也可以相应省略。', 'FALSE', 'DEV_PATTERN'), - sa('小李的同事说"既然有AI写代码了,测试就不用写了吧"。你怎么回应?', 'DEV_PATTERN', ['AI时代测试更重要', 'AI生成代码更需要测试验证', '测试是保证质量的最后防线']), - sa('小赵在瀑布式项目中用AI辅助开发,发现AI优化了原有设计。他能直接按AI的方案改吗?', 'DEV_PATTERN', ['不能直接改', '瀑布模式不鼓励中途变更方案', '应走正式变更流程']), - mcTF('AI辅助开发中,花时间明确需求比直接让AI写代码更高效。', 'TRUE', 'DEV_PATTERN'), - sa('小张用AI生成了核心功能的代码并合入了主分支。他的做法有什么问题?', 'DEV_PATTERN', ['AI代码应经审查后再合入', '直接合入可能引入质量问题', '应建立AI代码审查流程']), - sa('团队引入AI后,项目经理说交付周期可以缩短一半。你认同吗?', 'DEV_PATTERN', ['AI能提高效率但不能简单减半', '审查测试等流程不能省略', 'AI更适合辅助而不是替代']), - mcTF('使用AI辅助开发时,开发者对最终代码质量仍然负有全部责任。', 'TRUE', 'DEV_PATTERN'), - sa('小刘用AI生成了原型代码拿去给客户演示,客户很满意要求直接部署上线。小刘应该怎么做?', 'DEV_PATTERN', ['原型代码不能直接部署', '需要整理代码通过质量检查', '补充测试和文档后再上线']), - sa('小陈用AI探索一种新的技术方案,不确定能否成功。在瀑布模式下这么做有什么风险?', 'DEV_PATTERN', ['瀑布模式变更成本高', '探索性做法适合敏捷开发', '应在调研阶段验证而非开发阶段']), - mcTF('用AI写的代码,出了问题责任在AI工具公司。', 'FALSE', 'DEV_PATTERN'), -]; - -let ok = 0; -for (const q of questions) { - const id = randomUUID(); - try { - insert.run(id, BANK, q.questionText, q.questionType, q.options ? JSON.stringify(q.options) : null, q.correctAnswer || null, JSON.stringify(q.keyPoints || []), q.dimension); - ok++; - } catch (e) { console.log('FAIL:', e.message.substring(0, 60)); } -} -const r = db.prepare("SELECT dimension, questionType, COUNT(*) c FROM question_bank_items WHERE bank_id=? GROUP BY dimension, questionType ORDER BY dimension, questionType").all(BANK); -const t = db.prepare("SELECT COUNT(*) c FROM question_bank_items WHERE bank_id=?").get(BANK); -console.log('Added:', ok, 'Total:', t.c); -r.forEach(i => console.log(' ' + i.dimension + ' ' + i.questionType + ': ' + i.c)); -db.close(); diff --git a/server/scripts/check_db_v2.js b/server/scripts/check_db_v2.js deleted file mode 100644 index 11edd26..0000000 --- a/server/scripts/check_db_v2.js +++ /dev/null @@ -1,11 +0,0 @@ -const sqlite3 = require('better-sqlite3'); -const db = new sqlite3('server/data/metadata.db'); -try { - const results = db.prepare("SELECT * FROM model_configs WHERE modelId = 'text-embedding-v4'").all(); - console.log('Results for text-embedding-v4:', JSON.stringify(results, null, 2)); - - const count = db.prepare("SELECT COUNT(*) as cnt FROM model_configs").get(); - console.log('Total model configs:', count.cnt); -} catch (e) { - console.error(e.message); -} diff --git a/server/scripts/check_models.js b/server/scripts/check_models.js deleted file mode 100644 index eaffdac..0000000 --- a/server/scripts/check_models.js +++ /dev/null @@ -1,12 +0,0 @@ -const Database = require('better-sqlite3'); -const fs = require('fs'); -const db = new Database('./data/metadata.db'); - -try { - const rows = db.prepare("SELECT id, name, modelId, type, tenant_id FROM model_configs").all(); - fs.writeFileSync('models_list.json', JSON.stringify(rows, null, 2)); -} catch (err) { - console.error(err); -} finally { - db.close(); -} diff --git a/server/scripts/check_schema.js b/server/scripts/check_schema.js deleted file mode 100644 index 5bf5cf4..0000000 --- a/server/scripts/check_schema.js +++ /dev/null @@ -1,12 +0,0 @@ -const sqlite3 = require('better-sqlite3'); -const db = new sqlite3('./data/metadata.db'); - -const tableInfo = db.prepare("PRAGMA table_info(model_configs)").all(); -console.log("Table info for model_configs:"); -console.log(JSON.stringify(tableInfo, null, 2)); - -const sample = db.prepare("SELECT * FROM model_configs LIMIT 5").all(); -console.log("Sample data:"); -console.log(JSON.stringify(sample, null, 2)); - -db.close(); diff --git a/server/scripts/debug_es.js b/server/scripts/debug_es.js deleted file mode 100644 index 397f6ed..0000000 --- a/server/scripts/debug_es.js +++ /dev/null @@ -1,47 +0,0 @@ -const { Client } = require('@elastic/elasticsearch'); - -async function run() { - const client = new Client({ - node: 'http://127.0.0.1:9200', - }); - - try { - const indexName = 'knowledge_base'; - - console.log(`\n--- Total Documents ---`); - const count = await client.count({ index: indexName }); - console.log(count); - - console.log(`\n--- Document Distribution by tenantId ---`); - const distribution = await client.search({ - index: indexName, - size: 0, - aggs: { - by_tenant: { - terms: { field: 'tenantId', size: 100, missing: 'N/A' } - } - } - }); - console.log(JSON.stringify(distribution.aggregations.by_tenant.buckets, null, 2)); - - console.log(`\n--- Sample Documents (last 5) ---`); - const samples = await client.search({ - index: indexName, - size: 5, - sort: [{ createdAt: 'desc' }], - }); - console.log(JSON.stringify(samples.hits.hits.map(h => ({ - id: h._id, - tenantId: h._source.tenantId, - fileName: h._source.fileName, - vectorLength: h._source.vector?.length, - vectorPreview: h._source.vector?.slice(0, 5), - contentPreview: h._source.content?.substring(0, 50) - })), null, 2)); - - } catch (error) { - console.error('Error:', error.meta?.body || error.message); - } -} - -run(); diff --git a/server/scripts/pdf_to_images.py b/server/scripts/pdf_to_images.py deleted file mode 100644 index c129bfc..0000000 --- a/server/scripts/pdf_to_images.py +++ /dev/null @@ -1,60 +0,0 @@ -import fitz # PyMuPDF -import sys -import os -import json - -def convert_pdf_to_images(pdf_path, output_dir, zoom=2.0, quality=85): - """ - Converts PDF pages to images. - zoom: 2.0 means 200% scaling (approx 144 DPI if original is 72 DPI) - """ - try: - if not os.path.exists(output_dir): - os.makedirs(output_dir) - - doc = fitz.open(pdf_path) - images = [] - - # Matrix for scaling (DPI control) - mat = fitz.Matrix(zoom, zoom) - - for i in range(len(doc)): - page = doc.load_page(i) - pix = page.get_pixmap(matrix=mat, colorspace=fitz.csRGB) - - output_path = os.path.join(output_dir, f"page-{i+1}.jpg") - # In newer PyMuPDF, save() doesn't take quality. Use tobytes instead. - img_bytes = pix.tobytes("jpg", jpg_quality=quality) - with open(output_path, "wb") as f: - f.write(img_bytes) - - images.append({ - "path": output_path, - "pageIndex": i + 1, - "size": os.path.getsize(output_path) - }) - - doc.close() - return { - "success": True, - "images": images, - "totalPages": len(images) - } - except Exception as e: - return { - "success": False, - "error": str(e) - } - -if __name__ == "__main__": - if len(sys.argv) < 3: - print(json.dumps({"success": False, "error": "Usage: python pdf_to_images.py [zoom] [quality]"})) - sys.exit(1) - - pdf_path = sys.argv[1] - output_dir = sys.argv[2] - zoom = float(sys.argv[3]) if len(sys.argv) > 3 else 2.0 - quality = int(sys.argv[4]) if len(sys.argv) > 4 else 85 - - result = convert_pdf_to_images(pdf_path, output_dir, zoom, quality) - print(json.dumps(result)) diff --git a/server/scripts/reset-admin.mjs b/server/scripts/reset-admin.mjs deleted file mode 100644 index d3bfbbf..0000000 --- a/server/scripts/reset-admin.mjs +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Quick script to reset the admin user password for E2E testing. - * Usage: node reset-admin.mjs - */ -import Database from 'better-sqlite3'; -import bcrypt from 'bcrypt'; -import { fileURLToPath } from 'url'; -import path from 'path'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const DB_PATH = path.resolve(__dirname, '../data/metadata.db'); -const newPassword = process.argv[2] || 'Admin@2026'; - -const db = new Database(DB_PATH); - -const hashed = await bcrypt.hash(newPassword, 10); -const result = db.prepare("UPDATE users SET password = ? WHERE username = 'admin'").run(hashed); - -if (result.changes > 0) { - console.log(`✅ Admin password reset to: ${newPassword}`); -} else { - console.log('❌ Admin user not found'); -} -db.close(); diff --git a/server/scripts/seed-ide-questions.js b/server/scripts/seed-ide-questions.js deleted file mode 100644 index 900f534..0000000 --- a/server/scripts/seed-ide-questions.js +++ /dev/null @@ -1,476 +0,0 @@ -/** - * IDE 协作开发题库 — 种子脚本 - * 运行方式:cd D:/AuraK/server && node scripts/seed-ide-questions.js - */ -const { DatabaseSync } = require('node:sqlite'); -const crypto = require('crypto'); -const path = require('path'); - -const DB_PATH = path.join(__dirname, '..', 'data', 'metadata.db'); -const BANK_ID = crypto.randomUUID(); -const TENANT_ID = 'a140a68e-f70a-44d3-b753-fa33d48cf234'; // 现有tenant -const ADMIN_USER_ID = '1cf8ba6d-d184-4055-ab58-99c6f38bbf93'; // admin用户 - -const db = new DatabaseSync(DB_PATH); - -function uuid() { - return crypto.randomUUID(); -} - -function now() { - return new Date().toISOString().replace('T', ' ').substring(0, 22) + '000'; -} - -const ts = now(); - -// ===== 创建题库 ===== -console.log('Creating IDE question bank...'); -db.prepare(` - INSERT INTO question_banks (id, tenant_id, template_id, name, description, status, created_by, reviewed_by, reviewed_at, review_comment, created_at, updated_at) - VALUES (?, ?, NULL, ?, ?, 'PUBLISHED', ?, ?, ?, ?, ?, ?) -`).run(BANK_ID, TENANT_ID, 'IDE协作开发题库', 'L1课程四:IDE协作开发考核题库,包含Copilot、Claude Code、OpenCode三种工具的50道题目', ADMIN_USER_ID, ADMIN_USER_ID, ts, 'approve', ts, ts); - -// ===== 生成题目 ===== -const items = []; - -function addItem(questionText, questionType, options, correctAnswer, keyPoints, difficulty, dimension, basis, judgment) { - items.push({ - questionText, - questionType, - options: options ? JSON.stringify(options) : null, - correctAnswer, - keyPoints: JSON.stringify(keyPoints), - difficulty: difficulty || 'STANDARD', - dimension: dimension || 'IDE', - basis: basis || null, - judgment: judgment || null, - }); -} - -// ================================================ -// 一、GitHub Copilot — 智能代码补全(4题) -// ================================================ - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n看到 Copilot 给出的灰色补全建议后,按 Tab 键可以接受建议。', - 'TRUE_FALSE', null, '✓', - ['Tab键接受补全建议', 'Copilot基础操作'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n看到 Copilot 给出的补全建议后,按 Esc 键可以拒绝这个建议。', - 'TRUE_FALSE', null, '✓', - ['Esc键拒绝补全建议', 'Copilot基础操作'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n写函数开头后,Copilot 会自动逐行补全后续逻辑。', - 'TRUE_FALSE', null, '✓', - ['Copilot智能补全功能', '注释驱动代码生成'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章' -); - -addItem( - '小张用智能补全生成了一段代码,看起来功能正常。\n\n问:在正式使用这段代码前,他应该先做什么?', - 'SHORT_ANSWER', null, '审查代码逻辑,确认没有语法错误或逻辑漏洞后再使用。AI 生成的代码需要人工审核。', - ['人工审核AI生成代码', '代码审查', '不直接使用AI生成的代码'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 红线警告' -); - -// ================================================ -// 二、GitHub Copilot — Chat 三种模式(5题) -// ================================================ - -addItem( - '小张接手了一个老项目,打开 OrderService.java 发现有段逻辑看不太懂。他打开 Copilot Chat,想先问问这段代码是干什么的。\n\nCopilot Chat 有以下三种模式:Ask / Plan / Agent\n\n问:小张应该选择哪种模式?', - 'SHORT_ANSWER', null, 'Ask(问答模式)。Ask 模式只回答问题,不修改代码。', - ['Ask模式适用场景', '不修改代码的对话方式'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章 三种对话模式' -); - -addItem( - '小李需要在三个文件中新增一个「批量删除用户」的功能,希望 AI 直接帮他完成代码修改。\n\nCopilot Chat 有以下三种模式:Ask / Plan / Agent\n\n问:小李应该选择哪种模式?', - 'SHORT_ANSWER', null, 'Agent(智能代理模式)。Agent 模式可以自动跨文件修改代码。', - ['Agent模式适用场景', '跨文件修改任务'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章 三种对话模式' -); - -addItem( - '小赵想在项目中新增一个功能,但不知道涉及哪些文件、影响范围多大,想让 AI 先扫描整个项目给出方案。\n\nCopilot Chat 有以下三种模式:Ask / Plan / Agent\n\n问:小赵应该选择哪种模式?', - 'SHORT_ANSWER', null, 'Plan(计划模式)。Plan 模式只出方案不动代码,适合先评估再动手。', - ['Plan模式适用场景', '先规划再执行'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章 三种对话模式' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\nAsk 模式下,Copilot 只会回答问题,不会修改用户的代码。', - 'TRUE_FALSE', null, '✓', - ['Ask模式只回答不修改'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\nAgent 模式下,Copilot 可以跨多个文件修改代码。', - 'TRUE_FALSE', null, '✓', - ['Agent模式跨文件修改'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章' -); - -// ================================================ -// 三、GitHub Copilot — CLI 使用(3题) -// ================================================ - -addItem( - '小刘想用 Copilot CLI 重构一个 Python 脚本,过程中要多次对话、逐步调优。\n\nCopilot CLI 有以下两种使用方式:交互模式(copilot)/ 非交互模式(copilot -p "指令")\n\n问:小刘应该选择哪种方式?', - 'SHORT_ANSWER', null, '交互模式(copilot)。交互模式支持多轮对话,适合需要迭代的复杂任务。', - ['CLI交互模式适用场景', '多轮对话重构'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - CLI 使用' -); - -addItem( - '小钱想用 Copilot CLI 快速解释一下 git diff 的结果,不想进入交互式对话。\n\nCopilot CLI 有以下两种使用方式:交互模式(copilot)/ 非交互模式(copilot -p "指令")\n\n问:小钱应该选择哪种方式?', - 'SHORT_ANSWER', null, '非交互模式(copilot -p "指令")。非交互模式适合一次性任务,快速获得结果后退出。', - ['CLI非交互模式适用场景', '一次性任务'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - CLI使用' -); - -addItem( - '小赵在 Copilot CLI 交互模式中,想清空当前对话上下文重新开始。\n\nCopilot CLI 中常用的斜杠命令有:/clear / /model / /session / /exit\n\n问:小赵应该使用哪个命令?', - 'SHORT_ANSWER', null, '/clear', - ['CLI斜杠命令', '/clear清空对话'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - CLI斜杠命令' -); - -// ================================================ -// 四、Claude Code — 四种交互方式(6题) -// ================================================ - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n在 Claude Code 中输入 @src/utils.js 可以让 AI 读取该文件。', - 'TRUE_FALSE', null, '✓', - ['Claude Code文件引用', '@语法'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 文件引用' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n在 Claude Code 中输入 /clear 可以清空当前对话。', - 'TRUE_FALSE', null, '✓', - ['Claude Code斜杠命令', '/clear清屏'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 斜杠命令' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n在 Claude Code 中输入 !git status 可以查看 Git 状态。', - 'TRUE_FALSE', null, '✓', - ['Claude Code Bash模式', '!语法执行系统命令'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 Bash模式' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n在 Claude Code 中所有操作都必须用特殊符号,自然语言输入不能完成任何功能。', - 'TRUE_FALSE', null, '✗。自然语言也可以完成大部分功能,特殊符号用于特定场景。', - ['自然语言可用', '特殊符号的定位'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 交互方式' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n在 Claude Code 中输入 !npm run dev 可以启动开发服务器。', - 'TRUE_FALSE', null, '✓', - ['Claude Code Bash模式', '!语法启动开发服务器'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 Bash模式' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n在 Claude Code 中输入 /help 可以查看所有可用命令。', - 'TRUE_FALSE', null, '✓', - ['Claude Code斜杠命令', '/help帮助'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 斜杠命令' -); - -// ================================================ -// 五、Claude Code — 模型选择与切换(3题) -// ================================================ - -addItem( - 'Claude Code 的三个模型特点如下:\n- Sonnet:主力工程师,日常编码首选\n- Haiku:响应极快、成本低,适合简单任务\n- Opus:处理超级复杂的难题,智商最高\n\n小陈需要修复一个非常复杂的系统架构 Bug。\n\n问:他应该选择哪个模型?', - 'SHORT_ANSWER', null, 'Opus', - ['Opus模型适用场景', '复杂难题'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 模型选择' -); - -addItem( - 'Claude Code 的三个模型特点如下:\n- Sonnet:主力工程师,日常编码首选\n- Haiku:响应极快、成本低,适合简单任务\n- Opus:处理超级复杂的难题,智商最高\n\n小陈在做日常的 CRUD 接口开发。\n\n问:他应该选择哪个模型?', - 'SHORT_ANSWER', null, 'Sonnet', - ['Sonnet模型适用场景', '日常编码'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 模型选择' -); - -addItem( - 'Claude Code 的三个模型特点如下:\n- Sonnet:主力工程师,日常编码首选\n- Haiku:响应极快、成本低,适合简单任务\n- Opus:处理超级复杂的难题,智商最高\n\n小陈想快速查一下某个 JavaScript 数组方法的语法。\n\n问:他应该选择哪个模型?', - 'SHORT_ANSWER', null, 'Haiku', - ['Haiku模型适用场景', '快速简单任务'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 模型选择' -); - -// ================================================ -// 六、Claude Code — CLI 命令(3题) -// ================================================ - -addItem( - '小赵的 Claude Code 会话因为终端意外关闭了,想接着刚才的对话继续。\n\nClaude CLI 有以下命令:claude / claude --continue / claude --resume\n\n问:小赵应该用哪个命令?', - 'SHORT_ANSWER', null, 'claude --continue(或 claude -c)。该命令用于恢复上次意外关闭的会话。', - ['恢复会话', '--continue参数'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 CLI命令' -); - -addItem( - '小钱想用 Claude Code 快速解释一下 git diff 的结果,不想进入交互式对话。\n\nClaude CLI 有以下命令:claude / claude -p "指令" / claude --resume\n\n问:小钱应该用哪个命令?', - 'SHORT_ANSWER', null, 'claude -p "指令"。-p 参数用于一次性任务,适合快速执行。', - ['一次性任务', '-p参数'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 CLI命令' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\nclaude --resume 可以从历史会话列表中选择恢复。', - 'TRUE_FALSE', null, '✓', - ['恢复历史会话', '--resume参数'], - 'STANDARD', 'IDE', 'Claude Code 使用指南 - 第3章 CLI命令' -); - -// ================================================ -// 七、OpenCode — 整体认知(3题) -// ================================================ - -addItem( - '以下说法是否正确?(✓ / ✗)\n\nOpenCode 像一位身边的搭档,可以直接读取项目文件、修改代码、执行命令。', - 'TRUE_FALSE', null, '✓', - ['OpenCode核心定位', 'AI编码代理'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第1章 核心定位' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n传统 AI 像远程顾问,给你建议但需要你自己动手;OpenCode 可以直接帮你操作。', - 'TRUE_FALSE', null, '✓', - ['OpenCode与传统AI区别', '直接操作能力'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第1章' -); - -addItem( - '小周想用 OpenCode 读取包含客户个人信息的代码文件,让 AI 帮忙优化。\n\n问:这种做法是否合适?为什么?', - 'SHORT_ANSWER', null, '不合适。客户个人信息属于敏感数据,严禁输入任何公共 AI 工具。应该先对数据进行脱敏处理,用虚构数据或占位符替代后再使用。', - ['安全合规', '敏感数据保护', '数据脱敏'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 红线警告' -); - -// ================================================ -// 八、OpenCode — 安装与使用方式(4题) -// ================================================ - -addItem( - 'OpenCode 有以下四种使用方式:\n- 终端版 — 轻量启动快,适合有基础的用户\n- 桌面应用 — 界面直观,适合新手\n- IDE 扩展 — 深度绑定编辑器\n- Web 版 — 浏览器访问,可远程部署\n\n小周是新手,不喜欢操作命令行,想找一个界面直观的方式。\n\n问:他应该选择哪种方式?', - 'SHORT_ANSWER', null, '桌面应用', - ['OpenCode使用方式选择', '桌面应用适合新手'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第2章 使用方式' -); - -addItem( - 'OpenCode 有以下四种使用方式:终端版 / 桌面应用 / IDE 扩展 / Web 版\n\n小刘平时用 VS Code 写代码,希望不离开编辑器就能用 OpenCode。\n\n问:他应该选择哪种方式?', - 'SHORT_ANSWER', null, 'IDE 扩展', - ['OpenCode IDE扩展', '编辑器集成'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第2章 使用方式' -); - -addItem( - 'OpenCode 有以下四种使用方式:终端版 / 桌面应用 / IDE 扩展 / Web 版\n\n小马需要在远程服务器上开发,只能通过命令行操作。\n\n问:他应该选择哪种方式?', - 'SHORT_ANSWER', null, '终端版', - ['OpenCode终端版', '远程服务器开发'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第2章 使用方式' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n在终端中输入 opencode 可以启动 OpenCode。', - 'TRUE_FALSE', null, '✓', - ['OpenCode启动命令'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第2章 安装' -); - -// ================================================ -// 九、OpenCode — Plan / Build 工作模式(5题) -// ================================================ - -addItem( - '小周接手了一个新项目,想先让 OpenCode 分析项目结构,还不想修改任何文件。\n\nOpenCode 有以下两种工作模式:Plan / Build\n\n问:小周应该选择哪种模式?', - 'SHORT_ANSWER', null, 'Plan(计划模式)。Plan 模式下 AI 只能读取文件,不会修改代码。', - ['Plan模式', '只读分析'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第3章 Plan模式' -); - -addItem( - '小周已经确认了修改方案,想让 OpenCode 开始实际修改代码。\n\nOpenCode 有以下两种工作模式:Plan / Build\n\n问:小周应该选择哪种模式?', - 'SHORT_ANSWER', null, 'Build(构建模式)。Build 模式下 AI 可以编辑文件和执行命令。', - ['Build模式', '实际代码修改'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第3章 Build模式' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\nPlan 模式下 AI 只能读取文件,不会修改任何代码。', - 'TRUE_FALSE', null, '✓', - ['Plan模式只读特性'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第3章' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\nBuild 模式下 AI 可以编辑文件和执行命令。', - 'TRUE_FALSE', null, '✓', - ['Build模式可写特性'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第3章' -); - -addItem( - '小周让 OpenCode 在 Build 模式下修改了多个文件。\n\n问:修改完成后,他应该先做什么?', - 'SHORT_ANSWER', null, '审查 AI 修改的代码,确认逻辑正确后再使用。AI 生成的代码不能直接部署到生产环境。', - ['代码审查', 'AI生成代码需人工审核'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 安全原则' -); - -// ================================================ -// 十、OpenCode — 常用命令(5题) -// ================================================ - -addItem( - '小周用 OpenCode 修改了代码,但发现改错了,想撤销刚才的修改。\n\nOpenCode 中有以下命令:/undo / /redo / /clear / /init\n\n问:他应该使用哪个命令?', - 'SHORT_ANSWER', null, '/undo', - ['OpenCode撤销命令', '/undo'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第3章 撤销更改' -); - -addItem( - '小周撤销了修改后又觉得还是刚才改得好,想恢复回来。\n\nOpenCode 中有以下命令:/undo / /redo / /clear / /init\n\n问:他应该使用哪个命令?', - 'SHORT_ANSWER', null, '/redo', - ['OpenCode重做命令', '/redo'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第3章' -); - -addItem( - '小周想在新项目目录中创建 AGENTS.md 文件,让 OpenCode 了解项目结构。\n\nOpenCode 中有以下命令:/undo / /redo / /clear / /init\n\n问:他应该使用哪个命令?', - 'SHORT_ANSWER', null, '/init', - ['OpenCode初始化', '/init命令'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第4章 项目初始化' -); - -addItem( - '小周想看看 OpenCode 当前有哪些可用的斜杠命令和快捷键。\n\nOpenCode 中有以下命令:/help / /models / /connect / /exit\n\n问:他应该使用哪个命令?', - 'SHORT_ANSWER', null, '/help', - ['OpenCode帮助', '/help命令'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第3章 斜杠命令' -); - -addItem( - '小周想切换 OpenCode 正在使用的 AI 模型。\n\nOpenCode 中有以下命令:/help / /models / /connect / /exit\n\n问:他应该使用哪个命令?', - 'SHORT_ANSWER', null, '/models', - ['OpenCode模型切换', '/models命令'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第3章 模型选择' -); - -// ================================================ -// 十一、OpenCode — 模型选择(2题) -// ================================================ - -addItem( - '以下说法是否正确?(✓ / ✗)\n\nOpenCode 内置多款免费模型,启动后可以直接选择使用,无需配置 API 密钥。', - 'TRUE_FALSE', null, '✓', - ['OpenCode免费模型', '无需API密钥'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第3章 模型' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n使用第三方 LLM 提供商(如 OpenAI、Anthropic)需要自行承担 API 费用。', - 'TRUE_FALSE', null, '✓', - ['第三方LLM费用', 'API成本'], - 'STANDARD', 'IDE', 'OpenCode 使用指南 - 第3章 模型' -); - -// ================================================ -// 十二、Debug — 调试助手(7题) -// ================================================ - -addItem( - '小吴的代码运行时报错了,不知道问题出在哪,想让 Copilot Chat 帮他定位和解决 Bug。\n\nCopilot Chat 中有以下命令:/fix / /tests / /explain / /debug\n\n问:他应该使用哪个命令?', - 'SHORT_ANSWER', null, '/debug。该命令专用于帮助定位和解决 Bug。', - ['/debug命令', '定位解决Bug'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章 内置命令' -); - -addItem( - '小吴已经知道问题在哪了,想让 Copilot 直接修复选中的代码。\n\nCopilot Chat 中有以下命令:/fix / /tests / /explain / /debug\n\n问:他应该使用哪个命令?', - 'SHORT_ANSWER', null, '/fix。该命令用于自动修复代码问题。', - ['/fix命令', '自动修复代码'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章 内置命令' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n在 Copilot Chat 中输入 /tests 可以生成选中代码的单元测试。', - 'TRUE_FALSE', null, '✓', - ['/tests命令', '生成单元测试'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章 内置命令' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n在 Copilot Chat 中输入 /explain 可以让 AI 解释选中代码的逻辑。', - 'TRUE_FALSE', null, '✓', - ['/explain命令', '解释代码逻辑'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章 内置命令' -); - -addItem( - '以下说法是否正确?(✓ / ✗)\n\n/debug 命令可以帮助定位和解决 Bug。', - 'TRUE_FALSE', null, '✓', - ['/debug命令功能'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 第3章 内置命令' -); - -addItem( - '小吴用 /fix 命令让 Copilot 自动修复了代码。\n\n问:修复完成后,他应该先做什么?', - 'SHORT_ANSWER', null, '审查修复后的代码,确认修改正确、逻辑无误后再使用。', - ['代码审查', '修复后验证'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 安全原则' -); - -addItem( - '小吴遇到一个 Bug,想把包含数据库连接串的配置文件贴到 Copilot Chat 中用 /debug 分析。\n\n问:这种做法是否合适?为什么?', - 'SHORT_ANSWER', null, '不合适。数据库连接串属于敏感信息,严禁输入公共 AI 工具。应该用脱敏数据或占位符替代后再进行分析。', - ['安全合规', '敏感数据保护', '脱敏处理'], - 'STANDARD', 'IDE', 'GitHub Copilot 使用指南 - 红线警告' -); - -// ===== 批量插入题目 ===== -console.log(`Inserting ${items.length} questions...`); - -const insertItem = db.prepare(` - INSERT INTO question_bank_items (id, bank_id, question_text, questionType, options, correctAnswer, key_points, difficulty, dimension, basis, judgment, status, created_by, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'PUBLISHED', ?, ?, ?) -`); - -for (const item of items) { - insertItem.run( - uuid(), - BANK_ID, - item.questionText, - item.questionType, - item.options, - item.correctAnswer, - item.keyPoints, - item.difficulty, - item.dimension, - item.basis, - item.judgment, - ADMIN_USER_ID, - ts, - ts - ); -} - -console.log(`Successfully inserted ${items.length} IDE questions into bank ${BANK_ID}`); -db.close(); diff --git a/server/scripts/test-error-handling.d.ts b/server/scripts/test-error-handling.d.ts deleted file mode 100644 index a9578f6..0000000 --- a/server/scripts/test-error-handling.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare function testErrorHandling(): Promise; -export { testErrorHandling }; diff --git a/server/scripts/test-error-handling.js b/server/scripts/test-error-handling.js deleted file mode 100644 index 32b4960..0000000 --- a/server/scripts/test-error-handling.js +++ /dev/null @@ -1,180 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -exports.testErrorHandling = testErrorHandling; -const core_1 = require("@nestjs/core"); -const app_module_1 = require("./src/app.module"); -const knowledge_base_service_1 = require("./src/knowledge-base/knowledge-base.service"); -const libreoffice_service_1 = require("./src/libreoffice/libreoffice.service"); -const pdf2image_service_1 = require("./src/pdf2image/pdf2image.service"); -const vision_pipeline_service_1 = require("./src/vision-pipeline/vision-pipeline.service"); -const fs = __importStar(require("fs/promises")); -const path = __importStar(require("path")); -async function testErrorHandling() { - console.log('🧪 Starting error handling and degradation mechanism tests\n'); - const app = await core_1.NestFactory.createApplicationContext(app_module_1.AppModule, { - logger: ['error', 'warn', 'log'], - }); - try { - console.log('=== Test 1: LibreOffice service unavailable ==='); - const libreOffice = app.get(libreoffice_service_1.LibreOfficeService); - try { - const originalUrl = process.env.LIBREOFFICE_URL; - process.env.LIBREOFFICE_URL = 'http://localhost:9999'; - const testDoc = '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1765705143480-947461268.pdf'; - const testWord = '/tmp/test.docx'; - if (await fs.access(testWord).then(() => true).catch(() => false)) { - try { - await libreOffice.convertToPDF(testWord); - console.log('❌ Should have failed but succeeded'); - } - catch (error) { - console.log(`✅ Correctly caught error: ${error.message}`); - } - } - else { - console.log('⚠️ Test Word file does not exist, skipping this part'); - } - process.env.LIBREOFFICE_URL = originalUrl; - } - catch (error) { - console.log('✅ LibreOffice error handling test complete'); - } - console.log('\n=== Test 2: PDF to Image conversion failed ==='); - const pdf2Image = app.get(pdf2image_service_1.Pdf2ImageService); - try { - await pdf2Image.convertToImages('/nonexistent/file.pdf'); - console.log('❌ Should have failed but succeeded'); - } - catch (error) { - console.log(`✅ Correctly caught error: ${error.message}`); - } - console.log('\n=== Test 3: Vision Pipeline degradation mechanism ==='); - const visionPipeline = app.get(vision_pipeline_service_1.VisionPipelineService); - const testPdf = '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf'; - if (await fs.access(testPdf).then(() => true).catch(() => false)) { - console.log(`Test file: ${path.basename(testPdf)}`); - const recommendation = await visionPipeline.recommendMode(testPdf); - console.log(`Recommended mode: ${recommendation.recommendedMode}`); - console.log(`Reason: ${recommendation.reason}`); - if (recommendation.recommendedMode === 'precise') { - console.log('\n⚠️ Note: Full pipeline testing requires:'); - console.log(' 1. LibreOffice service running'); - console.log(' 2. ImageMagick installed'); - console.log(' 3. Vision model API Key configured'); - console.log('\nTo run full test, please manually configure the above environments'); - } - } - else { - console.log('⚠️ Test files not found'); - } - console.log('\n=== Test 4: KnowledgeBase degradation logic ==='); - const kbService = app.get(knowledge_base_service_1.KnowledgeBaseService); - console.log('Degradation logic check:'); - console.log('✅ Supported formats: PDF, DOC, DOCX, PPT, PPTX'); - console.log('✅ Check Vision model configuration'); - console.log('✅ Auto-degrade to fast mode'); - console.log('✅ Error logging'); - console.log('✅ Temporary file cleanup'); - console.log('\n=== Test 5: Environment configuration validation ==='); - const configService = app.get(require('@nestjs/config').ConfigService); - const checks = [ - { name: 'LIBREOFFICE_URL', required: true }, - { name: 'TEMP_DIR', required: true }, - { name: 'ELASTICSEARCH_HOST', required: true }, - { name: 'TIKA_HOST', required: true }, - { name: 'CHUNK_BATCH_SIZE', required: false }, - ]; - let allPassed = true; - for (const check of checks) { - const value = configService.get(check.name); - const passed = check.required ? !!value : true; - const status = passed ? '✅' : '❌'; - console.log(`${status} ${check.name}: ${value || 'Not configured'}`); - if (!passed) - allPassed = false; - } - if (allPassed) { - console.log('\n🎉 All configuration checks passed!'); - } - else { - console.log('\n⚠️ Please check missing configuration items'); - } - console.log('\n=== Test 6: Temporary file cleanup mechanism ==='); - try { - const tempDir = configService.get('TEMP_DIR', './temp'); - const tempExists = await fs.access(tempDir).then(() => true).catch(() => false); - if (tempExists) { - console.log(`✅ Temporary directory exists: ${tempDir}`); - const files = await fs.readdir(tempDir); - if (files.length > 0) { - console.log(`⚠️ Found ${files.length} temporary files, cleanup recommended`); - } - else { - console.log('✅ Temporary directory is empty'); - } - } - else { - console.log('⚠️ Temporary directory does not exist, will be created on first run'); - } - } - catch (error) { - console.log(`❌ Temporary directory check failed: ${error.message}`); - } - console.log('\n=== Error Handling Test Summary ==='); - console.log('✅ LibreOffice connection error handling'); - console.log('✅ PDF to Image conversion failure handling'); - console.log('✅ Vision model error handling'); - console.log('✅ Auto-degrade to fast mode'); - console.log('✅ Temporary file cleanup'); - console.log('✅ Environment configuration validation'); - console.log('\n💡 Suggestions:'); - console.log(' 1. Add more monitoring in production environment'); - console.log(' 2. Implement user quota limits'); - console.log(' 3. Add processing timeout mechanism'); - console.log(' 4. Regularly clean up temporary files'); - } - catch (error) { - console.error('❌ Test failed:', error.message); - console.error(error.stack); - } - finally { - await app.close(); - } -} -if (require.main === module) { - testErrorHandling().catch(console.error); -} -//# sourceMappingURL=test-error-handling.js.map \ No newline at end of file diff --git a/server/scripts/test-error-handling.js.map b/server/scripts/test-error-handling.js.map deleted file mode 100644 index 5592bee..0000000 --- a/server/scripts/test-error-handling.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"test-error-handling.js","sourceRoot":"","sources":["test-error-handling.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/server/scripts/test-error-handling.ts b/server/scripts/test-error-handling.ts deleted file mode 100644 index 7511450..0000000 --- a/server/scripts/test-error-handling.ts +++ /dev/null @@ -1,179 +0,0 @@ -/** - * Vision Pipeline 错误处理和降级机制测试 - * - * 测试各种错误场景下的系统行为 - */ - -import { NestFactory } from '@nestjs/core'; -import { AppModule } from './src/app.module'; -import { KnowledgeBaseService } from './src/knowledge-base/knowledge-base.service'; -import { LibreOfficeService } from './src/libreoffice/libreoffice.service'; -import { Pdf2ImageService } from './src/pdf2image/pdf2image.service'; -import { VisionPipelineService } from './src/vision-pipeline/vision-pipeline.service'; -import * as fs from 'fs/promises'; -import * as path from 'path'; - -async function testErrorHandling() { - console.log('🧪 Starting error handling and degradation mechanism tests\n'); - - const app = await NestFactory.createApplicationContext(AppModule, { - logger: ['error', 'warn', 'log'], - }); - - try { - // 测试 1: LibreOffice 服务不可用 - console.log('=== Test 1: LibreOffice service unavailable ==='); - const libreOffice = app.get(LibreOfficeService); - - try { - // 模拟服务不可用 - const originalUrl = process.env.LIBREOFFICE_URL; - process.env.LIBREOFFICE_URL = 'http://localhost:9999'; // 错误的地址 - - const testDoc = '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1765705143480-947461268.pdf'; - - // 尝试转换非 PDF 文件(需要 LibreOffice) - const testWord = '/tmp/test.docx'; // 假设存在 - if (await fs.access(testWord).then(() => true).catch(() => false)) { - try { - await libreOffice.convertToPDF(testWord); - console.log('❌ Should have failed but succeeded'); - } catch (error) { - console.log(`✅ Correctly caught error: ${error.message}`); - } - } else { - console.log('⚠️ Test Word file does not exist, skipping this part'); - } - - // 恢复配置 - process.env.LIBREOFFICE_URL = originalUrl; - } catch (error) { - console.log('✅ LibreOffice error handling test complete'); - } - - // 测试 2: PDF 转图片失败 - console.log('\n=== Test 2: PDF to Image conversion failed ==='); - const pdf2Image = app.get(Pdf2ImageService); - - try { - // 测试不存在的 PDF - await pdf2Image.convertToImages('/nonexistent/file.pdf'); - console.log('❌ Should have failed but succeeded'); - } catch (error) { - console.log(`✅ Correctly caught error: ${error.message}`); - } - - // 测试 3: Vision Pipeline 完整流程 - 降级测试 - console.log('\n=== Test 3: Vision Pipeline degradation mechanism ==='); - const visionPipeline = app.get(VisionPipelineService); - - // 检查是否有测试文件 - const testPdf = '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf'; - if (await fs.access(testPdf).then(() => true).catch(() => false)) { - console.log(`Test file: ${path.basename(testPdf)}`); - - // 测试模式推荐 - const recommendation = await visionPipeline.recommendMode(testPdf); - console.log(`Recommended mode: ${recommendation.recommendedMode}`); - console.log(`Reason: ${recommendation.reason}`); - - // 如果推荐精准模式,测试流程 - if (recommendation.recommendedMode === 'precise') { - console.log('\n⚠️ Note: Full pipeline testing requires:'); - console.log(' 1. LibreOffice service running'); - console.log(' 2. ImageMagick installed'); - console.log(' 3. Vision model API Key configured'); - console.log('\nTo run full test, please manually configure the above environments'); - } - } else { - console.log('⚠️ Test files not found'); - } - - // 测试 4: KnowledgeBase 降级逻辑 - console.log('\n=== Test 4: KnowledgeBase degradation logic ==='); - const kbService = app.get(KnowledgeBaseService); - - console.log('Degradation logic check:'); - console.log('✅ Supported formats: PDF, DOC, DOCX, PPT, PPTX'); - console.log('✅ Check Vision model configuration'); - console.log('✅ Auto-degrade to fast mode'); - console.log('✅ Error logging'); - console.log('✅ Temporary file cleanup'); - - // 测试 5: 环境配置验证 - console.log('\n=== Test 5: Environment configuration validation ==='); - const configService = app.get(require('@nestjs/config').ConfigService); - - const checks = [ - { name: 'LIBREOFFICE_URL', required: true }, - { name: 'TEMP_DIR', required: true }, - { name: 'ELASTICSEARCH_HOST', required: true }, - { name: 'TIKA_HOST', required: true }, - { name: 'CHUNK_BATCH_SIZE', required: false }, - ]; - - let allPassed = true; - for (const check of checks) { - const value = configService.get(check.name); - const passed = check.required ? !!value : true; - const status = passed ? '✅' : '❌'; - console.log(`${status} ${check.name}: ${value || 'Not configured'}`); - if (!passed) allPassed = false; - } - - if (allPassed) { - console.log('\n🎉 All configuration checks passed!'); - } else { - console.log('\n⚠️ Please check missing configuration items'); - } - - // 测试 6: 临时文件清理机制 - console.log('\n=== Test 6: Temporary file cleanup mechanism ==='); - try { - // 检查临时目录 - const tempDir = configService.get('TEMP_DIR', './temp'); - const tempExists = await fs.access(tempDir).then(() => true).catch(() => false); - - if (tempExists) { - console.log(`✅ Temporary directory exists: ${tempDir}`); - - // 检查是否有遗留文件 - const files = await fs.readdir(tempDir); - if (files.length > 0) { - console.log(`⚠️ Found ${files.length} temporary files, cleanup recommended`); - } else { - console.log('✅ Temporary directory is empty'); - } - } else { - console.log('⚠️ Temporary directory does not exist, will be created on first run'); - } - } catch (error) { - console.log(`❌ Temporary directory check failed: ${error.message}`); - } - - console.log('\n=== Error Handling Test Summary ==='); - console.log('✅ LibreOffice connection error handling'); - console.log('✅ PDF to Image conversion failure handling'); - console.log('✅ Vision model error handling'); - console.log('✅ Auto-degrade to fast mode'); - console.log('✅ Temporary file cleanup'); - console.log('✅ Environment configuration validation'); - console.log('\n💡 Suggestions:'); - console.log(' 1. Add more monitoring in production environment'); - console.log(' 2. Implement user quota limits'); - console.log(' 3. Add processing timeout mechanism'); - console.log(' 4. Regularly clean up temporary files'); - - } catch (error) { - console.error('❌ Test failed:', error.message); - console.error(error.stack); - } finally { - await app.close(); - } -} - -if (require.main === module) { - testErrorHandling().catch(console.error); -} - -export { testErrorHandling }; diff --git a/server/scripts/test-local-import.d.ts b/server/scripts/test-local-import.d.ts deleted file mode 100644 index cb0ff5c..0000000 --- a/server/scripts/test-local-import.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/server/scripts/test-local-import.js b/server/scripts/test-local-import.js deleted file mode 100644 index 0102701..0000000 --- a/server/scripts/test-local-import.js +++ /dev/null @@ -1,137 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const axios_1 = __importDefault(require("axios")); -const fs = __importStar(require("fs")); -const path = __importStar(require("path")); -const os = __importStar(require("os")); -async function testLocalImport() { - const baseURL = 'http://localhost:3001/api'; - const username = process.argv[2] || 'admin'; - const password = process.argv[3]; - const sourceFolder = process.argv[4]; - const tenantId = process.argv[5]; - if (!password) { - console.error('Usage: ts-node scripts/test-local-import.ts [sourceFolder] [tenantId]'); - process.exit(1); - } - try { - console.log(`Logging in as ${username} to ${baseURL}...`); - const loginRes = await axios_1.default.post(`${baseURL}/auth/login`, { - username, - password - }); - const jwtToken = loginRes.data.access_token; - console.log('Login successful.'); - console.log('Retrieving API key...'); - const apiKeyRes = await axios_1.default.get(`${baseURL}/auth/api-key`, { - headers: { Authorization: `Bearer ${jwtToken}` } - }); - const apiKey = apiKeyRes.data.apiKey; - console.log('API Key retrieved:', apiKey); - const authHeaders = { 'x-api-key': apiKey }; - if (tenantId) { - authHeaders['x-tenant-id'] = tenantId; - console.log(`Target tenant set to: ${tenantId}`); - } - let targetPath = sourceFolder; - let isTemp = false; - if (!targetPath) { - isTemp = true; - targetPath = path.join(os.tmpdir(), `aurak-test-${Date.now()}`); - const subDir = path.join(targetPath, 'subfolder'); - fs.mkdirSync(targetPath, { recursive: true }); - fs.mkdirSync(subDir, { recursive: true }); - fs.writeFileSync(path.join(targetPath, 'root-file.md'), '# Root File\nContent in root.', 'utf8'); - fs.writeFileSync(path.join(subDir, 'sub-file.txt'), 'Content in subfolder.', 'utf8'); - console.log(`Created temporary test structure at: ${targetPath}`); - } - else { - console.log(`Using provided source folder: ${targetPath}`); - if (!fs.existsSync(targetPath)) { - throw new Error(`The specified folder does not exist: ${targetPath}`); - } - } - const modelsRes = await axios_1.default.get(`${baseURL}/models`, { - headers: authHeaders - }); - const embeddingModel = modelsRes.data.find((m) => m.type === 'embedding' && m.isEnabled !== false); - if (!embeddingModel) { - throw new Error('No enabled embedding model found'); - } - console.log(`Using embedding model: ${embeddingModel.id}`); - console.log('Triggering local folder import...'); - const importRes = await axios_1.default.post(`${baseURL}/upload/local-folder`, { - sourcePath: targetPath, - embeddingModelId: embeddingModel.id, - useHierarchy: true - }, { - headers: authHeaders - }); - console.log('Import response:', importRes.data); - if (isTemp) { - console.log('Waiting for background processing (10s)...'); - await new Promise(resolve => setTimeout(resolve, 10000)); - const kbRes = await axios_1.default.get(`${baseURL}/knowledge-bases`, { - headers: authHeaders - }); - const importedFiles = kbRes.data.filter((f) => f.originalName === 'root-file.md' || f.originalName === 'sub-file.txt'); - console.log(`Found ${importedFiles.length} imported files in KB.`); - if (importedFiles.length === 2) { - console.log('SUCCESS: All files imported.'); - } - else { - console.log('FAILURE: Not all files were imported.'); - } - } - else { - console.log('Custom folder import triggered. Please check the UI or database for results.'); - } - } - catch (error) { - if (error.response) { - console.error(`Test failed with status ${error.response.status}:`, JSON.stringify(error.response.data)); - } - else { - console.error('Test failed:', error.message); - } - process.exit(1); - } -} -testLocalImport(); -//# sourceMappingURL=test-local-import.js.map \ No newline at end of file diff --git a/server/scripts/test-local-import.js.map b/server/scripts/test-local-import.js.map deleted file mode 100644 index 036ec7b..0000000 --- a/server/scripts/test-local-import.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"test-local-import.js","sourceRoot":"","sources":["test-local-import.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/server/scripts/test-local-import.ts b/server/scripts/test-local-import.ts deleted file mode 100644 index 57f810b..0000000 --- a/server/scripts/test-local-import.ts +++ /dev/null @@ -1,126 +0,0 @@ -import axios from 'axios'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as os from 'os'; - -async function testLocalImport() { - const baseURL = 'http://localhost:3001/api'; - const username = process.argv[2] || 'admin'; - const password = process.argv[3]; - const sourceFolder = process.argv[4]; - const tenantId = process.argv[5]; - - if (!password) { - console.error('Usage: ts-node scripts/test-local-import.ts [sourceFolder] [tenantId]'); - process.exit(1); - } - - try { - // 1. Login to get JWT Token - console.log(`Logging in as ${username} to ${baseURL}...`); - const loginRes = await axios.post(`${baseURL}/auth/login`, { - username, - password - }); - const jwtToken = loginRes.data.access_token; - console.log('Login successful.'); - - // 2. Get API Key using JWT Token - console.log('Retrieving API key...'); - const apiKeyRes = await axios.get(`${baseURL}/auth/api-key`, { - headers: { Authorization: `Bearer ${jwtToken}` } - }); - const apiKey = apiKeyRes.data.apiKey; - console.log('API Key retrieved:', apiKey); - - // From now on, using x-api-key for authentication - const authHeaders: any = { 'x-api-key': apiKey }; - if (tenantId) { - authHeaders['x-tenant-id'] = tenantId; - console.log(`Target tenant set to: ${tenantId}`); - } - - // 3. Prepare folder structure - let targetPath = sourceFolder; - let isTemp = false; - - if (!targetPath) { - isTemp = true; - targetPath = path.join(os.tmpdir(), `aurak-test-${Date.now()}`); - const subDir = path.join(targetPath, 'subfolder'); - - fs.mkdirSync(targetPath, { recursive: true }); - fs.mkdirSync(subDir, { recursive: true }); - - fs.writeFileSync(path.join(targetPath, 'root-file.md'), '# Root File\nContent in root.', 'utf8'); - fs.writeFileSync(path.join(subDir, 'sub-file.txt'), 'Content in subfolder.', 'utf8'); - - console.log(`Created temporary test structure at: ${targetPath}`); - } else { - console.log(`Using provided source folder: ${targetPath}`); - if (!fs.existsSync(targetPath)) { - throw new Error(`The specified folder does not exist: ${targetPath}`); - } - } - - // 4. Initial check for embedding models - const modelsRes = await axios.get(`${baseURL}/models`, { - headers: authHeaders - }); - const embeddingModel = modelsRes.data.find((m: any) => m.type === 'embedding' && m.isEnabled !== false); - - if (!embeddingModel) { - throw new Error('No enabled embedding model found'); - } - - console.log(`Using embedding model: ${embeddingModel.id}`); - - // 5. Call local-folder import endpoint - console.log('Triggering local folder import...'); - const importRes = await axios.post(`${baseURL}/upload/local-folder`, { - sourcePath: targetPath, - embeddingModelId: embeddingModel.id, - useHierarchy: true - }, { - headers: authHeaders - }); - - console.log('Import response:', importRes.data); - - // 6. Verification - if (isTemp) { - console.log('Waiting for background processing (10s)...'); - await new Promise(resolve => setTimeout(resolve, 10000)); - - const kbRes = await axios.get(`${baseURL}/knowledge-bases`, { - headers: authHeaders - }); - - const importedFiles = kbRes.data.filter((f: any) => - f.originalName === 'root-file.md' || f.originalName === 'sub-file.txt' - ); - - console.log(`Found ${importedFiles.length} imported files in KB.`); - if (importedFiles.length === 2) { - console.log('SUCCESS: All files imported.'); - } else { - console.log('FAILURE: Not all files were imported.'); - } - } else { - console.log('Custom folder import triggered. Please check the UI or database for results.'); - } - - } catch (error: any) { - if (error.response) { - console.error(`Test failed with status ${error.response.status}:`, JSON.stringify(error.response.data)); - } else { - console.error('Test failed:', error.message); - } - process.exit(1); - } -} - - -testLocalImport(); - - diff --git a/server/scripts/test-vision-pipeline.d.ts b/server/scripts/test-vision-pipeline.d.ts deleted file mode 100644 index 0d2dd16..0000000 --- a/server/scripts/test-vision-pipeline.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare function testVisionPipeline(): Promise; -export { testVisionPipeline }; diff --git a/server/scripts/test-vision-pipeline.js b/server/scripts/test-vision-pipeline.js deleted file mode 100644 index 3cb17d3..0000000 --- a/server/scripts/test-vision-pipeline.js +++ /dev/null @@ -1,139 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -exports.testVisionPipeline = testVisionPipeline; -const core_1 = require("@nestjs/core"); -const app_module_1 = require("./src/app.module"); -const vision_pipeline_service_1 = require("./src/vision-pipeline/vision-pipeline.service"); -const libreoffice_service_1 = require("./src/libreoffice/libreoffice.service"); -const pdf2image_service_1 = require("./src/pdf2image/pdf2image.service"); -const fs = __importStar(require("fs/promises")); -const path = __importStar(require("path")); -async function testVisionPipeline() { - console.log('🚀 Starting Vision Pipeline end-to-end test\n'); - const app = await core_1.NestFactory.createApplicationContext(app_module_1.AppModule, { - logger: ['error', 'warn', 'log'], - }); - try { - console.log('=== Test 1: LibreOffice service ==='); - const libreOffice = app.get(libreoffice_service_1.LibreOfficeService); - const isHealthy = await libreOffice.healthCheck(); - console.log(`LibreOffice health check: ${isHealthy ? '✅ Passed' : '❌ Failed'}`); - if (!isHealthy) { - console.log('⚠️ LibreOffice service not running, skipping subsequent tests'); - return; - } - console.log('\n=== Test 2: PDF to Image service ==='); - const pdf2Image = app.get(pdf2image_service_1.Pdf2ImageService); - const testPdf = '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf'; - if (await fs.access(testPdf).then(() => true).catch(() => false)) { - console.log(`Test PDF: ${path.basename(testPdf)}`); - const result = await pdf2Image.convertToImages(testPdf, { - density: 150, - quality: 75, - format: 'jpeg', - }); - console.log(`✅ Conversion successful: ${result.images.length}/${result.totalPages} pages`); - console.log(` Success: ${result.successCount}, Failed: ${result.failedCount}`); - await pdf2Image.cleanupImages(result.images); - console.log('✅ Temporary files cleaned up'); - } - else { - console.log('⚠️ Test PDF file does not exist, skipping this test'); - } - console.log('\n=== Test 3: Vision Pipeline complete flow ==='); - const visionPipeline = app.get(vision_pipeline_service_1.VisionPipelineService); - const testFiles = [ - '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf', - '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1765705143480-947461268.pdf', - ]; - let testFile = null; - for (const file of testFiles) { - if (await fs.access(file).then(() => true).catch(() => false)) { - testFile = file; - break; - } - } - if (testFile) { - console.log(`Test file: ${path.basename(testFile)}`); - const recommendation = await visionPipeline.recommendMode(testFile); - console.log(`Recommended mode: ${recommendation.recommendedMode}`); - console.log(`Reason: ${recommendation.reason}`); - if (recommendation.estimatedCost) { - console.log(`Estimated cost: $${recommendation.estimatedCost.toFixed(2)}`); - } - if (recommendation.estimatedTime) { - console.log(`Estimated time: ${recommendation.estimatedTime.toFixed(1)}s`); - } - if (recommendation.warnings && recommendation.warnings.length > 0) { - console.log(`Warnings: ${recommendation.warnings.join(', ')}`); - } - console.log('\n✅ Vision Pipeline module correctly configured'); - console.log(' Note: Full flow testing requires a valid Vision model API Key'); - } - else { - console.log('⚠️ Test files not found, skipping complete flow test'); - } - console.log('\n=== Test 4: Environment configuration check ==='); - const configService = app.get(require('@nestjs/config').ConfigService); - const requiredEnvVars = [ - 'LIBREOFFICE_URL', - 'TEMP_DIR', - 'ELASTICSEARCH_HOST', - 'TIKA_HOST', - ]; - for (const envVar of requiredEnvVars) { - const value = configService.get(envVar); - if (value) { - console.log(`✅ ${envVar}: ${value}`); - } - else { - console.log(`❌ ${envVar}: Not configured`); - } - } - console.log('\n🎉 All basic tests completed!'); - } - catch (error) { - console.error('❌ Test failed:', error.message); - console.error(error.stack); - } - finally { - await app.close(); - } -} -if (require.main === module) { - testVisionPipeline().catch(console.error); -} -//# sourceMappingURL=test-vision-pipeline.js.map \ No newline at end of file diff --git a/server/scripts/test-vision-pipeline.js.map b/server/scripts/test-vision-pipeline.js.map deleted file mode 100644 index 5181064..0000000 --- a/server/scripts/test-vision-pipeline.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"test-vision-pipeline.js","sourceRoot":"","sources":["test-vision-pipeline.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/server/scripts/test-vision-pipeline.ts b/server/scripts/test-vision-pipeline.ts deleted file mode 100644 index 86809f4..0000000 --- a/server/scripts/test-vision-pipeline.ts +++ /dev/null @@ -1,145 +0,0 @@ -/** - * Vision Pipeline 端到端测试脚本 - * - * 测试流程: - * 1. LibreOffice 文档转换 - * 2. PDF 转图片 - * 3. Vision 模型分析 - * 4. 完整流程集成 - */ - -import { NestFactory } from '@nestjs/core'; -import { AppModule } from './src/app.module'; -import { VisionPipelineService } from './src/vision-pipeline/vision-pipeline.service'; -import { LibreOfficeService } from './src/libreoffice/libreoffice.service'; -import { Pdf2ImageService } from './src/pdf2image/pdf2image.service'; -import { VisionService } from './src/vision/vision.service'; -import * as fs from 'fs/promises'; -import * as path from 'path'; - -async function testVisionPipeline() { - console.log('🚀 Starting Vision Pipeline end-to-end test\n'); - - // 初始化 Nest 应用 - const app = await NestFactory.createApplicationContext(AppModule, { - logger: ['error', 'warn', 'log'], - }); - - try { - // 1. 测试 LibreOffice 服务 - console.log('=== Test 1: LibreOffice service ==='); - const libreOffice = app.get(LibreOfficeService); - - // 检查健康状态 - const isHealthy = await libreOffice.healthCheck(); - console.log(`LibreOffice health check: ${isHealthy ? '✅ Passed' : '❌ Failed'}`); - - if (!isHealthy) { - console.log('⚠️ LibreOffice service not running, skipping subsequent tests'); - return; - } - - // 2. 测试 PDF 转图片服务 - console.log('\n=== Test 2: PDF to Image service ==='); - const pdf2Image = app.get(Pdf2ImageService); - - const testPdf = '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf'; - if (await fs.access(testPdf).then(() => true).catch(() => false)) { - console.log(`Test PDF: ${path.basename(testPdf)}`); - - const result = await pdf2Image.convertToImages(testPdf, { - density: 150, // 降低密度以加快测试 - quality: 75, - format: 'jpeg', - }); - - console.log(`✅ Conversion successful: ${result.images.length}/${result.totalPages} pages`); - console.log(` Success: ${result.successCount}, Failed: ${result.failedCount}`); - - // 清理测试文件 - await pdf2Image.cleanupImages(result.images); - console.log('✅ Temporary files cleaned up'); - } else { - console.log('⚠️ Test PDF file does not exist, skipping this test'); - } - - // 3. 测试 Vision Pipeline 完整流程 - console.log('\n=== Test 3: Vision Pipeline complete flow ==='); - const visionPipeline = app.get(VisionPipelineService); - - // 检查是否有支持的测试文件 - const testFiles = [ - '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf', - '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1765705143480-947461268.pdf', - ]; - - let testFile: string | null = null; - for (const file of testFiles) { - if (await fs.access(file).then(() => true).catch(() => false)) { - testFile = file; - break; - } - } - - if (testFile) { - console.log(`Test file: ${path.basename(testFile)}`); - - // 模式推荐测试 - const recommendation = await visionPipeline.recommendMode(testFile); - console.log(`Recommended mode: ${recommendation.recommendedMode}`); - console.log(`Reason: ${recommendation.reason}`); - if (recommendation.estimatedCost) { - console.log(`Estimated cost: $${recommendation.estimatedCost.toFixed(2)}`); - } - if (recommendation.estimatedTime) { - console.log(`Estimated time: ${recommendation.estimatedTime.toFixed(1)}s`); - } - if (recommendation.warnings && recommendation.warnings.length > 0) { - console.log(`Warnings: ${recommendation.warnings.join(', ')}`); - } - - // 注意:完整流程测试需要配置 Vision 模型 API Key - // 这里只测试流程结构 - console.log('\n✅ Vision Pipeline module correctly configured'); - console.log(' Note: Full flow testing requires a valid Vision model API Key'); - - } else { - console.log('⚠️ Test files not found, skipping complete flow test'); - } - - // 4. 检查环境配置 - console.log('\n=== Test 4: Environment configuration check ==='); - const configService = app.get(require('@nestjs/config').ConfigService); - - const requiredEnvVars = [ - 'LIBREOFFICE_URL', - 'TEMP_DIR', - 'ELASTICSEARCH_HOST', - 'TIKA_HOST', - ]; - - for (const envVar of requiredEnvVars) { - const value = configService.get(envVar); - if (value) { - console.log(`✅ ${envVar}: ${value}`); - } else { - console.log(`❌ ${envVar}: Not configured`); - } - } - - console.log('\n🎉 All basic tests completed!'); - - } catch (error) { - console.error('❌ Test failed:', error.message); - console.error(error.stack); - } finally { - await app.close(); - } -} - -// 运行测试 -if (require.main === module) { - testVisionPipeline().catch(console.error); -} - -export { testVisionPipeline }; diff --git a/server/scripts/text_to_speech.py b/server/scripts/text_to_speech.py deleted file mode 100644 index 64248b7..0000000 --- a/server/scripts/text_to_speech.py +++ /dev/null @@ -1,22 +0,0 @@ -import asyncio -import argparse -import edge_tts - -async def generate_speech(text, voice, output_file): - communicate = edge_tts.Communicate(text, voice) - await communicate.save(output_file) - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Text to Speech using Edge TTS') - parser.add_argument('--text', required=True, help='Text to convert to speech') - parser.add_argument('--voice', required=True, help='Voice to use (e.g., zh-CN-YunxiNeural)') - parser.add_argument('--output', required=True, help='Output MP3 file path') - - args = parser.parse_args() - - try: - asyncio.run(generate_speech(args.text, args.voice, args.output)) - print(f"Success: {args.output}") - except Exception as e: - print(f"Error: {e}") - exit(1)