UNPKG

bioinformatics-mcp-server

Version:

🧬 生物信息学MCP服务器 - 专为ModelScope设计的智能生物数据分析工具

223 lines (199 loc) 9.15 kB
import * as fs from 'fs'; import * as path from 'path'; import { generateId } from '../utils/common.js'; import { detectPythonCommand } from '../python/detector.js'; import { extractPythonScripts } from '../python/extractor.js'; import { installPythonPackages } from '../python/package-manager.js'; import { executePythonScripts } from '../python/executor.js'; import { generateHtmlReport, openHtmlReport } from '../report/html-generator.js'; /** * 处理执行Claude脚本的请求 */ export async function handleExecuteClaudeScript(args, projectPath) { const safeArgs = args || {}; const claude_response = safeArgs.claude_response || ''; const workflow_id = safeArgs.workflow_id || generateId(); const execution_context = safeArgs.execution_context || ''; if (!claude_response || claude_response.trim() === '') { throw new Error('claude_response is required and cannot be empty'); } try { console.error(`Analyzing Claude response for Python scripts...`); console.error(`Response length: ${claude_response.length} characters`); // 检测和提取Python脚本 const pythonScripts = extractPythonScripts(claude_response); if (pythonScripts.length === 0) { return { content: [ { type: 'text', text: `# Claude脚本执行结果 ## 检测结果: 未发现Python脚本 在Claude的响应中没有检测到可执行的Python代码块。 **提示**: 确保Python代码被包含在 \`\`\`python 代码块中。`, }, ], }; } // 记录脚本信息 const totalLines = pythonScripts.reduce((sum, script) => sum + (script.lineCount || 0), 0); let scriptInfo = ''; if (pythonScripts.length > 0) { scriptInfo = `\n📊 **脚本统计**: 共 ${pythonScripts.length} 个脚本,总计 ${totalLines} 行代码。注重代码质量和分析完整性。\n`; } // 创建执行目录 const executionDir = path.join(projectPath, workflow_id); fs.mkdirSync(executionDir, { recursive: true }); // 调试:保存原始响应到文件 fs.writeFileSync(path.join(executionDir, 'debug_claude_response.txt'), claude_response, 'utf8'); const executionResults = []; let pythonCommand; try { // 检测可用的Python命令 pythonCommand = await detectPythonCommand(); console.error(`Python检测成功: ${pythonCommand}`); } catch (pythonError) { // Python未安装,返回安装指导 return { content: [ { type: 'text', text: `# ❌ Python环境检测失败 ${pythonError.message} **请按照上述指导安装Python后重新运行脚本。** ## 检测到的脚本信息: - 发现 **${pythonScripts.length}** 个Python脚本 - 需要的包: ${Array.from(new Set(pythonScripts.flatMap(s => s.dependencies))).join(', ') || '无特殊依赖'} ${scriptInfo} 安装Python后,这些脚本将自动执行!`, }, ], }; } // 收集所有脚本的依赖包 const allDependencies = Array.from(new Set(pythonScripts.flatMap(script => script.dependencies))); // 安装依赖包 const packageInstallResult = await installPythonPackages(pythonCommand, allDependencies, executionDir); // 执行所有脚本 const scriptExecutionResults = await executePythonScripts(pythonScripts, pythonCommand, executionDir); // 保存执行结果 const fullResult = { workflow_id, execution_context, claude_response: claude_response.substring(0, 1000) + '...', // 截断长响应 scripts_found: pythonScripts.length, dependencies_detected: allDependencies, package_installation: packageInstallResult, execution_results: scriptExecutionResults, executed_at: new Date().toISOString() }; fs.writeFileSync(path.join(executionDir, 'claude_script_results.json'), JSON.stringify(fullResult, null, 2)); // 生成报告 const successCount = scriptExecutionResults.filter(r => r.status === 'success').length; const errorCount = scriptExecutionResults.filter(r => r.status === 'error').length; console.error(`执行结果统计: 成功=${successCount}, 失败=${errorCount}, 总计=${scriptExecutionResults.length}`); // 只在所有脚本都执行成功时生成和打开HTML报告 let htmlReportInfo = ''; if (errorCount === 0 && successCount > 0) { try { console.error('开始生成HTML报告...'); const reportPath = generateHtmlReport(fullResult, pythonScripts, executionDir); console.error(`HTML报告已生成: ${reportPath}`); // 检查文件是否确实存在 if (fs.existsSync(reportPath)) { console.error('HTML报告文件确认存在,准备打开浏览器...'); // 异步打开浏览器,不等待结果 openHtmlReport(reportPath).catch(error => { console.error('Failed to open HTML report:', error); }); htmlReportInfo = `## 📊 HTML详细报告: **已自动生成并打开HTML格式的详细执行报告!** - 报告路径: \`${reportPath}\` - 包含完整的执行日志、代码高亮和交互式界面 - 如未自动打开,请手动打开上述文件 `; } else { console.error('HTML报告文件生成失败,文件不存在'); htmlReportInfo = `## ⚠️ HTML报告生成失败: 报告文件未能成功创建 `; } } catch (reportError) { console.error('Failed to generate HTML report:', reportError); htmlReportInfo = `## ⚠️ HTML报告生成失败: 无法生成HTML报告: ${reportError instanceof Error ? reportError.message : '未知错误'} `; } } else if (errorCount > 0) { console.error(`由于有${errorCount}个脚本执行失败,跳过HTML报告生成`); htmlReportInfo = `## 📋 执行报告: 由于有脚本执行失败,未生成HTML报告。请修复错误后重新执行。 `; } else { console.error('没有成功执行的脚本,跳过HTML报告生成'); htmlReportInfo = `## 📋 执行报告: 没有成功执行的脚本,未生成HTML报告。 `; } return { content: [ { type: 'text', text: `# Claude Python脚本执行报告 ## 工作流ID: ${workflow_id} ## 执行概况: - 检测到 **${pythonScripts.length}** 个Python脚本 - 成功执行: **${successCount}** 个 - 执行失败: **${errorCount}** 个 ${scriptInfo} ## Python环境: - Python命令: \`${pythonCommand}\` - 检测到的依赖包: ${allDependencies.length > 0 ? allDependencies.join(', ') : '无特殊依赖'} ## 包安装结果: ${packageInstallResult.logs.map(log => `- ${log}`).join('\n')} ## 执行上下文: ${execution_context} ${htmlReportInfo}## 详细结果: ${scriptExecutionResults.map((result, idx) => ` ### 脚本 ${result.script_number}: ${result.script_name} **状态**: ${result.status === 'success' ? '✅ 成功' : '❌ 失败'} **描述**: ${result.description} **依赖包**: ${result.dependencies.length > 0 ? result.dependencies.join(', ') : '无特殊依赖'} ${pythonScripts[idx]?.lineCount ? `**代码行数**: ${pythonScripts[idx].lineCount} 行` : ''} **标准输出**: \`\`\` ${result.stdout || '(无输出)'} \`\`\` **错误输出**: \`\`\` ${result.stderr || '(无错误)'} \`\`\` `).join('\n')} ## 执行目录: ${executionDir} ${errorCount > 0 ? `## ⚠️ 发现错误 有 ${errorCount} 个脚本执行失败,请检查错误信息并考虑: 1. 检查Python环境和依赖包安装状态 2. 验证输入数据和文件路径 3. 检查脚本逻辑和语法 4. 使用 \`debug_workflow\` 工具进行详细分析 ${!packageInstallResult.success ? '⚠️ 部分Python包安装失败,这可能是导致脚本执行失败的原因。' : ''}` : `## 🎉 执行成功 所有脚本都成功执行!你可以查看执行目录中的结果文件或打开HTML报告查看详细信息。`} **下次如果Claude生成新的脚本,我会自动检测依赖并安装,然后执行它们!请注重代码质量和分析的完整性。**`, }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; console.error(`Claude script execution error: ${errorMessage}`); throw new Error(`Failed to execute Claude scripts: ${errorMessage}`); } }