diff --git a/README.md b/README.md index ee4f87b..151251f 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ quasar build ## ② 可视化编排 -- 自动化:支持文件、网络、音视频、图片、文本、浏览器、键鼠等超过 20 种类型的自动化处理 -- 工具集:所有功能既可以组合使用,也可以单独运行,具备视频压缩、格式转换,图片裁剪、旋转,文本朗读,音频播放,编解码,模拟按键,鼠标连点等超过 100 种实用功能 +- 自动化:文件操作、网络操作、系统操作、音频操作、图片操作、视频操作、uTools功能、Mac自动化、Window自动化、浏览器控制、数据处理、编码加密、流程控制、编程相关、用户交互、AI对话、模拟操作、获取状态、数学计算、用户数据、显示器、输出消息等20种以上不同类型命令。 +- 工具集:所有功能既可以组合使用,也可以单独运行,具备视频压缩、格式转换,图片裁剪、旋转,文本朗读,音频播放,编解码,模拟按键,鼠标连点等超过 100 种实用功能。 # 二、其他特色 @@ -156,6 +156,11 @@ JS代码注入、脚本执行(支持多种语言)、函数返回、变量管 匹配数据获取、插件跳转、窗口控制、版本信息获取、主题切换、快捷键管理... Windows特定功能 窗口控制(置顶、透明度、位置)、消息发送、文件系统监控、进程管理、注册表操作、服务管理、快捷方式管理、系统设置修改... + +## AI对话 + +获取API支持的模型列表、AI对话... + ## 视频处理 格式转换、视频压缩、视频剪辑、视频合并、速度调整、视频截图、GIF转换、音频提取、水印添加、分辨率调整、帧率设置、码率控制... diff --git a/plugin/lib/quickcomposer.js b/plugin/lib/quickcomposer.js index 8c05e61..1dbccbc 100644 --- a/plugin/lib/quickcomposer.js +++ b/plugin/lib/quickcomposer.js @@ -13,6 +13,7 @@ const quickcomposer = { status: require("./quickcomposer/status"), browser: require("./quickcomposer/browser"), video: require("./quickcomposer/video"), + ai: require("./quickcomposer/ai"), }; module.exports = quickcomposer; diff --git a/plugin/lib/quickcomposer/ai/chat.js b/plugin/lib/quickcomposer/ai/chat.js new file mode 100644 index 0000000..ee89525 --- /dev/null +++ b/plugin/lib/quickcomposer/ai/chat.js @@ -0,0 +1,214 @@ +const axios = require("axios"); + +// 支持的模型类型 +const MODEL_TYPES = { + OPENAI: "openai", + OLLAMA: "ollama", +}; + +// 预设提示词 +const PRESET_PROMPTS = { + // 翻译 + translate: `请将以下内容翻译成地道的中文,要求: +1. 保持原文的专业性和准确性 +2. 符合中文的表达习惯 +3. 对于专业术语保留英文原文,并在括号中给出中文翻译 +4. 保持原文的段落格式 + +原文:`, + + // 生成SHELL命令 + shell: `请根据以下描述生成一个 shell 命令,要求: +1. 命令应当简洁高效 +2. 优先使用常见的命令行工具 +3. 确保命令的安全性和可靠性 +4. 对于复杂操作,添加注释说明 +5. 如果需要多个命令,使用 && 连接或使用脚本格式 +6. 直接输出命令,不要输出任何解释,不要使用markdown格式 + +需求描述:`, + + // 总结 + summarize: `请总结以下内容的要点,要求: +1. 提取最重要和最有价值的信息 +2. 使用简洁的语言 +3. 按重要性排序 +4. 保持逻辑性和连贯性 +5. 如果有专业术语,保留并解释 + +原文:`, +}; + +/** + * AI对话功能 + * @param {Object} apiConfig - API配置参数 + * @param {string} apiConfig.modelType - 模型类型(openai/ollama) + * @param {string} apiConfig.apiUrl - API地址 + * @param {string} apiConfig.apiToken - API令牌 + * @param {string} apiConfig.model - 模型名称 + * @param {Object} content - 对话内容参数 + * @param {string} content.prompt - 用户输入的提示词 + * @param {string} content.presetPrompt - 预设提示词类型 + * @returns {Promise} 对话响应 + */ +async function chat(apiConfig, content) { + try { + const { modelType, apiUrl, apiToken, model } = apiConfig; + const { prompt, presetPrompt } = content; + + // 验证必要参数 + if (!apiUrl || !prompt || !model) { + throw new Error("API地址、模型名称和提示词不能为空"); + } + + // 构建完整提示词 + const fullPrompt = presetPrompt + ? `${PRESET_PROMPTS[presetPrompt]}\n${prompt}` + : prompt; + + // 准备请求配置 + const config = { + headers: { + "Content-Type": "application/json", + }, + }; + + let requestData; + let url = apiUrl; + + // 根据不同的模型类型构建请求数据 + if (modelType === MODEL_TYPES.OPENAI) { + // OpenAI API + config.headers["Authorization"] = `Bearer ${apiToken}`; + requestData = { + model: model, + messages: [ + { + role: "user", + content: fullPrompt, + }, + ], + }; + } else if (modelType === MODEL_TYPES.OLLAMA) { + // Ollama API + // 如果用户没有指定完整的 API 路径,添加 /api/generate + if (!url.endsWith("/api/generate")) { + url = url.replace(/\/?$/, "/api/generate"); + } + + requestData = { + model: model, + prompt: fullPrompt, + stream: false, + }; + } else { + throw new Error("不支持的模型类型"); + } + + // 发送请求 + const response = await axios.post(url, requestData, config); + + // 解析不同模型的响应 + let result; + if (modelType === MODEL_TYPES.OPENAI) { + // OpenAI 响应格式 + if (!response.data.choices || !response.data.choices[0]) { + throw new Error("OpenAI 响应格式错误"); + } + result = response.data.choices[0].message.content; + } else { + // Ollama 响应格式 + if (!response.data.response) { + throw new Error("Ollama 响应格式错误"); + } + result = response.data.response; + } + + return { + success: true, + result, + }; + } catch (error) { + return { + success: false, + error: error.response?.data?.error?.message || error.message, + }; + } +} + +/** + * 获取API支持的模型列表 + * @param {Object} apiConfig - API配置参数 + * @param {string} apiConfig.modelType - 模型类型(openai/ollama) + * @param {string} apiConfig.apiUrl - API地址 + * @param {string} apiConfig.apiToken - API令牌 + * @returns {Promise} 模型列表响应 + */ +async function getModels(apiConfig) { + try { + const { modelType, apiUrl, apiToken } = apiConfig; + + // 验证必要参数 + if (!apiUrl) { + throw new Error("API地址不能为空"); + } + + // 准备请求配置 + const config = { + headers: { + "Content-Type": "application/json", + }, + }; + + let url = apiUrl; + + // 根据不同的模型类型构建请求 + if (modelType === MODEL_TYPES.OPENAI) { + // OpenAI API + config.headers["Authorization"] = `Bearer ${apiToken}`; + // OpenAI的模型列表接口是 /v1/models + if (!url.endsWith("/models")) { + url = "https://api.openai.com/v1/models"; + } + } else if (modelType === MODEL_TYPES.OLLAMA) { + // Ollama API + // Ollama的模型列表接口是 /api/tags + if (!url.endsWith("/api/tags")) { + url = url.replace(/\/?$/, "/api/tags"); + } + } else { + throw new Error("不支持的模型类型"); + } + + // 发送请求 + const response = await axios.get(url, config); + + // 解析不同模型的响应 + let models; + if (modelType === MODEL_TYPES.OPENAI) { + // OpenAI 响应格式 + if (!response.data.data) { + throw new Error("OpenAI 响应格式错误"); + } + models = response.data.data.map((model) => model.id); + } else { + // Ollama 响应格式 + if (!response.data.models) { + throw new Error("Ollama 响应格式错误"); + } + models = response.data.models.map((model) => model.name); + } + + return { + success: true, + result: models, + }; + } catch (error) { + return { + success: false, + error: error.response?.data?.error?.message || error.message, + }; + } +} + +module.exports = { chat, getModels }; diff --git a/plugin/lib/quickcomposer/ai/index.js b/plugin/lib/quickcomposer/ai/index.js new file mode 100644 index 0000000..d4af17c --- /dev/null +++ b/plugin/lib/quickcomposer/ai/index.js @@ -0,0 +1,6 @@ +const { chat, getModels } = require("./chat"); + +module.exports = { + chat, + getModels, +}; diff --git a/plugin/plugin.json b/plugin/plugin.json index 2ca140a..09e9b6b 100644 --- a/plugin/plugin.json +++ b/plugin/plugin.json @@ -1,6 +1,6 @@ { "pluginName": "快捷命令", - "description": "实现具备UI交互的自动化操作,支持可视化拖拽及直接编写脚本两种形式。1.可视化拖拽:支持文件、网络、音视频、图片、文本、浏览器、键鼠等超过20种类型的自动化处理,2.编写脚本:支持utools的api,python、js、shell、cmd等多种脚本语言。关联关键词:自动化、可视化、RPA", + "description": "实现具备UI交互的自动化操作,支持可视化拖拽及直接编写脚本两种形式。1.可视化拖拽:支持文件、网络、音视频、图片、文本、浏览器、键鼠、AI对话等超过20种类型的自动化处理,2.编写脚本:支持utools的api,python、js、shell、cmd等多种脚本语言。关联关键词:自动化、可视化、RPA", "main": "index.html", "homepage": "https://github.com/fofolee/uTools-quickcommand", "publishPage": "https://yuanliao.info/d/424", diff --git a/src/js/composer/commands/aiCommands.js b/src/js/composer/commands/aiCommands.js new file mode 100644 index 0000000..ead3afe --- /dev/null +++ b/src/js/composer/commands/aiCommands.js @@ -0,0 +1,175 @@ +import { newVarInputVal } from "js/composer/varInputValManager"; + +export const aiCommands = { + label: "AI操作", + icon: "smart_toy", + defaultOpened: false, + commands: [ + { + value: "quickcomposer.ai.getModels", + label: "获取可用模型", + desc: "获取API支持的模型列表", + asyncMode: "await", + icon: "list", + showLoading: true, + config: [ + { + label: "API配置", + component: "OptionEditor", + icon: "settings", + width: 12, + options: { + modelType: { + component: "ButtonGroup", + width: 12, + height: "26px", + options: [ + { label: "OpenAI", value: "openai" }, + { label: "Ollama", value: "ollama" }, + ], + }, + apiUrl: { + label: "API地址", + component: "VariableInput", + icon: "link", + width: 12, + placeholder: "输入API地址", + }, + apiToken: { + label: "API令牌", + component: "VariableInput", + icon: "key", + width: 12, + placeholder: "ollama 则留空", + }, + }, + defaultValue: { + modelType: "openai", + apiUrl: newVarInputVal("str", "https://api.openai.com/v1/models"), + }, + }, + ], + outputs: { + label: "获取模型列表结果", + suggestName: "modelListResult", + structure: { + success: { + label: "是否成功", + suggestName: "isSuccess", + }, + result: { + label: "模型列表", + suggestName: "modelList", + }, + error: { + label: "错误信息", + suggestName: "resultErrorInfo", + }, + }, + }, + }, + { + value: "quickcomposer.ai.chat", + label: "AI对话", + desc: "与AI助手进行对话", + asyncMode: "await", + icon: "chat", + showLoading: true, + config: [ + { + label: "API配置", + component: "OptionEditor", + icon: "settings", + width: 12, + options: { + modelType: { + component: "ButtonGroup", + width: 12, + height: "26px", + options: [ + { label: "OpenAI", value: "openai" }, + { label: "Ollama", value: "ollama" }, + ], + }, + apiUrl: { + label: "API地址", + component: "VariableInput", + icon: "link", + width: 12, + placeholder: "输入API地址", + }, + apiToken: { + label: "API令牌", + component: "VariableInput", + icon: "key", + width: 6, + placeholder: "ollama 则留空", + }, + model: { + label: "模型名称", + component: "VariableInput", + icon: "smart_toy", + width: 6, + placeholder: "如 gpt-3.5-turbo", + }, + }, + defaultValue: { + modelType: "openai", + apiUrl: newVarInputVal( + "str", + "https://api.openai.com/v1/chat/completions" + ), + model: newVarInputVal("str", "gpt-3.5-turbo"), + }, + }, + { + label: "对话内容", + component: "OptionEditor", + icon: "chat", + width: 12, + options: { + presetPrompt: { + component: "ButtonGroup", + width: 12, + height: "26px", + options: [ + { label: "自由对话", value: "" }, + { label: "翻译", value: "translate" }, + { label: "总结", value: "summarize" }, + { label: "生成SHELL命令", value: "shell" }, + ], + }, + prompt: { + label: "提示词", + component: "VariableInput", + icon: "edit", + width: 12, + placeholder: "输入要询问AI的内容", + }, + }, + defaultValue: { + presetPrompt: "", + }, + }, + ], + outputs: { + label: "AI响应", + suggestName: "aiResponse", + structure: { + success: { + label: "是否成功", + suggestName: "isAiResponseSuccess", + }, + result: { + label: "响应内容", + suggestName: "aiResponseContent", + }, + error: { + label: "错误信息", + suggestName: "aiResponseError", + }, + }, + }, + }, + ], +}; diff --git a/src/js/composer/commands/audioCommands.js b/src/js/composer/commands/audioCommands.js index 5fe8702..4596171 100644 --- a/src/js/composer/commands/audioCommands.js +++ b/src/js/composer/commands/audioCommands.js @@ -1,5 +1,3 @@ -import { newVarInputVal } from "js/composer/varInputValManager"; - // 系统音效选项 const SYSTEM_SOUNDS = [ { label: "提示音", value: "beep" }, diff --git a/src/js/composer/commands/index.js b/src/js/composer/commands/index.js index 46ea57d..ddba40b 100644 --- a/src/js/composer/commands/index.js +++ b/src/js/composer/commands/index.js @@ -20,6 +20,7 @@ import { macosCommands } from "./macosCommands"; import { scriptCommands } from "./scriptCommands"; import { browserCommands } from "./browserCommands"; import { videoCommands } from "./videoCommands"; +import { aiCommands } from "./aiCommands"; export const commandCategories = [ fileCommands, @@ -38,6 +39,7 @@ export const commandCategories = [ scriptCommands, uiCommands, simulateCommands, + aiCommands, statusCommands, mathCommands, userdataCommands, diff --git a/src/plugins/monaco/types/quickcomposer.d.ts b/src/plugins/monaco/types/quickcomposer.d.ts index 3002208..fcb5dc7 100644 --- a/src/plugins/monaco/types/quickcomposer.d.ts +++ b/src/plugins/monaco/types/quickcomposer.d.ts @@ -2512,4 +2512,100 @@ interface quickcomposerApi { */ waitForElement(selector: string, timeout?: number): Promise; }; + + /** + * AI 相关功能 + */ + ai: { + /** + * 与 AI 进行对话 + * @param apiConfig API配置 + * @param content 对话内容 + * @example + * // OpenAI 示例 + * const response = await quickcomposer.ai.chat( + * { + * modelType: "openai", + * apiUrl: "https://api.openai.com/v1/chat/completions", + * apiToken: "your-api-token", + * model: "gpt-3.5-turbo" + * }, + * { + * prompt: "你好", + * presetPrompt: "" // 使用预设提示词:translate/shell/summarize + * } + * ); + * + * // Ollama 示例 + * const response = await quickcomposer.ai.chat( + * { + * modelType: "ollama", + * apiUrl: "http://localhost:11434/api/generate", + * model: "qwen2.5:32b" + * }, + * { + * prompt: "查找进程名为chrome的进程并关闭", + * presetPrompt: "shell" + * } + * ); + */ + chat( + apiConfig: { + /** 模型类型:openai/ollama */ + modelType: "openai" | "ollama"; + /** API地址 */ + apiUrl: string; + /** API令牌(仅 OpenAI 需要) */ + apiToken?: string; + /** 模型名称 */ + model: string; + }, + content: { + /** 提示词 */ + prompt: string; + /** 预设提示词类型 */ + presetPrompt?: "" | "translate" | "shell" | "summarize"; + } + ): Promise<{ + /** 是否成功 */ + success: boolean; + /** AI 响应内容 */ + result?: string; + /** 错误信息 */ + error?: string; + }>; + + /** + * 获取 API 支持的模型列表 + * @param apiConfig API配置 + * @example + * // OpenAI 示例 + * const models = await quickcomposer.ai.getModels({ + * modelType: "openai", + * apiUrl: "https://api.openai.com/v1/models", + * apiToken: "your-api-token" + * }); + * + * // Ollama 示例 + * const models = await quickcomposer.ai.getModels({ + * modelType: "ollama", + * apiUrl: "http://localhost:11434" + * }); + */ + getModels(apiConfig: { + /** 模型类型:openai/ollama */ + modelType: "openai" | "ollama"; + /** API地址 */ + apiUrl: string; + /** API令牌(仅 OpenAI 需要) */ + apiToken?: string; + }): Promise<{ + /** 是否成功 */ + success: boolean; + /** 模型名称列表 */ + result?: string[]; + /** 错误信息 */ + error?: string; + }>; + }; }