Vue3+NodeJS 接入文心一言, 发布一个 VSCode 大模型问答插件

目录

一:首先明确插件开发方式

[二:新建一个Vscode 插件项目](#二:新建一个Vscode 插件项目)

[1. 官网教程地址](#1. 官网教程地址)

[2. 一步一步来创建](#2. 一步一步来创建)

[3. 分析目录结构以及运行插件](#3. 分析目录结构以及运行插件)

[三:新建一个Vue3 项目,在侧边栏中展示,实现vscode插件 <=> vue项目 双向消息传递](#三:新建一个Vue3 项目,在侧边栏中展示,实现vscode插件 <=> vue项目 双向消息传递)

[1. 新建vue3+vite+ts项目](#1. 新建vue3+vite+ts项目)

[2. 将web页面展示在vscode侧边栏](#2. 将web页面展示在vscode侧边栏)

[(1) 插件项目修改,把视图注册到侧边栏,完成消息传递](#(1) 插件项目修改,把视图注册到侧边栏,完成消息传递)

[(2) web项目修改,增加事件监听](#(2) web项目修改,增加事件监听)

四:接入大模型对话能力,实现ChatUI

[1. 大模型接入准备](#1. 大模型接入准备)

[2. nodejs调用api](#2. nodejs调用api)

[3. 前端接口调试](#3. 前端接口调试)

五:注册开发者账号并发布插件

[1. 推荐教程](#1. 推荐教程)

[2. 增加插件商店图标](#2. 增加插件商店图标)

[3. 前端资源的缓存策略会影响插件web页面的实时更新](#3. 前端资源的缓存策略会影响插件web页面的实时更新)

六:实战能力探讨(会持续更新,欢迎探讨)

[1. 行内提示功能的设计与实现(InlineCompletionItemProvider9)](#1. 行内提示功能的设计与实现(InlineCompletionItemProvider[9]))

[2. SSH 远程打开文件能力(使用 remote-ssh 插件提供的命令)](#2. SSH 远程打开文件能力(使用 remote-ssh 插件提供的命令))

[3. Json 文件可视化编辑(JsonToHtml)](#3. Json 文件可视化编辑(JsonToHtml))


随着大模型能力越来越卷,在垂直领域的落地也在加快,对于大模型代码生成能力而言,最简洁高效的方式就是集成为常用IDE的插件,在vscode的插件战场中,比较知名的就有 GitHub Copilot, 智谱清言的codegeex, 讯飞星火的iFlyCode。

那么我们就以开发一个简易的大模型对话插件,来探究一下vscode插件开发到发布的流程,研究一下文心一言大模型api的接入

跟着操作大约30-60分钟,你需要

  • 安装vscode,npm/yarn等,node版本 >12.0

  • 最好有时间提前看一看 vscode 官网api开发文档1

万字长文 Action!

一:首先明确插件开发方式

  1. 如果你的插件只提供原生vscode能力,没有复杂的UI需求,只需要在vscode插件项目上开发即可,类似插件比如Volar Git History Eslint

  2. 如果提供复杂UI交互,定制化界面,就需要在vscode插件内嵌iframe页面(用iframe展示线上web地址与使用vscode提供的一套UI组件皆可,详见第三节),我这里选择访问线上地址,因此需要开发一个vscode插件项目与一个vue3项目(其他框架亦可),类似的复杂插件比如 CodeGeeX iFlyCode,会将web页面展示在侧边栏中。

image.png

本文主要讲解 如何在vscode插件中通过iframe展示web页面,获得更好的拓展性与可维护性

二:新建一个Vscode 插件项目

1. 官网教程地址

开始你的第一个插件项目2

2. 一步一步来创建
  • 找到一个比较舒服的文件夹,打开cmd,通过以下命令安装 vscode项目脚手架,取的是 registry.npmjs.org3 镜像源,因此可能会有科学问题

    复制代码
    npm install -g yo generator-code
  • 安装完成后,直接用命令创建新的插件项目

    yo code

  • 进入配置页面,默认就选择 NewExtension(TypeScript),后面的按照图中来就可

  • 然后会自动创建好项目,并执行npm i,然后用 vscode 打开项目

3. 分析目录结构以及运行插件

目录结构就很清晰了,我们主要涉及修改 extension.ts 以及 package.json文件

上图中,extension.ts 中 activate() 方法就是插件的入口函数,每次插件启动都会执行此函数,当前代码是注册了一个hello world命令,当你在vscode中通过 ctrl+shift+p 调出输入框并输入hello world,就会执行此注册命令的回调,弹出一个message框,下面我们来试一下

在当前项目中,直接按F5,会启动一个扩展开发宿主,你的插件就运行在这个vscode窗口上啦 下面我们调出命令输入框ctrl+shift+p ,输入 hello world, 会提示命令,选中执行,右下角会发现弹了一个message!!!

什么?你的没弹出?那你岂不是和我当时一样倒霉,但你不需要花时间去挖这个奇怪的~bug !

首先看一下你的vscode版本

image.png

当前vscode版本不能低于 package.json 中的最低版本要求!

这样写表示最低支持到1.83.0版本!改一下重新reload一下宿主插件,再试试命令就可以弹出啦!到此我们的插件侧项目就搭建好了,下面我们简单建一个vue项目,嵌入到侧边栏中

三:新建一个Vue3 项目,在侧边栏中展示,实现vscode插件 <=> vue项目 双向消息传递

文章开头我们提到,插件内展示丰富的UI,既可以用iframe展示线上web网页,也可以在插件内部用vsode ui实现。下面我主要演示用iframe的方式,另一种嵌入方式推荐大家去看一下 CodeGeeX 插件4源码如何做的,引入了一套vscode风格的UI组件@vscode/webview-ui-toolkit,源码里面的webviewUI文件夹与translationWebviewProvider.ts文件都是相关代码。

1. 新建vue3+vite+ts项目

找一个舒服的文件夹,打开cmd

复制代码
    npm init vite

执行后按需选择自己的框架与开发环境,然后run dev一下子,拿到地址, 比如 http://localhost:5173/

2. 将web页面展示在vscode侧边栏
(1) 插件项目修改,把视图注册到侧边栏,完成消息传递

第一步当然是先建一个iframe把我们的web项目的地址填进去呗,开始。

vscode 提供了两种创建iframe的方法,WebviewViewProvider 和 createWebviewPanel,选其一即可,这里我们介绍一下WebviewViewProvider如何使用

首先在extension.ts 同级目录下新建 chatWebview.ts

  • WebviewViewProvider 是一个接口,因此建一个自己的类实现它的方法即可

    下面我们创建一个实现WebviewViewProvider接口的类ChatWebview

    chatWebview.ts 文件: (可直接运行)

    具体代码作用看注释

    import { window, Position, WebviewView, WebviewViewProvider } from "vscode";
    export class ChatWebview implements WebviewViewProvider {
    // 写一个public变量,方便对象引用创建后的webview实例,但是可能存在还未完全解析完成时,访问值为null
    // 看了vscode api发现,resolveWebView 返回一个 Thenable,可以在解析完成后拿到webview实例
    // 但是这个函数是在webview容器第一次显示时自动执行,不需要手动调用,不知道怎么拿到Thenable
    public webview: WebviewView | null = null;
    resolveWebviewView(webviewView: WebviewView): void | Thenable {
    this.webview = webviewView;
    webviewView.webview.options = {
    enableScripts: true,
    };
    // 监听web端传来的消息
    webviewView.webview.onDidReceiveMessage((message) => {
    switch (message.command) {
    case "WebSendMesToVscode":
    // 实现一个简单的功能,将web端传递过来的消息插入到当前活动编辑器中
    let editor = window.activeTextEditor;
    editor?.edit((edit) => {
    let position = editor?.selection
    ? editor?.selection.start
    : new Position(0, 0);
    edit.insert(position, message.data);
    });
    return;
    }
    }, undefined);
    // webview 展示的内容本身就是嵌套在一个iframe中,因此在此html中再嵌套一个iframe时,需要传递两次postMessage
    webviewView.webview.html = `