喵喵喵

This commit is contained in:
gaoao-3 2025-01-03 15:19:08 +08:00
parent d1ca268f36
commit 267c24dda5

View file

@ -4,13 +4,15 @@ import { Config } from '../config.js';
import common from '../../../../lib/common/common.js';
/**
* 代码执行工具类 - 使用 Gemini API
* @class CodeExecutionTool
* CodeExecutionTool - Gemini API代码执行工具类
* 支持多种编程语言的代码执行并提供详细的执行结果和分析
* @extends {AbstractTool}
*/
export class CodeExecutionTool extends AbstractTool {
// 工具标识名称
name = 'CodeExecutionTool';
// 工具参数定义
parameters = {
properties: {
code: {
@ -29,54 +31,54 @@ export class CodeExecutionTool extends AbstractTool {
required: ['code', 'language'],
};
// 工具功能描述
description = '使用 Gemini API 执行代码,支持多种编程语言,并返回执行结果和相关解释。';
// 配置常量
static TIMEOUT = 30000; // 请求超时时间30秒
// API请求超时设置30秒
static TIMEOUT = 30000;
/**
* 工具执行函数
* @param {Object} opt - 工具参数
* @param {string} opt.code - 代码内容
* @param {string} opt.language - 编程语言
* 工具执行函数
* @param {Object} opt - 执行参数对象
* @param {string} opt.code - 需要执行的代码
* @param {string} opt.language - 代码语言
* @param {string} [opt.description] - 代码功能描述
* @param {Object} e - 事件对象
* @returns {Promise<Object>} - 包含执行结果的对象
* @returns {Promise<Object>} 执行结果对象
*/
func = async function (opt, e) {
const { code, language, description } = opt;
// 代码内容验证
if (!code?.trim()) {
throw new Error('代码内容不能为空');
}
try {
// 执行代码并获取结果
const result = await this.executeCode(code, language, description);
console.debug(`[CodeExecutionTool] 执行结果:`, result);
// 优化消息构建逻辑
const messages = [];
// 解构结果对象
const { output, executionOutput, explanation, error } = result;
const forwardMsg = [];
// 添加代码信息
messages.push(`执行代码:\n\`\`\`${language}\n${code}\n\`\`\``);
// 添加执行结果
if (result.error) {
messages.push(`执行错误:\n\`\`\`\n${result.error}\n\`\`\``);
// 根据执行结果构建消息
if (error) {
forwardMsg.push(`执行出错:\n${error}`);
} else {
messages.push(`执行结果:\n\`\`\`\n${result.output}\n\`\`\``);
// 添加程序实际输出(如果有)
if (executionOutput) {
forwardMsg.push(`程序输出:\n${executionOutput}`);
}
forwardMsg.push(`执行结果:\n${output}`);
if (explanation) {
forwardMsg.push(`\n代码分析:\n${explanation}`);
}
// 添加代码分析
if (result.explanation) {
messages.push(`代码分析:\n${result.explanation}`);
}
// 添加执行时间
messages.push(`执行时间:${new Date(result.executionTime).toLocaleString()}`);
// 发送转发消息
e.reply(await common.makeForwardMsg(e, messages, `${e.sender.card || e.sender.nickname || e.user_id}的代码执行结果`));
e.reply(await common.makeForwardMsg(e, forwardMsg, `${e.sender.card || e.sender.nickname || e.user_id}的代码执行结果`));
return result;
} catch (error) {
@ -86,22 +88,25 @@ export class CodeExecutionTool extends AbstractTool {
};
/**
* 使用 Gemini API 执行代码
* 通过Gemini API执行代码
* @param {string} code - 代码内容
* @param {string} language - 编程语言
* @param {string} [description] - 代码功能描述
* @returns {Promise<Object>} - 包含执行结果的对象
* @param {string} [description] - 代码描述
* @returns {Promise<Object>} API执行结果
* @private
*/
async executeCode(code, language, description) {
// 获取API配置信息
const apiKey = Config.geminiKey;
const apiBaseUrl = Config.geminiBaseUrl;
const apiUrl = `${apiBaseUrl}/v1beta/models/gemini-2.0-flash-exp:generateContent?key=${apiKey}`;
// API配置验证
if (!apiKey || !apiBaseUrl) {
throw new Error('Gemini API 配置缺失');
}
// 构建API请求体
const requestBody = {
"systemInstruction": {
"parts": [{
@ -126,9 +131,11 @@ export class CodeExecutionTool extends AbstractTool {
};
try {
// 设置请求超时控制
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), CodeExecutionTool.TIMEOUT);
// 发送API请求
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
@ -142,6 +149,7 @@ export class CodeExecutionTool extends AbstractTool {
const data = await response.json();
// 响应状态检查
if (!response.ok) {
throw new Error(`API 请求失败: ${data.error?.message || '未知错误'}`);
}
@ -156,11 +164,11 @@ export class CodeExecutionTool extends AbstractTool {
}
/**
* 构建提示词
* 构建API提示词
* @param {string} code - 代码内容
* @param {string} language - 编程语言
* @param {string} [description] - 代码功能描述
* @returns {string} - 格式化的提示词
* @param {string} [description] - 代码描述
* @returns {string} 格式化的提示词
* @private
*/
constructPrompt(code, language, description) {
@ -170,24 +178,27 @@ export class CodeExecutionTool extends AbstractTool {
}
prompt += `\n执行代码:\n\`\`\`${language}\n${code}\n\`\`\`\n`;
prompt += '请按照以下格式返回结果:\n';
prompt += '执行结果(OUTCOME_OK)\n```\n<执行输出>\n```\n';
prompt += '执行输出:\n```\n<程序实际输出内容>\n```\n';
prompt += '执行结果(OUTCOME_OK)\n```\n<执行状态和结果说明>\n```\n';
prompt += '如果执行出错,请使用:\n';
prompt += '执行结果(OUTCOME_ERROR)\n```\n<错误信息>\n```\n';
prompt += '如果需要,可以在最后添加代码分析。';
prompt += '代码分析:\n<分析和建议>';
return prompt;
}
/**
* 处理 Gemini API 响应
* @param {Object} data - API 响应数据
* @returns {Object} - 处理后的结果对象
* 处理Gemini API响应数据
* @param {Object} data - API响应数据
* @returns {Object} 处理后的结果对象包含输出执行输出解释和错误信息
* @private
*/
processGeminiResponse(data) {
// 响应数据结构验证
if (!data?.candidates?.[0]?.content?.parts) {
throw new Error('无效的 API 响应');
}
// 合并响应文本
const response = data.candidates[0].content.parts
.map(part => part.text)
.filter(Boolean)
@ -196,23 +207,30 @@ export class CodeExecutionTool extends AbstractTool {
let output = '';
let explanation = '';
let error = null;
let executionOutput = '';
try {
// 查找执行结果部分
// 提取执行输出
const outputMatch = response.match(/执行输出:\s*```(?:\w*\n)?([\s\S]*?)```/);
if (outputMatch) {
executionOutput = outputMatch[1].trim();
}
// 提取执行结果
const outcomeMatch = response.match(/执行结果\(OUTCOME_OK\)\s*```(?:\w*\n)?([\s\S]*?)```/);
if (outcomeMatch) {
output = outcomeMatch[1].trim();
} else {
// 检查是否有错误结果
// 提取错误信息
const errorMatch = response.match(/执行结果\(OUTCOME_ERROR\)\s*```(?:\w*\n)?([\s\S]*?)```/);
if (errorMatch) {
error = errorMatch[1].trim();
} else {
output = response; // 如果没有匹配到预期格式,返回原始响应
output = response; // 使用原始响应作为输出
}
}
// 提取代码分析部分(如果有)
// 提取代码分析
const analysisMatch = response.match(/代码分析:([\s\S]*?)(?=\n\n|$)/);
if (analysisMatch) {
explanation = analysisMatch[1].trim();
@ -222,11 +240,13 @@ export class CodeExecutionTool extends AbstractTool {
output = response; // 解析失败时返回原始响应
}
// 返回完整的结果对象
return {
output,
explanation,
error,
executionTime: Date.now()
output, // 执行结果说明
executionOutput, // 程序实际输出
explanation, // 代码分析
error, // 错误信息
executionTime: Date.now() // 执行时间戳
};
}
}