樱花人工智能 - 使用chatGPT构建一个打字助手
如果你还没有听说过chatGPT,那你可能是住在桥下的人。它无处不在!
我决定通过创建一个Chrome扩展并利用chatGPT的力量来探索这项技术,因为为什么不呢..?
首先,让我告诉你我们将要构建的是什么...
一个Chrome扩展程序,启用后将在您正在编辑的当前活动选项卡中帮助您。听起来不错吧?好的,让我们开始构建吧...
与下面显示的功能类似,现在可以在当前活动标签页的任何可编辑位置实现此功能。
好的,让我们从创建一个新文件夹开始,并在其中添加一个名为manifest.json的新文件,这是我们定义项目为 Chrome 扩展而不是网页并提供必要参数的地方。
manifest.json
{
"name": "Cherry : Powered by chatGPT",
"description": "Use the power of ChatGPT at your fingertips, your assistant Cherry will serve its master.",
"author": "Jigyasa Upadhyay",
"version": "0.0.1",
"manifest_version": 3,
"permissions": ["storage", "activeTab"],
"host_permissions": [""],
"action": {
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"runAt": "document_end",
"js": ["script.js"],
"all_frames": true
}
]
}
- 动作:default_popup: 当您点击扩展程序的图标时打开的默认HTML页面。
- content_scripts: 在所有框架的所有URL
上的 document_end(页面加载完成时)打开 script.js。 script.js 将包含所有的逻辑。
现在,创建一个新的文件popup.html,设置为默认页面,并将以下片段添加到其中。
弹出框
这是一个弹出框示例。
<!doctype html>
<html lang="en">
<head>
<meta charset=UTF-8 />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Cherry AI</title>
</head>
<body>
<h1>Cherry AI Powered By ChatGPT</h1>
</body>
</html>
足够简单,对吧?好了,现在我们来到处理功能的主文件。
让我们首先添加一个事件监听器,它将观察用户的输入。
脚本.js
// event listener for what the user is typing
window.addEventListener("keypress", debouncedScrapText);
现在,添加一个函数,该函数在用户输入时被调用。我们在这里添加防抖(debounce)方法,因为我们不希望不必要的调用发生,这将影响我们应用程序的性能。
什么是防抖(debouncing)?
简单地说,JavaScript中的去抖动是一种用来提高浏览器性能的实践。在网页中可能存在一些需要耗费时间的计算功能。如果这样的方法频繁调用,它可能会严重影响浏览器的性能,因为JavaScript是一种单线程语言。
function debounce(func, delay) {
let timer;
return function () {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(() => func.apply(context, args), delay);
};
}
// debounced function call
//
// Here the scrapText function will be debounced after 1000 milliseconds that is if the user
// stopped typing for 1 second then only the function scrapText will be invoked.
const debouncedScrapText = debounce(scrapText, 1000);
现在,添加一个函数来获取DOM中textarea/input中用户正在输入的文本(提示)。
// helper function extract their text from the node
const getTextContentFromDOMElements = (nodes, textarea = false) => {
if (!nodes || nodes.length === 0) {
return null;
}
for (let node of nodes) {
if (node) {
textarea = node.nodeName.toLowerCase();
}
const value = textarea && node.value ? node.value : node.textContent;
if (node && value) {
const text = getTextParsed(value);
if (text) return [node, text];
else return null;
}
}
};
const scrapText = () => {
const element = document.querySelectorAll('[contenteditable="true"]');
const parsedValue = getTextContentFromDOMElements(element);
if (parsedValue) {
const [node, text] = parsedValue;
makeChatGPTCall(text, node);
}
};
现在,我们已经有了文本,但是我们需要将它与“cherry:”命令分开。我们将使用正则表达式来处理,并在另一个函数中进行处理。
// regex to check the text is in the form "cherry: command;"
const getTextParsed = (text) => {
const parsed = /cherry:(.*?)\;/gi.exec(text);
return parsed ? parsed[1] : "";
};
好的,让我们添加处理 OpenAI API 调用的功能。为此,您将需要一个唯一的 APIKEY,您可以从这里生成:https://platform.openai.com/api-keys
const makeChatGPTCall = async (text, node) => {
try {
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Authorization", `Bearer ${apikey}`);
const raw = JSON.stringify({
model: "gpt-3.5-turbo-instruct",
prompt: text,
max_tokens: 2048,
temperature: 0,
top_p: 1,
n: 1,
stream: false,
logprobs: null,
});
const requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow",
};
let response = await fetch(
"https://api.openai.com/v1/completions",
requestOptions,
);
response = await response.json();
const { choices } = response;
// remove the spaces from the reponse text
text = choices[0].text.replace(/^s\s+|\s+$/g, "");
node.value = text;
node.textContent = text;
} catch (e) {
console.error("Error while calling openai api", e);
}
};
最后,script.js文件应该是这样的。
const makeChatGPTCall = async (text, node) => {
try {
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Authorization", `Bearer ${apikey}`);
const raw = JSON.stringify({
model: "gpt-3.5-turbo-instruct",
prompt: text,
max_tokens: 2048,
temperature: 0,
top_p: 1,
n: 1,
stream: false,
logprobs: null,
});
const requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow",
};
let response = await fetch(
"https://api.openai.com/v1/completions",
requestOptions,
);
response = await response.json();
const { choices } = response;
// remove the spaces from the reponse text
text = choices[0].text.replace(/^s\s+|\s+$/g, "");
node.value = text;
node.textContent = text;
} catch (e) {
console.error("Error while calling openai api", e);
}
};
// regex to check the text is in the form "cherry: command;"
const getTextParsed = (text) => {
const parsed = /cherry:(.*?)\;/gi.exec(text);
return parsed ? parsed[1] : "";
};
// helper function extract their text from the node
const getTextContentFromDOMElements = (nodes, textarea = false) => {
if (!nodes || nodes.length === 0) {
return null;
}
for (let node of nodes) {
if (node) {
textarea = node.nodeName.toLowerCase();
}
const value = textarea && node.value ? node.value : node.textContent;
if (node && value) {
const text = getTextParsed(value);
if (text) return [node, text];
else return null;
}
}
};
const scrapText = () => {
const element = document.querySelectorAll('[contenteditable="true"]');
const parsedValue = getTextContentFromDOMElements(element);
if (parsedValue) {
const [node, text] = parsedValue;
makeChatGPTCall(text, node);
}
};
function debounce(func, delay) {
let timer;
return function () {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(() => func.apply(context, args), delay);
};
}
// debounced function call
//
// Here the scrapText function will be debounced after 1000 milliseconds that is if the user
// stopped typing for 1 second then only the function scrapText will be invoked.
const debouncedScrapText = debounce(scrapText, 1000);
// event listener for what the user is typing
window.addEventListener("keypress", debouncedScrapText);
这就是代码部分的全部内容,现在让我们将这个包加载到浏览器中。
- 打开Chrome浏览器。
- 去设置 > 扩展。
- 在右上角启用开发者模式。
- 点击左上角的“加载已解压的扩展”按钮。
- 导航并加载您的目录。
现在,转到任何具有可编辑文本输入的站点并重新加载页面,扩展程序应该已加载并且应该完美运行。
恭喜,您刚刚使用GPT创建了自己的打字助手。🎉
限制
为了安全起见,网站会做很多内部处理,并通过javascript阻止通?#23567;议?#21040;值的更新。
但是你是一个开发者,你懂得HTML/JS的技巧 ;)
我将把这个代码库上传到我的Github,所以请参考 https://github.com/jigyasa-ctrl。
希望你喜欢阅读这篇博客,就像我写这篇博客一样开心。
感谢您的阅读!🥳