樱花人工智能 - 使用chatGPT构建一个打字助手

如果你还没有听说过chatGPT,那你可能是住在桥下的人。它无处不在!

我决定通过创建一个Chrome扩展并利用chatGPT的力量来探索这项技术,因为为什么不呢..?

首先,让我告诉你我们将要构建的是什么...

一个Chrome扩展程序,启用后将在您正在编辑的当前活动选项卡中帮助您。听起来不错吧?好的,让我们开始构建吧...

与下面显示的功能类似,现在可以在当前活动标签页的任何可编辑位置实现此功能。

demo image of the chrome extension functionality in stackedit.
demo of chrome extension in github

好的,让我们从创建一个新文件夹开始,并在其中添加一个名为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,设置为默认页面,并将以下片段添加到其中。

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);

这就是代码部分的全部内容,现在让我们将这个包加载到浏览器中。

  1. 打开Chrome浏览器。
  2. 去设置 > 扩展。
  3. 在右上角启用开发者模式。
  4. 点击左上角的“加载已解压的扩展”按钮。
  5. 导航并加载您的目录。

现在,转到任何具有可编辑文本输入的站点并重新加载页面,扩展程序应该已加载并且应该完美运行。

恭喜,您刚刚使用GPT创建了自己的打字助手。🎉

限制

为了安全起见,网站会做很多内部处理,并通过javascript阻止通?#23567;议?#21040;值的更新。

但是你是一个开发者,你懂得HTML/JS的技巧 ;)

我将把这个代码库上传到我的Github,所以请参考 https://github.com/jigyasa-ctrl。

希望你喜欢阅读这篇博客,就像我写这篇博客一样开心。

感谢您的阅读!🥳

2024-02-01 04:14:11 AI中文站翻译自原文