技术人员常用的划词翻译插件及配置 ChatGPT 和代理服务
作为技术人员平时经常会翻看一些技术文档,而对应技术社区来说很多文档都是英文的,那毫无疑问翻译工具是少不了的。了不起常用的一个翻译工具叫划词翻译,是一个 Chrome
插件,日常看英文文档的遇到不懂的单词或者句子直接选中,然后点击一下图标就可以实现自动翻译。
翻译源
![0-6 0-6](https://yuandifly.com/wp-content/uploads/2023/09/0-6.jpg)
![0-10 0-10](https://yuandifly.com/wp-content/uploads/2023/09/0-10.jpg)
这个插件的翻译源有很多,如下所示
![0-7 0-7](https://yuandifly.com/wp-content/uploads/2023/09/0-7.jpg)
其中的翻译源的使用方式不完全相同,有一些不用任何配置就可以使用,比如 DeepL
和必应翻译,安装好插件就可以直接使用;
![0-8 0-8](https://yuandifly.com/wp-content/uploads/2023/09/0-8.jpg)
有一些需要解决网络问题才能正常使用,比如谷歌翻译,因为谷歌翻译已经退出中国了;
![0-9 0-9](https://yuandifly.com/wp-content/uploads/2023/09/0-9.jpg)
还有一些需要去对应的官网申请秘钥进行配置过后才能正常使用,比如有道翻译和火山翻译等,如果上图所示。
配置 ChatGPT
通过翻译源我们可以看到其中也有 ChatGPT
的选项,ChatGPT
的配置相较于其他的翻译源我们除了要配置 API Key
之外,我们同时也需要解决网络问题。
但是这对于大部分来说,这两个问题都有一定的门槛,ChatGPT
对网络的要求稍微会高点,弄不好就会被封号。
所以我们这里通过两步来解决这个问题
-
申请微软的 Azure Open AI
; -
通过 proxy
代理的形式将ChatGPT
原生请求转换为Azure Open AI
格式;
关于第一点前面的文章已经很详细的介绍了如果去申请,感兴趣的可以去看看,今天主要分享一下如何配置代理服务。
配置代理服务
在完成微软的 Azure Open AI
申请并成功部署模型过后,我们会获取到对应的 endpoint
以及秘钥信息。
然后我们注册一个 cloudflare
账号,然后在 Worker & Papes
下面创建一个应用,
![0-13 0-13](https://yuandifly.com/wp-content/uploads/2023/09/0-13.jpg)
![0-11 0-11](https://yuandifly.com/wp-content/uploads/2023/09/0-11.jpg)
重命名我们的服务,然后点击部署即可
![0-12 0-12](https://yuandifly.com/wp-content/uploads/2023/09/0-12.jpg)
![0-15 0-15](https://yuandifly.com/wp-content/uploads/2023/09/0-15.jpg)
然后点击 edit code
,在编辑器中输入下放代码,其中的代码有三处需要修改
-
resourceName
:修改成申请的微软Azure OpenAI
的时候配置的资源名称 -
mapper
:修改成open ai
模型和Azure OpenAI
的部署名称,前面是原生的模型名称,后面是Azure
的部署名称; -
apiVersion
:修改成在Azure OpenAI
里面的一致即可;
// The name of your Azure OpenAI Resource.
const resourceName="resource name"
// The deployment name you chose when you deployed the model.
const mapper = {
// model: deployName
'gpt-35-turbo-16k': "gpt-35-turbo"
};
const apiVersion="2023-03-15-preview"
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
if (request.method === 'OPTIONS') {
return handleOPTIONS(request)
}
const url = new URL(request.url);
if (url.pathname.startsWith("//")) {
url.pathname = url.pathname.replace('/',"")
}
if (url.pathname === '/v1/chat/completions') {
var path="chat/completions"
} else if (url.pathname === '/v1/completions') {
var path="completions"
} else if (url.pathname === '/v1/models') {
return handleModels(request)
} else {
return new Response('404 Not Found', { status: 404 })
}
let body;
if (request.method === 'POST') {
body = await request.json();
}
const modelName = body?.model;
const deployName = mapper[modelName] || ''
if (deployName === '') {
return new Response('Missing model mapper', {
status: 403
});
}
const fetchAPI = `https://${resourceName}.openai.azure.com/openai/deployments/${deployName}/${path}?api-version=${apiVersion}`
const authKey = request.headers.get('Authorization');
if (!authKey) {
return new Response("Not allowed", {
status: 403
});
}
const payload = {
method: request.method,
headers: {
"Content-Type": "application/json",
"api-key": authKey.replace('Bearer ', ''),
},
body: typeof body === 'object' ? JSON.stringify(body) : '{}',
};
let response = await fetch(fetchAPI, payload);
response = new Response(response.body, response);
response.headers.set("Access-Control-Allow-Origin", "*");
if (body?.stream != true){
return response
}
let { readable, writable } = new TransformStream()
stream(response.body, writable);
return new Response(readable, response);
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// support printer mode and add newline
async function stream(readable, writable) {
const reader = readable.getReader();
const writer = writable.getWriter();
// const decoder = new TextDecoder();
const encoder = new TextEncoder();
const decoder = new TextDecoder();
// let decodedValue = decoder.decode(value);
const newline = "\n";
const delimiter = "\n\n"
const encodedNewline = encoder.encode(newline);
let buffer = "";
while (true) {
let { value, done } = await reader.read();
if (done) {
break;
}
buffer += decoder.decode(value, { stream: true }); // stream: true is important here,fix the bug of incomplete line
let lines = buffer.split(delimiter);
// Loop through all but the last line, which may be incomplete.
for (let i = 0; i < lines.length - 1; i++) {
await writer.write(encoder.encode(lines[i] + delimiter));
await sleep(20);
}
buffer = lines[lines.length - 1];
}
if (buffer) {
await writer.write(encoder.encode(buffer));
}
await writer.write(encodedNewline)
await writer.close();
}
async function handleModels(request) {
const data = {
"object": "list",
"data": []
};
for (let key in mapper) {
data.data.push({
"id": key,
"object": "model",
"created": 1677610602,
"owned_by": "openai",
"permission": [{
"id": "modelperm-M56FXnG1AsIr3SXq8BYPvXJA",
"object": "model_permission",
"created": 1679602088,
"allow_create_engine": false,
"allow_sampling": true,
"allow_logprobs": true,
"allow_search_indices": false,
"allow_view": true,
"allow_fine_tuning": false,
"organization": "*",
"group": null,
"is_blocking": false
}],
"root": key,
"parent": null
});
}
const json = JSON.stringify(data, null, 2);
return new Response(json, {
headers: { 'Content-Type': 'application/json' },
});
}
async function handleOPTIONS(request) {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Headers': '*'
}
})
}
代码修改完成过后,点击右上角的 save and deploy
按钮即可。此时 cloudflare
会帮我们生成一个 worker.dev
接口的地址,通过这个地址我们就可以直接访问了,不过更优雅的方式是我们配置一个自己的域名。
配置自定义域名
配置自定义域名要求我们首先有一个主域名,并且绑定到 cloudflare
里面,我们通过上方的 add site
添加一个自己的域名,
![0-14 0-14](https://yuandifly.com/wp-content/uploads/2023/09/0-14.jpg)
并且选择 free 方案
![0-16 0-16](https://yuandifly.com/wp-content/uploads/2023/09/0-16.jpg)
接下来我们再按照要求,到域名 dns
解析的地方去配置一下 dns
的解析,保存过后可以点击 Check nameservers
,这个过程需要一段时间,上面说到差不多要 24 小时,我们可以晚点再回来看看。
![0-18 0-18](https://yuandifly.com/wp-content/uploads/2023/09/0-18.jpg)
直到我们看到对应的 site
下面显示 active
就说明可以了
![0-19 0-19](https://yuandifly.com/wp-content/uploads/2023/09/0-19.jpg)
接下来我们再到之前部分的 worker
下面去配置自定义域名
![0-17 0-17](https://yuandifly.com/wp-content/uploads/2023/09/0-17.jpg)
先配置一下 route
,然后在配置一下自定义域名即可。
这里有点绕,不过按照流程配置是可以正常使用的。
配置 roure 的时候需要我们有可用是 site 站点;配置自定义域名的时候要求我们可用的 roure
配置划词翻译
当我们代理服务部署完成过后,再回来划词翻译这里,在插件的服务申请 => ChatGPT
管理秘钥这里,填入我们 Azure OpenAI
的 key
;在第三方服务 => ChatGPT
这里填上我们上面自定义的域名和对应的模型名称,这个模型需要跟脚本 mapper
里面的 key
保持一致。
![0-20 0-20](https://yuandifly.com/wp-content/uploads/2023/09/0-20.jpg)
至此我们的 ChatGPT
的配置就完成了,简单总结一下:
因为我们国内无法直接使用 ChatGPT
,我们这里通过申请微软的 Azure OpenAI
来替代原生 OpenAI
,但是又因为划词翻译的 API
对接的是 OpenAI
的接口,所以我们需要一个中间代理服务将两者的协议进行转换。
如果划词翻译能直接兼容 Azure OpenAI
的话,其实我们就不用中间的代理了,可以直接配置。同理我们配置了代理服务过后,以后在其他 OpenAI
的客户端我们都可以直接使用了,一劳永逸。
发表评论