?本文作者是360奇舞團(tuán)開發(fā)工程師
引言
OpenAI
發(fā)布了ChatGPT
,就像是給平靜許久的互聯(lián)網(wǎng)湖面上扔了一顆重磅炸彈,剎那間所有人都在追捧學(xué)習(xí)它。究其原因,它其實(shí)是一款真正意義上的人工智能對(duì)話機(jī)器人
。它使用了深度學(xué)習(xí)技術(shù),通過大量的訓(xùn)練數(shù)據(jù)和自監(jiān)督學(xué)習(xí)方法進(jìn)行訓(xùn)練,以模擬人類的對(duì)話能力和生成自然語言回應(yīng)。日常生產(chǎn)、學(xué)習(xí)中利用好ChatGPT
這個(gè)工具,是絕對(duì)能夠提升我們工作效率的,這一點(diǎn)對(duì)于我們程序員來說,感受應(yīng)該尤為明顯。我們最常用的開發(fā)工具VSCode
,已經(jīng)有許多的插件集成了ChatGPT
功能,這篇文章將從零開始,介紹這些插件的實(shí)現(xiàn)原理與思路,希望對(duì)你有所幫助。
基本需求
實(shí)現(xiàn)一款可以跟ChatGPT
對(duì)話的插件,可以通過一問一答的形式來進(jìn)行對(duì)話,并且可以將我們選中的代碼發(fā)送給ChatGPT
,讓其可以對(duì)代碼進(jìn)行優(yōu)化。當(dāng)然如果要訪問ChatGPT
,首先需要綁定我們?cè)?code>OpenAI后臺(tái)申請(qǐng)的ApiKey
.
VSCode 插件基本配置
首先簡單介紹一下VSCode
插件開發(fā)的基本流程
安裝腳手架
npm install -g yo generator-code
然后cd
到你的工作目錄,運(yùn)行yo code
,根據(jù)向?qū)б徊讲竭x擇即可,沒啥好說的,運(yùn)行完后就生成了一個(gè)干凈的可以運(yùn)行的插件工程了。
2. 工程目錄介紹
查看當(dāng)前目錄,工程的核心是package.json
與extension.js
.首先看下package.json
的配置文件:
name
:工程名稱displayName
: 應(yīng)用市場名稱description
: 應(yīng)用描述version
: 當(dāng)前插件版本engines
: 表示插件最低支持的vscode版本categories
: 插件應(yīng)用市場分類main
: 程序的主入口文件activationEvents
:重要,擴(kuò)展的激活事件數(shù)組,表示可以被哪些事件激活當(dāng)前插件。比如:
"activationEvents": [
"onView:chatgpt-for-vscode.view",
"onCommand:chatgpt-for-vscode.setAPIKey",
"onCommand:chatgpt-for-vscode.askGPT",
"onCommand:chatgpt-for-vscode.whyBroken",
"onCommand:chatgpt-for-vscode.optimizeCode",
"onCommand:chatgpt-for-vscode.explainCode",
"onCommand:chatgpt-for-vscode.refactor"
],
onView
:表示 通過視圖觸發(fā),chatgpt-for-vscode.view
是視圖Id。當(dāng)觸發(fā)這個(gè)視圖時(shí),喚起當(dāng)前插件onCommand
: 表示通過命令觸發(fā),后面是命令I(lǐng)d,這些都是我們自定義的命令。在VSCode
中按下快捷鍵:Command + Shift + P
?輸入命令title
后喚起插件,命令title
在contributes
,commands
模塊里面定義,后面介紹。
除了這兩個(gè)還有:onLanguage
、onUri
、onDebug
、workspaceContains
、onFileSystem
等,如果設(shè)置為*
,只要一啟動(dòng)VSCode
,插件就會(huì)被激活,當(dāng)然為了用戶體驗(yàn),官方不推薦這么做。
contributes
:?重要,配置插件的主要功能點(diǎn)。比如:
"contributes": {
"commands": [
{
"command": "chatgpt-for-vscode.setAPIKey",
"title": "GPT:綁定APIKey"
},
{
"command": "chatgpt-for-vscode.askGPT",
"title": "GPT:詢問 GPT"
},
{
"command": "chatgpt-for-vscode.whyBroken",
"title": "GPT:說明這段代碼存在的問題"
},
{
"command": "chatgpt-for-vscode.optimizeCode",
"title": "GPT:優(yōu)化這段代碼"
},
{
"command": "chatgpt-for-vscode.explainCode",
"title": "GPT:解釋這段代碼"
},
{
"command": "chatgpt-for-vscode.refactor",
"title": "GPT:重構(gòu)這段代碼"
}
],
"menus": {
"editor/context": [
{
"command": "chatgpt-for-vscode.askGPT",
"group": "navigation@1"
},
{
"command": "chatgpt-for-vscode.whyBroken",
"group": "navigation@2"
},
{
"command": "chatgpt-for-vscode.optimizeCode",
"group": "navigation@3"
},
{
"command": "chatgpt-for-vscode.explainCode",
"group": "navigation@4"
},
{
"command": "chatgpt-for-vscode.refactor",
"group": "navigation@5"
},
{
"command": "chatgpt-for-vscode.setAPIKey",
"group": "navigation@6"
}
]
},
"viewsContainers": {
"activitybar": [
{
"id": "chatgpt-for-vscode",
"title": "ChatGPT",
"icon": "images/ChatGPT.png"
}
]
},
"views": {
"chatgpt-for-vscode": [
{
"type": "webview",
"id": "chatgpt-for-vscode.view",
"name": "ChatGPT"
}
]
}
},
commands:?
command
: 命令I(lǐng)d,這個(gè)命令I(lǐng)d跟activationEvents
中配置的命令I(lǐng)d相同。title
:輸入的命令的名稱。Command + Shift + P
?輸入這個(gè)命令title后找到對(duì)應(yīng)的命令。menus:?
editor/context
:配置編輯器右鍵展示內(nèi)容。command
是命令I(lǐng)d,group
:右鍵后展示看板的命令位置。這里navigation
表示展示在模塊的頂部。@*
表示排序。viewsContainers
:?activitybar
:配置右側(cè)工具欄視圖入口,配置后展示,注意這里的id
,要跟后面的views
模塊里面的視圖key值保持一致,表示點(diǎn)擊右側(cè)icon
后展示那個(gè)視圖,icon
是你本地的圖片路徑。views
: 配置視圖,這里使用webview
展示自定義視圖
配置完成
package.json
后右鍵命令展示,左側(cè)狀態(tài)欄Icon,頂部命令行選擇輸入命令,已經(jīng)可以展示了。運(yùn)行npm run test
?后會(huì)打開默認(rèn)安裝你插件的VSCode
面板,接下來就是完善觸發(fā)命令后的代碼邏輯了,核心在extension.ts
中實(shí)現(xiàn)。
extension.ts
模塊開發(fā)
extension.ts
?是程序的入口文件,里面有兩個(gè)核心方法:
export function activate(context: vscode.ExtensionContext) {}
export function deactivate() {}
看字面意思很好理解,分別表示插件被激活與釋放調(diào)用的生命周期方法.
1. 綁定APIKey
命令邏輯
要想使用OpenAI
的api,首先需要將自己的ApiKey
與插件進(jìn)行關(guān)聯(lián)。這里使用VSCode
自有APIvscode.window.showInputBox
來獲取用戶輸入.
this.apiKey = await this.context.globalState.get('chatgpt-api-key');
if (!this.apiKey) {
const apiKeyInput = await vscode.window.showInputBox({
prompt: "請(qǐng)輸入你的API Key",
ignoreFocusOut: true,
});
this.apiKey = apiKeyInput;
this.context.globalState.update('chatgpt-api-key', this.apiKey);
}
使用上下文的
globalState
來持久化保存ApiKey
如果要讓這個(gè)命令生效,需要在
activate
中進(jìn)行注冊(cè)
context.subscriptions.push(vscode.commands.registerCommand('chatgpt-for-vscode.setAPIKey', resetToken))
async function resetToken() {
await vscode.window.showInputBox({
prompt: "請(qǐng)輸入OpenAI API Key",
ignoreFocusOut: true,
});
}
執(zhí)行
command + shift + p
?輸入命令titleGPT:綁定APIKey
后,展示效果如下:
這樣就完成了對(duì)用戶ApiKey
的綁定邏輯.
2. 命令觸發(fā)邏輯
與綁定用戶ApiKey
類似,其他命令的執(zhí)行也是同樣的流程,這里以onCommand:chatgpt-for-vscode.askGPT
命令來說明:
// 注冊(cè)命令
vscode.commands.registerCommand('chatgpt-for-vscode.askGPT', askChatGPT)
// 命令實(shí)現(xiàn)
async function askChatGPT(userInput: string) {
let editor = vscode.window.activeTextEditor;
if (editor) {
const selectedCode = editor.document.getText(vscode.window.activeTextEditor?.selection);
if(selectedCode.length) {
chatViewProvider.sendOpenAiApiRequest(userInput, selectedCode);
vscode.window.showInformationMessage(selectedCode);
}else {
vscode.window.showInformationMessage(`請(qǐng)選中一段代碼`);
}
}
}
注冊(cè)命令后 使用
editor.document.getText(vscode.window.activeTextEditor?.selection)
來獲取選中的代碼段落,并判空.利用
chatViewProvider.sendOpenAiApiRequest(userInput, selectedCode);
利用這個(gè)方法用戶輸入的Prompt
與選中的代碼端傳遞出去,這個(gè)方法的實(shí)現(xiàn)后面介紹,注冊(cè)所有的命令后,activate
方法是這樣的
export function activate(context: vscode.ExtensionContext) {
const chatViewProvider = new view_provider.default(context);
context.subscriptions.push(
vscode.commands.registerCommand('chatgpt-for-vscode.askGPT', askChatGPT),
vscode.commands.registerCommand('chatgpt-for-vscode.whyBroken', askGPTWhyBroken),
vscode.commands.registerCommand('chatgpt-for-vscode.explainCode', askGPTToExplain),
vscode.commands.registerCommand('chatgpt-for-vscode.refactor', askGPTToRefactor),
vscode.commands.registerCommand('chatgpt-for-vscode.optimizeCode', askGPTToOptimize),
vscode.commands.registerCommand('chatgpt-for-vscode.setAPIKey', resetToken),
vscode.window.registerWebviewViewProvider("chatgpt-for-vscode.view", chatViewProvider, {
webviewOptions: { retainContextWhenHidden: true }})
);
async function askGPTWhyBroken() { await askChatGPT('說明下面的代碼會(huì)出現(xiàn)什么問題?'); }
async function askGPTToExplain() { await askChatGPT('請(qǐng)幫我解釋一下下面的代碼?'); }
async function askGPTToRefactor() { await askChatGPT('幫我重構(gòu)下面的代碼'); }
async function askGPTToOptimize() { await askChatGPT('幫我優(yōu)化下面的代碼'); }
async function resetToken() {
await chatViewProvider.ensureApiKey();
}
async function askChatGPT(userInput: string) {
let editor = vscode.window.activeTextEditor;
if (editor) {
const selectedCode = editor.document.getText(vscode.window.activeTextEditor?.selection);
if(selectedCode.length) {
chatViewProvider.sendOpenAiApiRequest(userInput, selectedCode);
vscode.window.showInformationMessage(selectedCode);
}else {
vscode.window.showInformationMessage(`請(qǐng)選中一段代碼`);
}
}
}
}
3.webView與chatViewProvider
上面的代碼除了注冊(cè)命令的APIregisterCommand
,還有一個(gè)注冊(cè)自定義webview
視圖的API,registerWebviewViewProvider
,作用是展示我們自定義的webview
,它有三個(gè)參數(shù):
chatgpt-for-vscode.view
是視圖Id,跟package.json
中views
模塊對(duì)應(yīng)的Id相同,表示為那個(gè)視圖Id注冊(cè)provider
.chatViewProvider
?視圖提供者.第三個(gè)參數(shù):
webview
的屬性配置,retainContextWhenHidden: true
表示:webview
被隱藏時(shí)保持狀態(tài),避免被重置.
接下來重點(diǎn)來看chatViewProvider
:
作為自定義視圖的provider
首先需要繼承vscode.WebviewViewProvider
這個(gè)接口
export interface WebviewViewProvider {
/**
* Revolves a webview view.
*
* `resolveWebviewView` is called when a view first becomes visible. This may happen when the view is
* first loaded or when the user hides and then shows a view again.
*
* @param webviewView Webview view to restore. The provider should take ownership of this view. The
* provider must set the webview's `.html` and hook up all webview events it is interested in.
* @param context Additional metadata about the view being resolved.
* @param token Cancellation token indicating that the view being provided is no longer needed.
*
* @return Optional thenable indicating that the view has been fully resolved.
*/
resolveWebviewView(webviewView: WebviewView, context: WebviewViewResolveContext, token: CancellationToken): Thenable<void> | void;
}
這個(gè)接口只有一個(gè)方法,resolveWebviewView
在視圖首次可見時(shí)被調(diào)用。這可能發(fā)生在視圖第一次加載時(shí),或者當(dāng)用戶隱藏然后再次顯示視圖時(shí)。在這個(gè)方面里面設(shè)置webview
的html
與視圖屬性。
export default class ChatGptViewProvider implements vscode.WebviewViewProvider {
private webView?: vscode.WebviewView;
private apiKey?: string;
private message?: any;
constructor(private context: vscode.ExtensionContext) { }
public resolveWebviewView(
webviewView: vscode.WebviewView,
_context: vscode.WebviewViewResolveContext,
_token: vscode.CancellationToken,
) {
this.webView = webviewView;
// webview屬性設(shè)置
webviewView.webview.options = {
enableScripts: true,
localResourceRoots: [this.context.extensionUri]
};
// 返回Html代碼
webviewView.webview.html = this.getHtml(webviewView.webview);
// 接收
webviewView.webview.onDidReceiveMessage(data => {
if (data.type === 'askChatGPT') {
this.sendOpenAiApiRequest(data.value);
}
});
if (this.message !== null) {
this.sendMessageToWebView(this.message);
this.message = null;
}
}
}
4. 通信機(jī)制
自定義的webview
和普通網(wǎng)頁非常類似,都不能直接調(diào)用任何VSCodeAPI
,但是,它唯一特別之處就在于多了一個(gè)名叫acquireVsCodeApi
的方法,執(zhí)行這個(gè)方法會(huì)返回一個(gè)超級(jí)閹割版的vscode
對(duì)象.利用這個(gè)對(duì)象,可以實(shí)現(xiàn)webview
與插件也就是provider
的通信。
provider
給webview
發(fā)送消息:
this.webView?.webview.postMessage(message);
webview
端接收消息:
window.addEventListener('message', event => {
const message = event.data;
console.log('Webview接收到的消息:', message);
}
webview
主動(dòng)發(fā)送消息給provider
:
const vscode = acquireVsCodeApi();
vscode.postMessage({text: '你好,我是Webview??!'});
provider
接收消息:
this.webView?.webview.onDidReceiveMessage(data => {
if (data.type === 'askChatGPT') {
this.sendOpenAiApiRequest(data.value);
}
});
了解完雙方的通信機(jī)制后,基本邏輯是:當(dāng)點(diǎn)擊webview
上的發(fā)送
按鈕后,將用戶輸入發(fā)送給ChatGPT
,ChatGPT
處理完成后將返回信息發(fā)送給webview
,webview
將回答信息展示出來,完成一次對(duì)話邏輯。
// 按鈕綁定點(diǎn)擊事件
document.getElementById("ask-button")?.addEventListener("click", submitHandler);
let submitHandler = function (e) {
e.preventDefault();
e.stopPropagation();
const input = document.getElementById("question-input");
if (input.value?.length > 0) {
// 發(fā)送消息給 插件,使其完成ChatGPT請(qǐng)求
vscode.postMessage({
type: "askChatGPT",
value: input.value,
});
input.value = "";
}
};
5. 調(diào)用OPenAI
接口
要想完成一次對(duì)話,需要調(diào)用OPenAI
的API.具體的API你可以在官網(wǎng)找到:
參數(shù)
model
是你要對(duì)話的ChatGPT
模型代碼,不同模型針對(duì)同一個(gè)問題的答案會(huì)有所區(qū)別。具體模塊區(qū)別可以參考下面圖片:
更多模型可以點(diǎn)擊這里去查看參數(shù)
messages
: 你的問題信息參數(shù)
temperature
: 它是一個(gè)用于控制生成文本的創(chuàng)造性的參數(shù),其值介于0到2之間。值為1意味著模型將使用其默認(rèn)采樣策略,而值低于1.0將導(dǎo)致更保守和可預(yù)測的響應(yīng),值大于1.0將導(dǎo)致更有創(chuàng)造性和多樣化的響應(yīng)。參數(shù)
max_tokens
: 生成對(duì)話的最大token
數(shù)量。這里的token
可以理解為模型的構(gòu)建塊。了解完成上面的參數(shù),可以利用fetch
發(fā)起請(qǐng)求了:
let completion = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
body: JSON.stringify({
model: "text-davinci-003",
messages: [{ role: "user", content: question }],
temperature: 0.7
}),
headers: {
// eslint-disable-next-line @typescript-eslint/naming-convention
"Content-Type": 'application/json',
Authorization: 'Bearer ' + this.apiKey,
},
}) as any;
根據(jù)返回的數(shù)據(jù)結(jié)構(gòu),解析響應(yīng)數(shù)據(jù),并將結(jié)果發(fā)送給webview
進(jìn)行展示,完成開發(fā)。
發(fā)布插件
擴(kuò)展安裝
通過以上步驟基本完成了插件的開發(fā),接下來有兩種方式發(fā)布我們的插件,如果你的插件只是在內(nèi)網(wǎng)使用,可以通過命令:vsce package
, 將插件打包為vsix
插件包,通過VSCode
的擴(kuò)展,從VSIX
安裝.
當(dāng)然首先要安裝vsce
這個(gè)工具
npm i vsce -g
-
上傳到應(yīng)用
VSCode
插件市場插件上傳到
VSCode
應(yīng)用市場,需要有應(yīng)用市場的publisher
賬號(hào),具體的賬號(hào)創(chuàng)建流程這里不再涉及,創(chuàng)建賬號(hào)后,登錄當(dāng)前賬號(hào),執(zhí)行vsce publish
,發(fā)布成功后大概需要過幾分鐘才能在應(yīng)用市場搜到.發(fā)布賬號(hào)有幾個(gè)注意事項(xiàng): README.md
文件默認(rèn)會(huì)顯示在插件主頁;README.md
中的資源必須全部是HTTPS的,如果是HTTP會(huì)發(fā)布失?。?/p>CHANGELOG.md
會(huì)顯示在變更選項(xiàng)卡;如果代碼是放在
git
倉庫并且設(shè)置了repository
字段,發(fā)布前必須先提交git
,否則會(huì)提示Git working directory not clean
發(fā)布后需要等待幾分鐘應(yīng)用市場才會(huì)更新;
-
當(dāng)然你可以在插件市場里面搜索
chatgpt-for-vscode
?來試用這個(gè)插件;
總結(jié)
以上就是一個(gè)ChatGPT
插件的基本創(chuàng)建流程,核心是對(duì)VSCode API
以及ChatGPT API
的了解與使用。當(dāng)然你所需要的功能都可以在對(duì)應(yīng)的官方文檔中找到。
參考文獻(xiàn):
https://code.visualstudio.com/api/extension-guides/overview
https://platform.openai.com/docs/api-reference/chat/create
http://blog.haoji.me/vscode-plugin-publish.html
-?END?-
關(guān)于奇舞團(tuán)
奇舞團(tuán)是 360 集團(tuán)最大的大前端團(tuán)隊(duì),代表集團(tuán)參與 W3C 和 ECMA 會(huì)員(TC39)工作。奇舞團(tuán)非常重視人才培養(yǎng),有工程師、講師、翻譯官、業(yè)務(wù)接口人、團(tuán)隊(duì) Leader 等多種發(fā)展方向供員工選擇,并輔以提供相應(yīng)的技術(shù)力、專業(yè)力、通用力、領(lǐng)導(dǎo)力等培訓(xùn)課程。奇舞團(tuán)以開放和求賢的心態(tài)歡迎各種優(yōu)秀人才關(guān)注和加入奇舞團(tuán)。
文章來源:http://www.zghlxwxcb.cn/news/detail-696496.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-696496.html
到了這里,關(guān)于從零開發(fā)一款ChatGPT VSCode插件的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!