UNPKG

aigit-cli

Version:

AI-powered git commit message generator using OpenAI or DeepSeek

334 lines (263 loc) 9.05 kB
import { config } from './config.js'; // 代码审查器 export class CodeReviewer { constructor(provider = config.provider) { this.provider = provider; } // 获取AI客户端 async getAIClient() { if (this.provider === 'openai') { const { OpenAI } = await import('openai'); return new OpenAI({ apiKey: config.openaiApiKey, }); } else if (this.provider === 'deepseek') { // 直接创建DeepSeek客户端 const { OpenAI } = await import('openai'); return new OpenAI({ apiKey: config.deepseekApiKey, baseURL: 'https://api.deepseek.com/v1', }); } throw new Error('不支持的AI提供商'); } // 生成代码审查prompt generateReviewPrompt(diff, options = {}) { const { language = '中文', reviewType = 'comprehensive' } = options; const reviewTypes = { comprehensive: `作为资深代码审查专家,请对以下代码变更进行全面审查,给出详细的修改建议。 审查要点: 1. 代码质量和最佳实践 2. 潜在的安全问题 3. 性能优化建议 4. 代码可读性和维护性 5. 测试覆盖建议 6. 文档完善建议 请用${language}回答,格式如下: ## 🔍 代码审查结果 ### ✅ 优点 - 列出代码的优点 ### ⚠️ 需要注意的问题 - 列出需要注意的问题 ### 🚨 严重问题 - 列出需要立即修复的严重问题 ### 💡 改进建议 - 具体的改进建议 ### 📝 代码示例 \`\`\`代码语言 // 改进后的代码示例 \`\`\` ### 🧪 测试建议 - 建议添加的测试用例 ### 📚 文档建议 - 建议完善的文档内容`, security: `作为安全专家,请对以下代码变更进行安全审查,重点关注潜在的安全风险。 安全审查要点: 1. 输入验证和清理 2. 权限控制 3. 数据泄露风险 4. 注入攻击风险 5. 认证和授权 6. 加密和哈希 7. 日志和监控 请用${language}回答,格式如下: ## 🔒 安全审查结果 ### 🚨 高危安全问题 - 列出高危安全问题 ### ⚠️ 中危安全问题 - 列出中危安全问题 ### 💡 安全改进建议 - 具体的安全改进建议 ### 🛡️ 防护措施 - 建议的防护措施`, performance: `作为性能优化专家,请对以下代码变更进行性能审查,找出性能瓶颈和优化机会。 性能审查要点: 1. 算法复杂度 2. 内存使用 3. 数据库查询优化 4. 缓存策略 5. 异步处理 6. 资源管理 7. 监控和指标 请用${language}回答,格式如下: ## ⚡ 性能审查结果 ### 🐌 性能瓶颈 - 识别性能瓶颈 ### 💡 优化建议 - 具体的性能优化建议 ### 📊 性能指标 - 建议监控的性能指标 ### 🔧 优化工具 - 推荐的性能优化工具`, maintainability: `作为软件架构师,请对以下代码变更进行可维护性审查,评估代码的长期维护成本。 可维护性审查要点: 1. 代码结构设计 2. 模块化程度 3. 依赖关系 4. 代码重复 5. 命名规范 6. 错误处理 7. 扩展性 请用${language}回答,格式如下: ## 🏗️ 可维护性审查结果 ### ✅ 良好的设计 - 列出良好的设计决策 ### ⚠️ 维护风险 - 识别维护风险 ### 💡 重构建议 - 具体的重构建议 ### 📋 代码规范 - 建议遵循的代码规范` }; return `${reviewTypes[reviewType] || reviewTypes.comprehensive} ## 📄 代码变更内容 \`\`\`diff ${diff} \`\`\` 请基于以上代码变更进行审查。`; } // 执行代码审查 async reviewCode(diff, options = {}) { try { const finalOptions = { language: options.language || config.language, reviewType: options.reviewType || 'comprehensive', temperature: parseFloat(options.temperature) || 0.3, // 降低温度以获得更稳定的审查结果 maxTokens: options.maxTokens || 2000 }; if (!diff || !diff.trim()) { throw new Error('没有有效的代码变更内容'); } const prompt = this.generateReviewPrompt(diff, finalOptions); const client = await this.getAIClient(); const completion = await client.chat.completions.create({ model: options.model || (this.provider === 'openai' ? 'gpt-4' : 'deepseek-chat'), messages: [ { role: 'system', content: '你是一位经验丰富的代码审查专家,具有深厚的软件工程背景。请提供专业、准确、实用的代码审查建议。' }, { role: 'user', content: prompt } ], temperature: finalOptions.temperature, max_tokens: finalOptions.maxTokens, }); const reviewResult = completion.choices[0]?.message?.content?.trim(); if (!reviewResult) { throw new Error('AI未能生成有效的代码审查结果'); } return { success: true, review: reviewResult, options: finalOptions, timestamp: new Date().toISOString() }; } catch (error) { const providerName = this.provider === 'openai' ? 'OpenAI' : 'DeepSeek'; // 检查具体的错误类型 if (error.code === 'insufficient_quota' || error.message.includes('Insufficient Balance')) { throw new Error(`${providerName} API余额不足,请充值账户`); } else if (error.code === 'invalid_api_key' || error.message.includes('Invalid API key')) { throw new Error(`${providerName} API密钥无效,请检查配置`); } else if (error.code === 'rate_limit_exceeded' || error.message.includes('rate limit')) { throw new Error(`${providerName} API请求频率超限,请稍后重试`); } else if (error.code === 'model_not_found' || error.message.includes('Model Not Exist') || error.message.includes('model not found')) { throw new Error(`${providerName} 模型不存在,请检查模型名称`); } else if (error.message.includes('fetch')) { throw new Error(`${providerName} 网络连接失败,请检查网络设置`); } else { // 提供更详细的错误信息用于调试 console.error('详细错误信息:', error); throw new Error(`${providerName} API调用失败: ${error.message}`); } } } // 生成代码审查摘要 async generateReviewSummary(diff, options = {}) { try { const summaryPrompt = `请对以下代码变更生成一个简洁的审查摘要,用${options.language || '中文'}回答。 摘要要求: 1. 总体评价(优秀/良好/一般/需要改进) 2. 主要问题数量 3. 关键改进建议 4. 优先级排序 代码变更: \`\`\`diff ${diff} \`\`\` 请用简洁的语言给出摘要。`; const client = await this.getAIClient(); const completion = await client.chat.completions.create({ model: options.model || (this.provider === 'openai' ? 'gpt-3.5-turbo' : 'deepseek-chat'), messages: [ { role: 'system', content: '你是代码审查专家,请提供简洁明了的审查摘要。' }, { role: 'user', content: summaryPrompt } ], temperature: 0.3, max_tokens: 500, }); const summary = completion.choices[0]?.message?.content?.trim(); if (!summary) { throw new Error('AI未能生成有效的审查摘要'); } return summary; } catch (error) { throw new Error(`生成审查摘要失败: ${error.message}`); } } // 分析代码质量指标 analyzeCodeQuality(diff) { const metrics = { linesChanged: 0, filesChanged: 0, additions: 0, deletions: 0, complexity: 'low', riskLevel: 'low' }; if (!diff) return metrics; const lines = diff.split('\n'); const changedFiles = new Set(); for (const line of lines) { if (line.startsWith('+++') || line.startsWith('---')) { if (line.includes('/')) { const fileName = line.split('/').pop(); if (fileName) { changedFiles.add(fileName); } } } else if (line.startsWith('+') && !line.startsWith('+++')) { metrics.additions++; metrics.linesChanged++; } else if (line.startsWith('-') && !line.startsWith('---')) { metrics.deletions++; metrics.linesChanged++; } } metrics.filesChanged = changedFiles.size; // 评估复杂度 if (metrics.linesChanged > 100) { metrics.complexity = 'high'; } else if (metrics.linesChanged > 50) { metrics.complexity = 'medium'; } // 评估风险等级 if (metrics.complexity === 'high' || metrics.filesChanged > 5) { metrics.riskLevel = 'high'; } else if (metrics.complexity === 'medium' || metrics.filesChanged > 2) { metrics.riskLevel = 'medium'; } return metrics; } } // 导出默认实例 export const codeReviewer = new CodeReviewer();