diff --git a/global.d.ts b/global.d.ts index 36f4069..ca0e964 100644 --- a/global.d.ts +++ b/global.d.ts @@ -214,13 +214,7 @@ declare namespace Bob { // https://ripperhe.gitee.io/bob/#/plugin/api/option type Option = { - apiKeys: string; - apiUrl: string; - customSystemPrompt: string; - customUserPrompt: string; - deploymentName: string; - model: string; - polishingMode: "simplicity" | "detailed"; + [propName: string]: string; }; diff --git a/src/info.json b/src/info.json index d3b70d3..6c654a5 100644 --- a/src/info.json +++ b/src/info.json @@ -25,11 +25,22 @@ "identifier": "deploymentName", "type": "text", "title": "Dep. Name", - "desc": "可选项。此值为在部署模型时为部署选择的自定义名称,可在 Azure 门户中的 “资源管理“>“部署“下查看", + "desc": "可选项。此值为在部署 Azure 模型时为部署选择的自定义名称,可在 Azure 门户中的 “资源管理”>“部署” 下查看", "textConfig": { "type": "visible" } }, + { + "identifier": "apiVersion", + "type": "text", + "title": "API Version", + "defaultValue": "2023-03-15-preview", + "desc": "可选项。此值为在使用 Azure 模型时采用的 Chat completions API 版本,不支持 2023-03-15-preview 之前的版本", + "textConfig": { + "type": "visible", + "placeholderText": "2023-03-15-preview" + } + }, { "identifier": "apiKeys", "type": "text", @@ -47,6 +58,10 @@ "title": "模型", "defaultValue": "gpt-3.5-turbo-0613", "menuValues": [ + { + "title": "custom", + "value": "custom" + }, { "title": "gpt-3.5-turbo-0613 (recommended)", "value": "gpt-3.5-turbo-0613" @@ -86,17 +101,19 @@ { "title": "gpt-4-32k-0613", "value": "gpt-4-32k-0613" - }, - { - "title": "text-davinci-003", - "value": "text-davinci-003" - }, - { - "title": "text-davinci-002", - "value": "text-davinci-002" } ] }, + { + "identifier": "customModel", + "type": "text", + "title": "自定义模型", + "desc": "可选项。当 Model 选择为 custom 时,此项为必填项。请填写有效的模型名称", + "textConfig": { + "type": "visible", + "placeholderText": "gpt-3.5-turbo" + } + }, { "identifier": "customSystemPrompt", "type": "text", diff --git a/src/main.js b/src/main.js index 80c23c2..bcbfb71 100644 --- a/src/main.js +++ b/src/main.js @@ -1,18 +1,6 @@ //@ts-check var lang = require("./lang.js"); -var ChatGPTModels = [ - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-0301", - "gpt-3.5-turbo-0613", - "gpt-4", - "gpt-4-0314", - "gpt-4-0613", - "gpt-4-32k", - "gpt-4-32k-0314", - "gpt-4-32k-0613", -]; var HttpErrorCodes = { "400": "Bad Request", "401": "Unauthorized", @@ -85,7 +73,7 @@ function buildHeader(isAzureServiceProvider, apiKey) { /** * @param {string} basePrompt - * @param {"simplicity" | "detailed"} polishingMode + * @param {string} polishingMode * @param {Bob.TranslateQuery} query * @returns {string} */ @@ -150,11 +138,10 @@ function replacePromptKeywords(prompt, query) { } /** - * @param {typeof ChatGPTModels[number]} model - * @param {boolean} isChatGPTModel + * @param {string} model * @param {Bob.TranslateQuery} query * @returns {{ - * model: typeof ChatGPTModels[number]; + * model: string; * temperature: number; * max_tokens: number; * top_p: number; @@ -167,14 +154,14 @@ function replacePromptKeywords(prompt, query) { * prompt?: string; * }} */ -function buildRequestBody(model, isChatGPTModel, query) { +function buildRequestBody(model, query) { const { customSystemPrompt, customUserPrompt, polishingMode } = $option; const systemPrompt = generateSystemPrompt(replacePromptKeywords(customSystemPrompt, query), polishingMode, query); const userPrompt = customUserPrompt ? `${replacePromptKeywords(customUserPrompt, query)}:\n\n"${query.text}"` : query.text; const standardBody = { - model, + model: model, stream: true, temperature: 0.2, max_tokens: 1000, @@ -183,24 +170,19 @@ function buildRequestBody(model, isChatGPTModel, query) { presence_penalty: 1, }; - if (isChatGPTModel) { - return { - ...standardBody, - messages: [ - { - role: "system", - content: systemPrompt, - }, - { - role: "user", - content: userPrompt, - }, - ], - }; - } return { ...standardBody, - prompt: `${systemPrompt}\n\n${userPrompt}`, + model: model, + messages: [ + { + role: "system", + content: systemPrompt, + }, + { + role: "user", + content: userPrompt, + }, + ], }; } @@ -223,12 +205,11 @@ function handleError(query, result) { /** * @param {Bob.TranslateQuery} query - * @param {boolean} isChatGPTModel * @param {string} targetText * @param {string} textFromResponse * @returns {string} */ -function handleResponse(query, isChatGPTModel, targetText, textFromResponse) { +function handleResponse(query, targetText, textFromResponse) { if (textFromResponse !== '[DONE]') { try { const dataObj = JSON.parse(textFromResponse); @@ -244,7 +225,7 @@ function handleResponse(query, isChatGPTModel, targetText, textFromResponse) { return targetText; } - const content = isChatGPTModel ? choices[0].delta.content : choices[0].text; + const content = choices[0].delta.content; if (content !== undefined) { targetText += content; query.onStream({ @@ -282,7 +263,18 @@ function translate(query, completion) { }); } - const { model, apiKeys, apiUrl, deploymentName } = $option; + const { model, customModel, apiKeys, apiVersion, apiUrl, deploymentName } = $option; + + const isCustomModelRequired = model === "custom"; + if (isCustomModelRequired && !customModel) { + query.onCompletion({ + error: { + type: "param", + message: "配置错误 - 请确保您在插件配置中填入了正确的自定义模型名称", + addtion: "请在插件配置中填写自定义模型名称", + }, + }); + } if (!apiKeys) { completion({ @@ -293,20 +285,22 @@ function translate(query, completion) { }, }); } + + const modelValue = isCustomModelRequired ? customModel : model; + const trimmedApiKeys = apiKeys.endsWith(",") ? apiKeys.slice(0, -1) : apiKeys; const apiKeySelection = trimmedApiKeys.split(",").map(key => key.trim()); const apiKey = apiKeySelection[Math.floor(Math.random() * apiKeySelection.length)]; const modifiedApiUrl = ensureHttpsAndNoTrailingSlash(apiUrl || "https://api.openai.com"); - const isChatGPTModel = ChatGPTModels.includes(model); const isAzureServiceProvider = modifiedApiUrl.includes("openai.azure.com"); - let apiUrlPath = isChatGPTModel ? "/v1/chat/completions" : "/v1/completions"; + let apiUrlPath = "/v1/chat/completions"; + const apiVersionQuery = apiVersion ? `?api-version=${apiVersion}` : "?api-version=2023-03-15-preview"; if (isAzureServiceProvider) { if (deploymentName) { - apiUrlPath = `/openai/deployments/${deploymentName}`; - apiUrlPath += isChatGPTModel ? "/chat/completions?api-version=2023-03-15-preview" : "/completions?api-version=2022-12-01"; + apiUrlPath = `/openai/deployments/${deploymentName}/chat/completions${apiVersionQuery}`; } else { completion({ error: { @@ -319,7 +313,7 @@ function translate(query, completion) { } const header = buildHeader(isAzureServiceProvider, apiKey); - const body = buildRequestBody(model, isChatGPTModel, query); + const body = buildRequestBody(modelValue, query); let targetText = ""; // 初始化拼接结果变量 let buffer = ""; // 新增 buffer 变量 @@ -348,7 +342,7 @@ function translate(query, completion) { if (match) { // 如果是一个完整的消息,处理它并从缓冲变量中移除 const textFromResponse = match[1].trim(); - targetText = handleResponse(query, isChatGPTModel, targetText, textFromResponse); + targetText = handleResponse(query, targetText, textFromResponse); buffer = buffer.slice(match[0].length); } else { // 如果没有完整的消息,等待更多的数据