Develop a ChatGPT VSCode plugin from scratch

‍The author of this article is a development engineer of 360 Qiwu Troupe

introduction

OpenAIReleased ChatGPT, it was like throwing a blockbuster on the Internet lake that had been calm for a long time, and everyone was chasing and learning it in an instant. The reason for this is that it is actually a mobile phone in the true sense 人工智能对话机器人. It uses deep learning technology, trained with a large amount of training data and self-supervised learning methods, to simulate human dialogue ability and generate natural language responses. Making good use of ChatGPTthis tool in daily production and learning can definitely improve our work efficiency, which should be especially obvious to us programmers. Many of our most commonly used development tools VSCodehave already integrated functions with many plug-ins ChatGPT. This article will start from scratch and introduce the implementation principles and ideas of these plug-ins. I hope it will be helpful to you.

basic needs

Realize a plug-in that can ChatGPTtalk to you, you can have a dialogue in the form of a question and an answer, and you can send the code we selected to ChatGPT, so that it can optimize the code. Of course, if you want to access ChatGPT, you first need to bind OpenAIthe ApiKey.

VSCode plug-in basic configuration

First, briefly introduce VSCodethe basic process of plug-in development

  1. Install scaffolding

npm install -g yo generator-code

Then cdgo to your working directory, run it yo code, and choose step by step according to the wizard. There is nothing to say. After running, a clean and runnable plug-in project will be generated.
2. Introduction to the project directory
00e34aacf33fd3c83989ef4da7c983d4.png
View the current directory, the core of the project is package.jsonand extension.js. First look at package.jsonthe configuration file:

  • name:project name

  • displayName: App market name

  • description: Application description

  • version: current plugin version

  • engines: Indicates the minimum supported vscode version of the plugin

  • categories: Plug-in application market classification

  • main: The main entry file of the program

  • activationEvents: Important , an array of extended activation events, indicating which events can activate the current plugin. for example:

"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: Indicates that it is triggered by a view, chatgpt-for-vscode.viewwhich is the view ID. When this view is triggered, the current plug-in is invoked
onCommand: Indicates that it is triggered by a command, followed by the command Id, these are our custom commands. Press the shortcut key in VSCode: After Command + Shift + P entering the command title, the plug-in will be invoked. The command titleis contributesdefined commandsin the module, which will be introduced later.
In addition to these two, there are: onLanguage, onUri, onDebug, workspaceContains, onFileSystemetc. If set to , the plug-in will be activated *as soon as it is started . Of course, for the user experience, this is not officially recommended.VSCode

  • contributesImportant , configure the main function points of the plugin. for example:

"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:优化这段代码"
      },
      {
        "command": "chatgpt-for-vscode.explainCode",
        "title": "GPT:解释这段代码"
      },
      {
        "command": "chatgpt-for-vscode.refactor",
        "title": "GPT:重构这段代码"
      }
    ],
    "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: Command Id, this command Id activationEventsis the same as the command Id configured in . title: The name of the entered command. Command + Shift + P Enter the command title and find the corresponding command.
    5a0dd3b4eb2fa81ee18437cdea7ce53e.png

  • menus:  editor/context: Configure the editor to right-click to display the content. commandIs the command Id, group: Display the command position of the Kanban after right-clicking. Here navigationthe representation is shown at the top of the module. @*Indicates sorting.
    63296978ac27341e39004dbb2c055ba2.png

  • viewsContainersactivitybar: Configure the right toolbar view entry, and display it after configuration. Note here that it must be consistent with the view key value in the idlater module, which means that the view displayed after clicking on the right is your local image path.
    viewsiconicon
    5d098dccf315705f424fd93bd4a5f889.png

  • views: Configure the view, here is used to webviewdisplay the custom view

  1. After the configuration is complete package.json, the right-click command is displayed, the icon on the left status bar, and the top command line selects the input command, which can already be displayed. After running, npm run test it will open the panel where your plug-in is installed by default VSCode. The next step is to improve the code logic after triggering the command, and the core is extension.tsimplemented in .

extension.tsmodule development

extension.ts It is the entry file of the program, and there are two core methods in it:

export function activate(context: vscode.ExtensionContext) {}
export function deactivate() {}

It is easy to understand the literal meaning, which means the life cycle method called by the plug-in when it is activated and released.

1. Binding APIKeycommand logic

To use the api, you first need to associate OpenAIyour own with the plug-in. ApiKeyThis uses VSCodeits own API vscode.window.showInputBoxto get user input.

this.apiKey = await this.context.globalState.get('chatgpt-api-key');
 if (!this.apiKey) {
    const apiKeyInput = await vscode.window.showInputBox({
        prompt: "请输入你的API Key",
        ignoreFocusOut: true,
    });
    this.apiKey = apiKeyInput;
    this.context.globalState.update('chatgpt-api-key', this.apiKey);
 }
  • globalStatePersistence using the contextApiKey

  • For this command to take effect, it needs activateto be registered in

context.subscriptions.push(vscode.commands.registerCommand('chatgpt-for-vscode.setAPIKey', resetToken))

async function resetToken() {
	await vscode.window.showInputBox({
          prompt: "请输入OpenAI API Key",
          ignoreFocusOut: true,
     });
}

After executing command + shift + p the input command title GPT:绑定APIKey, the display effect is as follows: ff345131e0e3cdfa7e9044ec116346ec.png
In this way, the binding logic to the user is completed ApiKey.

2. Command trigger logic

Similar to binding users ApiKey, the execution of other commands is also the same process, here is onCommand:chatgpt-for-vscode.askGPTthe command to illustrate:

// 注册命令
vscode.commands.registerCommand('chatgpt-for-vscode.askGPT', askChatGPT)
// 命令实现
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(`请选中一段代码`);
      }
  }
}
  • After registering the command, use it editor.document.getText(vscode.window.activeTextEditor?.selection)to get the selected code paragraph and judge it as empty.

  • Use chatViewProvider.sendOpenAiApiRequest(userInput, selectedCode);this method Prompt
    to pass the code input and selected by the user. The implementation of this method will be introduced later. After registering all the commands, activatethe method is as follows

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('说明下面的代码会出现什么问题?'); }
	async function askGPTToExplain() { await askChatGPT('请帮我解释一下下面的代码?'); }
	async function askGPTToRefactor() { await askChatGPT('帮我重构下面的代码'); }
	async function askGPTToOptimize() { await askChatGPT('帮我优化下面的代码'); }
	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(`请选中一段代码`);
			}
        }
    }
}
3. webView and chatViewProvider

In addition to the API for registering commands, the above code registerCommandalso has an API for registering custom webviewviews. registerWebviewViewProviderThe function is to display our custom ones webview. It has three parameters:

  • chatgpt-for-vscode.viewIs the view Id, which is the same as the Id corresponding to the module package.jsonin the middle , indicating that it is registered for that view Id .viewsprovider

  • chatViewProvider view provider.

  • The third parameter: webviewthe attribute configuration, retainContextWhenHidden: truewhich means: webviewkeep the state when it is hidden, and avoid being reset.
    Next, focus on chatViewProvider:
    as a custom view, provideryou first need to inherit vscode.WebviewViewProviderthis interface

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

This interface has only one method, which resolveWebviewViewis called when the view is first made visible. This can happen when the view first loads, or when the user hides and then shows the view again. Inside this aspect is set webviewthe htmlsame view properties.

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属性设置
        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. Communication mechanism

Custom webviewweb pages are very similar to ordinary web pages, and they cannot be called directly VSCodeAPI. However, their only special feature is that there is an additional acquireVsCodeApimethod named, and executing this method will return a super castrated version of the vscodeobject. Using this object, you can implement Communication webviewwith plugins, that is .provider

  • providerSend a message to webview:

this.webView?.webview.postMessage(message);
  • webviewThe terminal receives the message:

window.addEventListener('message', event => {
	const message = event.data;
	console.log('Webview接收到的消息:', message);
}
  • webviewProactively send a message to provider:

const vscode = acquireVsCodeApi();
vscode.postMessage({text: '你好,我是Webview啊!'});
  • providerReceive message:

this.webView?.webview.onDidReceiveMessage(data => {
    if (data.type === 'askChatGPT') {
        this.sendOpenAiApiRequest(data.value);
    }
});

After understanding the communication mechanism between the two parties, the basic logic is: when the button webviewis clicked 发送, the user input is sent to ChatGPT, ChatGPTafter the processing is completed, the return information is sent to webview, and webviewthe answer information is displayed to complete a dialogue logic.

// 按钮绑定点击事件
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) {
      // 发送消息给 插件,使其完成ChatGPT请求
        vscode.postMessage({
            type: "askChatGPT",
            value: input.value,
        });

        input.value = "";
    }
};
5. Call OPenAIinterface

To complete a conversation, you need to call OPenAIthe API. You can find the specific API on the official website:
79fc4a14332a9c9460f7edb57d51c37a.png

  • The parameter modelis the code of the model you want to talk to ChatGPT, and different models will have different answers to the same question. For specific module differences, please refer to the picture below:
    6827c009aafd1d484a03c8851f20b8f9.png
    For more models, click here to view

  • Parameters messages: your question information

  • Parameter temperature: It is a parameter used to control the creativity of the generated text, and its value is between 0 and 2. A value of 1 means the model will use its default sampling strategy, while values ​​below 1.0 will result in more conservative and predictable responses, and values ​​above 1.0 will result in more creative and diverse responses.

  • Parameters max_tokens: The maximum number of dialogs to generate token. Here tokencan be understood as the building blocks of the model. After understanding the above parameters, you can use it to fetchinitiate a request:

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;

According to the returned data structure, parse the response data, and send the result to webviewdisplay to complete the development.
6e71432f43f4dc3aac2442dd5c953b80.png

Publish plugin

  • Extension installation The
    development of the plug-in is basically completed through the above steps. Next, there are two ways to publish our plug-in. If your plug-in is only used on the intranet, you can use the command: , to package the plug-in into a plug- vsce packagein vsixpackage VSCode. VSIXInstallation.
    Of course, you must first install vscethis tool

npm i vsce -g

c77920fcdcff3469af1710f37f8865a2.png

  • Upload to Apps VSCodeMarketplace

    To upload a plug-in to VSCodethe application market, you need an account in the application market publisher. The specific account creation process is not involved here. After creating an account, log in to the current account and execute it. vsce publishIt will take a few minutes to find it in the application market after the release is successful. There are a few caveats:

  • README.mdThe file will be displayed on the plugin home page by default;

  • README.mdThe resources in must all be HTTPS, if it is HTTP, the publishing will fail;

  • CHANGELOG.mdwill be displayed in the Changes tab;

  • If the code is placed in gitthe warehouse and the field is set repository, it must be submitted before publishing git, otherwise it will promptGit working directory not clean

  • It takes a few minutes for the application market to be updated after release;

  • Of course, you can search in the plug-in market chatgpt-for-vscode to try this plug-in;

    2c8d1e6321f979bb4c577eb4a2ec2742.png

Summarize

The above is ChatGPTthe basic creation process of a plug-in, the core is the understanding and use of VSCode APIand ChatGPT API. Of course, all the functions you need can be found in the corresponding official documents.

references:

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 -

About Qi Wu Troupe

Qi Wu Troupe is the largest front-end team of 360 Group, and participates in the work of W3C and ECMA members (TC39) on behalf of the group. Qi Wu Troupe attaches great importance to talent training. There are engineers, lecturers, translators, business interface people, team leaders and other development directions for employees to choose from, and supplemented by providing corresponding training on technical skills, professional skills, general skills, leadership skills, etc. course. Qi Dance Troupe welcomes all kinds of outstanding talents to pay attention to and join Qi Dance Troupe with an open and talent-seeking attitude.

8a105c36a3de2f7566ce7ed44ac623c1.png

Guess you like

Origin blog.csdn.net/qiwoo_weekly/article/details/132680254