mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-12-15 23:54:35 +08:00
Compare commits
27 Commits
5.0.3
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8865d42c4e | ||
|
|
2625a25584 | ||
|
|
724bd9e4e7 | ||
|
|
72abdf4524 | ||
|
|
b400bbb48d | ||
|
|
c2514e9f2d | ||
|
|
c32a5a4829 | ||
|
|
0d4f49fcf4 | ||
|
|
55516159ba | ||
|
|
d4e58e58be | ||
|
|
d1b117186f | ||
|
|
3fb17dcd99 | ||
|
|
ffbae3f33f | ||
|
|
a762b87d2b | ||
|
|
3d2d15e177 | ||
|
|
14769bb7e7 | ||
|
|
5d76d4d657 | ||
|
|
ebde8999bf | ||
|
|
31f0d66ebc | ||
|
|
c1f86c20d2 | ||
|
|
bbdc2c6d65 | ||
|
|
0979e5648c | ||
|
|
f9a22595be | ||
|
|
823a95079a | ||
|
|
39ee88b02a | ||
|
|
fcf3d5912e | ||
|
|
f61fe17c6a |
4
build.sh
Executable file
4
build.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
git pull
|
||||
cd plugin && npm i && cd .. && npm i
|
||||
quasar build
|
||||
4
dev.sh
Executable file
4
dev.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
git pull
|
||||
cd plugin && npm i && cd .. && npm i
|
||||
quasar dev
|
||||
144
plugin/lib/ai.js
144
plugin/lib/ai.js
@@ -17,6 +17,7 @@ window.aiResponseParser = (content) => {
|
||||
const API_TYPES = {
|
||||
OPENAI: "openai",
|
||||
OLLAMA: "ollama",
|
||||
UTOOLS: "utools",
|
||||
};
|
||||
|
||||
// 角色提示词
|
||||
@@ -122,7 +123,7 @@ function buildRequestData(content, apiConfig) {
|
||||
const roleMessage = rolePrompt
|
||||
? [
|
||||
{
|
||||
role: "user",
|
||||
role: "system",
|
||||
content: rolePrompt,
|
||||
},
|
||||
]
|
||||
@@ -151,21 +152,6 @@ function buildRequestData(content, apiConfig) {
|
||||
};
|
||||
}
|
||||
|
||||
// 处理普通响应
|
||||
function parseResponse(response, apiType) {
|
||||
if (apiType === API_TYPES.OPENAI) {
|
||||
if (!response.data.choices || !response.data.choices[0]) {
|
||||
throw new Error("OpenAI 响应格式错误");
|
||||
}
|
||||
return response.data.choices[0].message.content;
|
||||
} else {
|
||||
if (!response.data.message) {
|
||||
throw new Error("Ollama 响应格式错误");
|
||||
}
|
||||
return response.data.message.content;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理模型列表响应
|
||||
function parseModelsResponse(response, apiType) {
|
||||
if (apiType === API_TYPES.OPENAI) {
|
||||
@@ -181,6 +167,24 @@ function parseModelsResponse(response, apiType) {
|
||||
}
|
||||
}
|
||||
|
||||
let reasoning_content_start = false;
|
||||
function processContentWithReason(response, onStream) {
|
||||
if (response.reasoning_content) {
|
||||
if (!reasoning_content_start) {
|
||||
reasoning_content_start = true;
|
||||
onStream("<think>", false);
|
||||
}
|
||||
onStream(response.reasoning_content, false);
|
||||
}
|
||||
if (response.content) {
|
||||
if (reasoning_content_start) {
|
||||
reasoning_content_start = false;
|
||||
onStream("</think>", false);
|
||||
}
|
||||
onStream(response.content, false);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理 OpenAI 流式响应
|
||||
async function handleOpenAIStreamResponse(line, onStream) {
|
||||
if (line.startsWith("data:")) {
|
||||
@@ -190,9 +194,9 @@ async function handleOpenAIStreamResponse(line, onStream) {
|
||||
return;
|
||||
}
|
||||
const json = JSON.parse(jsonStr);
|
||||
const content = json.choices[0]?.delta?.content;
|
||||
if (content) {
|
||||
onStream(content, false);
|
||||
const response = json.choices[0]?.delta;
|
||||
if (response) {
|
||||
processContentWithReason(response, onStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,13 +208,30 @@ async function handleOllamaStreamResponse(line, onStream) {
|
||||
onStream("", true);
|
||||
return;
|
||||
}
|
||||
if (json.message?.content) {
|
||||
onStream(json.message.content, false);
|
||||
const response = json.message;
|
||||
if (response) {
|
||||
processContentWithReason(response, onStream);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理 uTools AI 流式响应
|
||||
async function handleUToolsAIStreamResponse(response, onStream) {
|
||||
processContentWithReason(response, onStream);
|
||||
}
|
||||
|
||||
// 处理流式响应
|
||||
async function handleStreamResponse(response, apiConfig, onStream) {
|
||||
// 处理 uTools AI 响应
|
||||
if (apiConfig.apiType === API_TYPES.UTOOLS) {
|
||||
try {
|
||||
await handleUToolsAIStreamResponse(response, onStream);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理其他 API 的流式响应
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = "";
|
||||
@@ -283,24 +304,27 @@ async function chat(content, apiConfig, options = {}) {
|
||||
} = options;
|
||||
|
||||
// 验证必要参数
|
||||
if (!apiConfig.apiUrl || !content.prompt || !apiConfig.model) {
|
||||
throw new Error("API地址、模型名称和提示词不能为空");
|
||||
if (apiConfig.apiType === API_TYPES.UTOOLS) {
|
||||
if (!content.prompt || !apiConfig.model) {
|
||||
throw new Error("模型名称和提示词不能为空");
|
||||
}
|
||||
} else {
|
||||
if (!apiConfig.apiUrl) {
|
||||
throw new Error("API地址不能为空");
|
||||
}
|
||||
if (!apiConfig.apiUrl || !content.prompt || !apiConfig.model) {
|
||||
throw new Error("API地址、模型名称和提示词不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
// 构建请求URL和配置
|
||||
const url = buildApiUrl(
|
||||
apiConfig.apiUrl,
|
||||
API_ENDPOINTS[apiConfig.apiType].chat
|
||||
);
|
||||
const config = buildRequestConfig(apiConfig);
|
||||
const requestData = buildRequestData(content, apiConfig);
|
||||
let controller;
|
||||
|
||||
// 显示进度条
|
||||
const processBar = showProcessBar
|
||||
? await quickcommand.showProcessBar({
|
||||
text: "AI思考中...",
|
||||
onClose: () => {
|
||||
if (controller) {
|
||||
if (typeof controller !== "undefined") {
|
||||
controller.abort();
|
||||
}
|
||||
},
|
||||
@@ -327,11 +351,65 @@ async function chat(content, apiConfig, options = {}) {
|
||||
onStream(chunk, isDone);
|
||||
};
|
||||
|
||||
// 统一使用 fetch 处理请求
|
||||
const controller = new AbortController();
|
||||
// 处理 uTools AI 请求
|
||||
if (apiConfig.apiType === API_TYPES.UTOOLS) {
|
||||
try {
|
||||
const messages = buildRequestData(content, apiConfig).messages;
|
||||
controller = utools.ai(
|
||||
{
|
||||
model: apiConfig.model,
|
||||
messages: messages,
|
||||
},
|
||||
(chunk) => {
|
||||
handleUToolsAIStreamResponse(chunk, streamHandler);
|
||||
}
|
||||
);
|
||||
onFetch(controller);
|
||||
|
||||
await controller;
|
||||
|
||||
// 在流式响应完全结束后,发送一个空字符串表示结束
|
||||
streamHandler("", true);
|
||||
|
||||
// 完成时更新进度条并关闭
|
||||
if (processBar) {
|
||||
quickcommand.updateProcessBar(
|
||||
{
|
||||
text: "AI响应完成",
|
||||
complete: true,
|
||||
},
|
||||
processBar
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
result: fullResponse,
|
||||
};
|
||||
} catch (error) {
|
||||
if (error.name === "AbortError") {
|
||||
return {
|
||||
success: false,
|
||||
error: "请求已取消",
|
||||
cancelled: true,
|
||||
};
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 统一使用 fetch 处理其他 API 请求
|
||||
controller = new AbortController();
|
||||
|
||||
onFetch(controller);
|
||||
|
||||
const url = buildApiUrl(
|
||||
apiConfig.apiUrl,
|
||||
API_ENDPOINTS[apiConfig.apiType].chat
|
||||
);
|
||||
const config = buildRequestConfig(apiConfig);
|
||||
const requestData = buildRequestData(content, apiConfig);
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: config.headers,
|
||||
|
||||
@@ -520,6 +520,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
if (dialogType === "textarea" && !e.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
// select 类型有自己的键盘处理器,不需要全局处理器处理 Enter 键
|
||||
if (dialogType === "select") {
|
||||
return;
|
||||
}
|
||||
document.getElementById("ok-btn").click();
|
||||
}
|
||||
});
|
||||
|
||||
331
plugin/package-lock.json
generated
331
plugin/package-lock.json
generated
@@ -5,7 +5,7 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"axios": "^1.12.0",
|
||||
"chrome-remote-interface": "^0.33.2",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dompurify": "^3.2.4",
|
||||
@@ -15,7 +15,7 @@
|
||||
"node-forge": "^1.3.1",
|
||||
"pinyin-match": "^1.2.6",
|
||||
"png2icons": "^2.0.1",
|
||||
"ses": "^1.10.0",
|
||||
"ses": "^1.12.0",
|
||||
"sm-crypto": "^0.3.13",
|
||||
"tree-kill": "^1.2.2"
|
||||
}
|
||||
@@ -36,20 +36,30 @@
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.9",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
|
||||
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
|
||||
"license": "MIT",
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.0.tgz",
|
||||
"integrity": "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/chrome-remote-interface": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.33.2.tgz",
|
||||
@@ -66,7 +76,6 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
@@ -89,7 +98,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
@@ -103,6 +111,60 @@
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/exif-reader": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/exif-reader/-/exif-reader-2.0.1.tgz",
|
||||
@@ -130,19 +192,110 @@
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
|
||||
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
|
||||
"license": "MIT",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
@@ -172,11 +325,18 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -185,7 +345,6 @@
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
@@ -229,9 +388,9 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"node_modules/ses": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/ses/-/ses-1.10.0.tgz",
|
||||
"integrity": "sha512-HXmJbNEgY/4hsQfaz5dna39vVKNyvlElRmJYk+bjTqSXSElT0Hr6NKwWVg4j0TxP6IuHp/PNMoWJKIRXzmLbAQ==",
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ses/-/ses-1.12.0.tgz",
|
||||
"integrity": "sha512-jvmwXE2lFxIIY1j76hFjewIIhYMR9Slo3ynWZGtGl5M7VUCw3EA0wetS+JCIbl2UcSQjAT0yGAHkyxPJreuC9w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@endo/env-options": "^1.1.8"
|
||||
@@ -293,15 +452,24 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.7.9",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
|
||||
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.0.tgz",
|
||||
"integrity": "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"requires": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"chrome-remote-interface": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.33.2.tgz",
|
||||
@@ -342,6 +510,45 @@
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
}
|
||||
},
|
||||
"dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"requires": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="
|
||||
},
|
||||
"es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="
|
||||
},
|
||||
"es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"requires": {
|
||||
"es-errors": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"requires": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"exif-reader": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/exif-reader/-/exif-reader-2.0.1.tgz",
|
||||
@@ -353,15 +560,74 @@
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
|
||||
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"requires": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"requires": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="
|
||||
},
|
||||
"has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"requires": {
|
||||
"has-symbols": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
@@ -380,6 +646,11 @@
|
||||
"resolved": "https://registry.npmmirror.com/marked/-/marked-15.0.7.tgz",
|
||||
"integrity": "sha512-dgLIeKGLx5FwziAnsk4ONoGwHwGPJzselimvlVskE9XLN4Orv9u2VA3GWw/lYUqjfA0rUT/6fqKwfZJapP9BEg=="
|
||||
},
|
||||
"math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
@@ -419,9 +690,9 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"ses": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/ses/-/ses-1.10.0.tgz",
|
||||
"integrity": "sha512-HXmJbNEgY/4hsQfaz5dna39vVKNyvlElRmJYk+bjTqSXSElT0Hr6NKwWVg4j0TxP6IuHp/PNMoWJKIRXzmLbAQ==",
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ses/-/ses-1.12.0.tgz",
|
||||
"integrity": "sha512-jvmwXE2lFxIIY1j76hFjewIIhYMR9Slo3ynWZGtGl5M7VUCw3EA0wetS+JCIbl2UcSQjAT0yGAHkyxPJreuC9w==",
|
||||
"requires": {
|
||||
"@endo/env-options": "^1.1.8"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"axios": "^1.12.0",
|
||||
"chrome-remote-interface": "^0.33.2",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dompurify": "^3.2.4",
|
||||
@@ -10,7 +10,7 @@
|
||||
"node-forge": "^1.3.1",
|
||||
"pinyin-match": "^1.2.6",
|
||||
"png2icons": "^2.0.1",
|
||||
"ses": "^1.10.0",
|
||||
"ses": "^1.12.0",
|
||||
"sm-crypto": "^0.3.13",
|
||||
"tree-kill": "^1.2.2"
|
||||
}
|
||||
|
||||
17
src/App.vue
17
src/App.vue
@@ -16,6 +16,8 @@ import programmings from "./js/options/programs.js";
|
||||
import defaultProfile from "./js/options/defaultProfile.js";
|
||||
import Cron from "croner";
|
||||
import QuickCommand from "components/quickcommandUI/QuickCommand";
|
||||
import { generateFlowsCode } from "js/composer/generateCode";
|
||||
|
||||
// import autoDetach from "./js/autoDetach.js";
|
||||
|
||||
export default defineComponent({
|
||||
@@ -157,10 +159,13 @@ export default defineComponent({
|
||||
reslove([`超过${timeout}ms未响应`]);
|
||||
}, timeout);
|
||||
let command = dbManager.getDB("qc_" + featureCode);
|
||||
let commandCode = command.cmd;
|
||||
let commandCode =
|
||||
command.program === "quickcomposer"
|
||||
? generateFlowsCode(command.flows)
|
||||
: command.cmd;
|
||||
if (mainInput)
|
||||
commandCode = commandCode.replace(/\{\{input\}\}/g, mainInput);
|
||||
if (command.program === "quickcommand") {
|
||||
if (["quickcommand", "quickcomposer"].includes(command.program)) {
|
||||
window.runCodeInSandbox(commandCode, (stdout, stderr) => {
|
||||
stderr && reslove([stderr.toString()]);
|
||||
reslove(stdout);
|
||||
@@ -168,10 +173,10 @@ export default defineComponent({
|
||||
} else {
|
||||
let option =
|
||||
command.program === "custom"
|
||||
? command.customOptions
|
||||
: this.programs[command.program];
|
||||
option.scptarg = command.scptarg;
|
||||
option.charset = command.charset;
|
||||
? command.customOptions || {}
|
||||
: this.programs[command.program] || {};
|
||||
option.scptarg = command.scptarg || "";
|
||||
option.charset = command.charset || {};
|
||||
window.runCodeFile(
|
||||
commandCode,
|
||||
option,
|
||||
|
||||
@@ -170,8 +170,8 @@ export default {
|
||||
getCommandOpt(command) {
|
||||
let option =
|
||||
command.program === "custom"
|
||||
? command.customOptions
|
||||
: programs[command.program];
|
||||
? command.customOptions || {}
|
||||
: programs[command.program] || {};
|
||||
option.scptarg = command.scptarg || "";
|
||||
option.charset = command.charset || {};
|
||||
option.envPath = this.$root.nativeProfile.envPath.trim() || "";
|
||||
|
||||
@@ -213,7 +213,7 @@ export default defineComponent({
|
||||
const response = await window.quickcommand.askAI(
|
||||
{
|
||||
prompt: promptText,
|
||||
context: [...presetContext, ...this.chatHistory.slice(0, -2)],
|
||||
context: [presetContext, ...this.chatHistory.slice(0, -2)],
|
||||
},
|
||||
this.selectedApi,
|
||||
{
|
||||
@@ -291,7 +291,7 @@ export default defineComponent({
|
||||
shell: "liunx shell脚本",
|
||||
};
|
||||
const languageName = languageMap[language] || language;
|
||||
const commonInstructions = `接下来我所有的对话中的需求都请通过编写${languageName}代码来实现,并请遵循以下原则:
|
||||
const commonInstructions = `接下来所有的对话中的需求都请通过编写${languageName}代码来实现,并请遵循以下原则:
|
||||
- 编写简洁、可读性强的代码
|
||||
- 遵循${languageName}最佳实践和设计模式
|
||||
- 使用恰当的命名规范和代码组织
|
||||
@@ -312,7 +312,7 @@ export default defineComponent({
|
||||
const specificInstructions = languageSpecific[language] || "";
|
||||
|
||||
const lastInstructions =
|
||||
"\n请直接给我MARKDOWN格式的代码(以```脚本语言开头,以```结尾),任何情况下都不需要做解释和说明";
|
||||
"\n请直接提供MARKDOWN格式的代码(以```脚本语言开头,以```结尾),任何情况下都不需要做解释和说明";
|
||||
|
||||
return commonInstructions + specificInstructions + lastInstructions;
|
||||
},
|
||||
@@ -330,48 +330,26 @@ export default defineComponent({
|
||||
];
|
||||
},
|
||||
getPresetContext() {
|
||||
let finnalPrompt = ""
|
||||
|
||||
const languagePrompt = this.getLanguagePrompt(this.language);
|
||||
|
||||
let presetContext = [
|
||||
{
|
||||
role: "user",
|
||||
content: languagePrompt,
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
content: "好的,我会严格按照你的要求编写代码。",
|
||||
},
|
||||
];
|
||||
finnalPrompt += languagePrompt;
|
||||
|
||||
if (this.submitDocs && this.language === "quickcommand") {
|
||||
const docs = this.getLanguageDocs(this.language);
|
||||
|
||||
presetContext.push(
|
||||
{
|
||||
role: "user",
|
||||
content: `你现在使用的是一种特殊的环境,支持uTools和quickcommand两种特殊的接口,请优先使用uTools和quickcommand接口解决需求,然后再使用当前语言通用的解决方案`,
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
content: "好的,我会注意。",
|
||||
}
|
||||
);
|
||||
finnalPrompt += `\n你现在使用的是一种特殊的环境,支持uTools和quickcommand两种特殊的接口,请优先使用uTools和quickcommand接口解决需求,然后再使用当前语言通用的解决方案`;
|
||||
|
||||
docs.forEach((doc) => {
|
||||
presetContext.push(
|
||||
{
|
||||
role: "user",
|
||||
content: `这是${doc.name}的API文档:\n${doc.api}`,
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
content: "好的,我会认真学习并记住这些接口。",
|
||||
}
|
||||
);
|
||||
finnalPrompt += `\n这是${doc.name}的API文档:\n${doc.api}`;
|
||||
});
|
||||
}
|
||||
|
||||
return presetContext;
|
||||
return {
|
||||
role: "system",
|
||||
content: finnalPrompt,
|
||||
};
|
||||
},
|
||||
openAIAssistantHelp() {
|
||||
window.showUb.help("#KUCwm");
|
||||
|
||||
@@ -2,25 +2,20 @@
|
||||
<q-card style="width: 800px" class="q-pa-sm">
|
||||
<div class="text-h5 q-my-md q-px-sm">API配置</div>
|
||||
<div>
|
||||
<div class="flex q-mb-md q-px-sm" style="height: 26px">
|
||||
<ButtonGroup
|
||||
v-model="apiToAdd"
|
||||
class="col"
|
||||
:options="[
|
||||
{ label: 'OPENAI', value: 'openai' },
|
||||
{ label: 'OLLAMA', value: 'ollama' },
|
||||
]"
|
||||
height="26px"
|
||||
/>
|
||||
<q-icon
|
||||
name="add_box"
|
||||
@click="addModel"
|
||||
<div class="q-pa-sm row q-gutter-sm">
|
||||
<q-btn
|
||||
v-for="option in aiOptions"
|
||||
:key="option.value"
|
||||
icon="add_link"
|
||||
dense
|
||||
color="primary"
|
||||
size="26px"
|
||||
class="cursor-pointer q-ml-sm"
|
||||
:label="option.label"
|
||||
@click="addModel(option.value)"
|
||||
class="col"
|
||||
/>
|
||||
</div>
|
||||
<q-scroll-area
|
||||
ref="scrollArea"
|
||||
:style="`height: ${getConfigListHeight()}px;`"
|
||||
class="q-px-sm"
|
||||
:vertical-thumb-style="{
|
||||
@@ -80,6 +75,7 @@
|
||||
? '例:https://api.openai.com'
|
||||
: '例:http://localhost:11434'
|
||||
"
|
||||
v-show="aiConfig.apiType !== 'utools'"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-badge
|
||||
@@ -179,21 +175,33 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
import { defineComponent, ref } from "vue";
|
||||
import { dbManager } from "js/utools.js";
|
||||
import ButtonGroup from "components/composer/common/ButtonGroup.vue";
|
||||
import draggable from "vuedraggable";
|
||||
import { getUniqueId } from "js/common/uuid.js";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AIConfig",
|
||||
components: {
|
||||
ButtonGroup,
|
||||
draggable,
|
||||
},
|
||||
setup() {
|
||||
const initAiOptions = utools.allAiModels
|
||||
? [{ label: "uTools内置AI", value: "utools" }]
|
||||
: [];
|
||||
|
||||
const aiOptions = ref([
|
||||
...initAiOptions,
|
||||
{ label: "OPENAI接口(需Key)", value: "openai" },
|
||||
{ label: "OLLAMA接口", value: "ollama" },
|
||||
]);
|
||||
|
||||
return {
|
||||
aiOptions,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
apiToAdd: "openai",
|
||||
aiConfigs: [],
|
||||
models: [],
|
||||
tokenInputTypes: [],
|
||||
@@ -202,6 +210,19 @@ export default defineComponent({
|
||||
emits: ["save"],
|
||||
methods: {
|
||||
async getModels(aiConfig) {
|
||||
if (aiConfig.apiType === "utools") {
|
||||
try {
|
||||
const models = await utools.allAiModels();
|
||||
this.models = models.map((model) => model.id);
|
||||
} catch (error) {
|
||||
quickcommand.showMessageBox(
|
||||
"获取 uTools AI 模型失败: " + error.message,
|
||||
"error"
|
||||
);
|
||||
this.models = [];
|
||||
}
|
||||
return;
|
||||
}
|
||||
const { success, result, error } = await window.getModelsFromAiApi(
|
||||
aiConfig
|
||||
);
|
||||
@@ -222,15 +243,22 @@ export default defineComponent({
|
||||
deleteModel(index) {
|
||||
this.aiConfigs.splice(index, 1);
|
||||
},
|
||||
addModel() {
|
||||
this.aiConfigs.push({
|
||||
addModel(apiType) {
|
||||
const defaultConfig = {
|
||||
id: getUniqueId(),
|
||||
apiType: this.apiToAdd,
|
||||
apiType: apiType,
|
||||
apiUrl: "",
|
||||
apiToken: "",
|
||||
model: "",
|
||||
name: "",
|
||||
});
|
||||
};
|
||||
|
||||
if (apiType === "utools") {
|
||||
defaultConfig.apiUrl = "";
|
||||
}
|
||||
|
||||
this.aiConfigs.unshift(defaultConfig);
|
||||
|
||||
},
|
||||
getConfigListHeight() {
|
||||
const counts = Math.min(this.aiConfigs.length, 3);
|
||||
|
||||
@@ -14,12 +14,15 @@
|
||||
bordered
|
||||
class="action-card cursor-pointer"
|
||||
:class="{
|
||||
'action-selected': selectedActionKeys.includes(actionKey),
|
||||
'action-selected': actionCount[actionKey] > 0,
|
||||
}"
|
||||
@click="toggleAction(actionKey)"
|
||||
@click="addAction(actionKey)"
|
||||
>
|
||||
<div class="q-pa-xs text-caption text-wrap text-center">
|
||||
{{ action.label }}
|
||||
<q-badge v-if="actionCount[actionKey]" color="primary" floating>
|
||||
{{ actionCount[actionKey] }}
|
||||
</q-badge>
|
||||
</div>
|
||||
</q-card>
|
||||
</div>
|
||||
@@ -38,7 +41,7 @@
|
||||
<q-chip
|
||||
square
|
||||
removable
|
||||
@remove="toggleAction(selectedActionKey)"
|
||||
@remove="removeAction(index)"
|
||||
class="text-caption q-mb-sm"
|
||||
:style="{
|
||||
paddingLeft: '7px',
|
||||
@@ -125,6 +128,13 @@ export default {
|
||||
selectedActionArgs() {
|
||||
return this.modelValue.map((x) => x.args);
|
||||
},
|
||||
actionCount() {
|
||||
const count = {};
|
||||
this.selectedActionKeys.forEach((key) => {
|
||||
count[key] = (count[key] || 0) + 1;
|
||||
});
|
||||
return count;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
moveAction(index, direction) {
|
||||
@@ -138,26 +148,25 @@ export default {
|
||||
this.$emit("update:model-value", newOperation);
|
||||
}
|
||||
},
|
||||
toggleAction(actionKey) {
|
||||
const index = this.selectedActionKeys.indexOf(actionKey);
|
||||
addAction(actionKey) {
|
||||
let newOperation = [...this.modelValue];
|
||||
if (index !== -1) {
|
||||
// 移除操作
|
||||
newOperation.splice(index, 1);
|
||||
} else {
|
||||
// 添加操作
|
||||
const { config, value } = this.operationsMap[actionKey];
|
||||
const args = config?.length
|
||||
? config.map((field) => field.defaultValue)
|
||||
: [];
|
||||
// 添加操作
|
||||
const { config, value } = this.operationsMap[actionKey];
|
||||
const args = config?.length
|
||||
? config.map((field) => field.defaultValue)
|
||||
: [];
|
||||
|
||||
const newOperationItem = { value, args };
|
||||
if (actionKey !== value) {
|
||||
newOperationItem.key = actionKey;
|
||||
}
|
||||
|
||||
newOperation.push(newOperationItem);
|
||||
const newOperationItem = { value, args };
|
||||
if (actionKey !== value) {
|
||||
newOperationItem.key = actionKey;
|
||||
}
|
||||
|
||||
newOperation.push(newOperationItem);
|
||||
this.$emit("update:model-value", newOperation);
|
||||
},
|
||||
removeAction(index) {
|
||||
let newOperation = [...this.modelValue];
|
||||
newOperation.splice(index, 1);
|
||||
this.$emit("update:model-value", newOperation);
|
||||
},
|
||||
updateActionArgs(argvIndex, argvVal, actionIndex) {
|
||||
@@ -250,4 +259,11 @@ export default {
|
||||
.row.q-col-gutter-xs > * {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.q-badge {
|
||||
font-size: 10px;
|
||||
padding: 2px 4px;
|
||||
right: -4px;
|
||||
top: -4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -114,9 +114,13 @@ export default {
|
||||
|
||||
return this.items.filter((x) => {
|
||||
if (this.is.json) {
|
||||
const titleMatch = window.pinyinMatch.match(x.title, this.searchWords);
|
||||
const titleMatch = window.pinyinMatch.match(
|
||||
x.title,
|
||||
this.searchWords
|
||||
);
|
||||
const descMatch =
|
||||
x.description && window.pinyinMatch.match(x.description, this.searchWords);
|
||||
x.description &&
|
||||
window.pinyinMatch.match(x.description, this.searchWords);
|
||||
return titleMatch || descMatch;
|
||||
} else {
|
||||
return window.pinyinMatch.match(x, this.searchWords);
|
||||
@@ -212,6 +216,7 @@ export default {
|
||||
this.searchWords = text;
|
||||
if (this.matchedItems.length < this.currentIndex + 1)
|
||||
this.currentIndex = 0;
|
||||
this.setUtoolsHeight(this.itemHeight * this.matchedItemsSize);
|
||||
}, this.options.options.placeholder);
|
||||
},
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ export const controlCommands = {
|
||||
{
|
||||
label: "结束",
|
||||
value: "end",
|
||||
codeTemplate: "}",
|
||||
codeTemplate: "};",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -112,7 +112,7 @@ export const controlCommands = {
|
||||
{
|
||||
label: "结束",
|
||||
value: "end",
|
||||
codeTemplate: "}",
|
||||
codeTemplate: "};",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -169,7 +169,7 @@ export const controlCommands = {
|
||||
{
|
||||
label: "结束",
|
||||
value: "end",
|
||||
codeTemplate: "}",
|
||||
codeTemplate: "};",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -225,7 +225,7 @@ export const controlCommands = {
|
||||
{
|
||||
label: "结束",
|
||||
value: "end",
|
||||
codeTemplate: "}",
|
||||
codeTemplate: "};",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -266,7 +266,7 @@ export const controlCommands = {
|
||||
{
|
||||
label: "结束",
|
||||
value: "end",
|
||||
codeTemplate: "}",
|
||||
codeTemplate: "};",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -320,7 +320,7 @@ export const controlCommands = {
|
||||
{
|
||||
label: "结束",
|
||||
value: "end",
|
||||
codeTemplate: "}",
|
||||
codeTemplate: "};",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -360,7 +360,7 @@ export const controlCommands = {
|
||||
{
|
||||
label: "结束",
|
||||
value: "end",
|
||||
codeTemplate: "}",
|
||||
codeTemplate: "};",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -4,13 +4,13 @@ export function generateCode(flow) {
|
||||
// 获取变量赋值代码,如果变量已经存在,则直接赋值,否则声明并赋值
|
||||
const getVarAssignCode = (varName, varValue) => {
|
||||
if (usedVarNames.includes(varName)) {
|
||||
return `${varName} = ${varValue};`;
|
||||
return `${varName} = ${varValue}`;
|
||||
}
|
||||
usedVarNames.push(varName);
|
||||
if (!varValue) {
|
||||
return `let ${varName};`;
|
||||
return `let ${varName}`;
|
||||
}
|
||||
return `let ${varName} = ${varValue};`;
|
||||
return `let ${varName} = ${varValue}`;
|
||||
};
|
||||
|
||||
const getVarByPath = (name, path) => {
|
||||
@@ -36,10 +36,11 @@ export function generateCode(flow) {
|
||||
);
|
||||
|
||||
const indent = " ";
|
||||
const comma = ";";
|
||||
|
||||
// 局部变量赋值
|
||||
manualVars.forEach((v) => {
|
||||
code.push(indent + getVarAssignCode(v.name, v.value));
|
||||
code.push(indent + getVarAssignCode(v.name, v.value) + comma);
|
||||
});
|
||||
|
||||
commands.forEach((cmd) => {
|
||||
@@ -65,7 +66,7 @@ export function generateCode(flow) {
|
||||
const extractVarCode = Object.entries(details)
|
||||
.map(
|
||||
([path, varName]) =>
|
||||
`let ${varName} = ${getVarByPath(promiseName, path)}`
|
||||
`let ${varName} = ${getVarByPath(promiseName, path)};`
|
||||
)
|
||||
.join("\n");
|
||||
|
||||
@@ -80,20 +81,22 @@ export function generateCode(flow) {
|
||||
})`;
|
||||
}
|
||||
}
|
||||
code.push(indent + cmdCode);
|
||||
code.push(indent + cmdCode + comma);
|
||||
} else if (cmd.asyncMode === "await") {
|
||||
// 使用 await 模式
|
||||
const promiseName = name || "__result";
|
||||
cmdCode = getVarAssignCode(promiseName, `await ${cmdCode}`);
|
||||
code.push(indent + cmdCode);
|
||||
code.push(indent + cmdCode + comma);
|
||||
// 处理详细变量
|
||||
if (details) {
|
||||
Object.entries(details).forEach(([path, varName]) => {
|
||||
code.push(
|
||||
`${indent}${getVarAssignCode(
|
||||
varName,
|
||||
getVarByPath(promiseName, path)
|
||||
)}`
|
||||
indent +
|
||||
`${getVarAssignCode(
|
||||
varName,
|
||||
getVarByPath(promiseName, path)
|
||||
)}` +
|
||||
comma
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -101,15 +104,17 @@ export function generateCode(flow) {
|
||||
// 非Async命令
|
||||
const resultVarName = name || "__result";
|
||||
cmdCode = getVarAssignCode(resultVarName, `${cmdCode}`);
|
||||
code.push(indent + cmdCode);
|
||||
code.push(indent + cmdCode + comma);
|
||||
// 处理详细变量
|
||||
if (details) {
|
||||
Object.entries(details).forEach(([path, varName]) => {
|
||||
code.push(
|
||||
`${indent}${getVarAssignCode(
|
||||
varName,
|
||||
getVarByPath(resultVarName, path)
|
||||
)}`
|
||||
indent +
|
||||
`${getVarAssignCode(
|
||||
varName,
|
||||
getVarByPath(resultVarName, path)
|
||||
)}` +
|
||||
comma
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -119,11 +124,11 @@ export function generateCode(flow) {
|
||||
if (cmd.asyncMode === "await") {
|
||||
cmdCode = `await ${cmdCode}`;
|
||||
}
|
||||
code.push(indent + cmdCode);
|
||||
code.push(indent + cmdCode + (cmd.isControlFlow ? "" : comma));
|
||||
}
|
||||
});
|
||||
|
||||
code.push("}"); // Close the function
|
||||
code.push("};"); // Close the function
|
||||
|
||||
// 如果是主函数,则自动执行
|
||||
if (funcName === "main") {
|
||||
|
||||
@@ -70,8 +70,6 @@ export function generateUBrowserCode(argvs) {
|
||||
// 添加其他操作
|
||||
if (argvs.operations?.length) {
|
||||
argvs.operations.forEach(({ value, args }) => {
|
||||
if (!args?.length) return;
|
||||
|
||||
const stringifiedArgs = args
|
||||
.map((arg) => stringifyArgv(arg))
|
||||
.filter(Boolean);
|
||||
|
||||
@@ -323,6 +323,19 @@ export const ubrowserOperationConfigs = {
|
||||
},
|
||||
],
|
||||
},
|
||||
markdown: {
|
||||
value: "markdown",
|
||||
label: "转markdown",
|
||||
icon: "get_app",
|
||||
config: [
|
||||
{
|
||||
label: "CSS 或 XPath 选择器,不传递则转换整个网页内容",
|
||||
icon: "find_in_page",
|
||||
component: "VariableInput",
|
||||
width: 12,
|
||||
},
|
||||
],
|
||||
},
|
||||
setCookies: {
|
||||
value: "setCookies",
|
||||
label: "设置Cookie",
|
||||
@@ -478,13 +491,13 @@ export const ubrowserOperationConfigs = {
|
||||
],
|
||||
},
|
||||
setValue: {
|
||||
value: "setValue",
|
||||
value: "value",
|
||||
label: "设置值",
|
||||
icon: "check_box",
|
||||
config: [
|
||||
{
|
||||
label: "元素选择器",
|
||||
icon: "varInput",
|
||||
icon: "find_in_page",
|
||||
component: "VariableInput",
|
||||
width: 6,
|
||||
},
|
||||
|
||||
133
src/plugins/monaco/types/utools.api.d.ts
vendored
133
src/plugins/monaco/types/utools.api.d.ts
vendored
@@ -138,6 +138,11 @@ interface UBrowser {
|
||||
* 配合 when 使用
|
||||
*/
|
||||
end(): this;
|
||||
/**
|
||||
* 转为markdown
|
||||
* @param selector CSS 或 XPath 选择器,不传递则转换整个网页内容
|
||||
*/
|
||||
markdown(selector: string): this;
|
||||
/**
|
||||
* 单击元素
|
||||
*/
|
||||
@@ -662,6 +667,134 @@ interface UToolsApi {
|
||||
isLinux(): boolean;
|
||||
|
||||
ubrowser: UBrowser;
|
||||
|
||||
/**
|
||||
* 调用 AI 能力,支持 Function Calling
|
||||
* @param option AI 选项
|
||||
* @param streamCallback 流式调用函数 (可选)
|
||||
* @returns 返回定制的 PromiseLike
|
||||
*/
|
||||
ai(option: AiOption): PromiseLike<Message>;
|
||||
ai(
|
||||
option: AiOption,
|
||||
streamCallback: (chunk: Message) => void
|
||||
): PromiseLike<void>;
|
||||
|
||||
/**
|
||||
* 获取所有 AI 模型
|
||||
* @returns 返回 AI 模型数组
|
||||
*/
|
||||
allAiModels(): Promise<AiModel[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* AI 选项接口
|
||||
*/
|
||||
interface AiOption {
|
||||
/**
|
||||
* AI 模型, 为空默认使用 deepseek-v3
|
||||
*/
|
||||
model?: string;
|
||||
/**
|
||||
* 消息列表
|
||||
*/
|
||||
messages: Message[];
|
||||
/**
|
||||
* 工具列表
|
||||
*/
|
||||
tools?: Tool[];
|
||||
}
|
||||
|
||||
/**
|
||||
* AI 消息接口
|
||||
*/
|
||||
interface Message {
|
||||
/**
|
||||
* 消息角色
|
||||
* system:系统消息
|
||||
* user:用户消息
|
||||
* assistant:AI 消息
|
||||
*/
|
||||
role: "system" | "user" | "assistant";
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
content?: string;
|
||||
/**
|
||||
* 消息推理内容,一般只有推理模型会返回
|
||||
*/
|
||||
reasoning_content?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* AI 工具接口
|
||||
*/
|
||||
interface Tool {
|
||||
/**
|
||||
* 工具类型
|
||||
* function:函数工具
|
||||
*/
|
||||
type: "function";
|
||||
/**
|
||||
* 函数工具配置
|
||||
*/
|
||||
function?: {
|
||||
/**
|
||||
* 函数名称
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 函数描述
|
||||
*/
|
||||
description: string;
|
||||
/**
|
||||
* 函数参数
|
||||
*/
|
||||
parameters: {
|
||||
type: "object";
|
||||
properties: Record<string, any>;
|
||||
};
|
||||
/**
|
||||
* 必填参数
|
||||
*/
|
||||
required?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* AI 模型接口
|
||||
*/
|
||||
interface AiModel {
|
||||
/**
|
||||
* AI 模型 ID,用于 utools.ai 调用的 model 参数
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* AI 模型名称
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
* AI 模型描述
|
||||
*/
|
||||
description: string;
|
||||
/**
|
||||
* AI 模型图标
|
||||
*/
|
||||
icon: string;
|
||||
/**
|
||||
* AI 模型调用消耗
|
||||
*/
|
||||
cost: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Promise 扩展类型,包含 abort() 函数
|
||||
*/
|
||||
interface PromiseLike<T> extends Promise<T> {
|
||||
/**
|
||||
* 中止 AI 调用
|
||||
*/
|
||||
abort(): void;
|
||||
}
|
||||
|
||||
declare var utools: UToolsApi;
|
||||
|
||||
Reference in New Issue
Block a user