当前位置: 首页 > news >正文

vscode插件开发笔记——大模型应用之AI编程助手

系列文章目录

文章目录

  • 系列文章目录
  • 前言
  • 一、代码补全


前言

最近在开发vscode插件相关的项目,网上很少有关于大模型作为AI 编程助手这方面的教程。因此,借此机会把最近写的几个demo分享记录一下。

一、代码补全

思路:

  1. 读取vscode插件上鼠标光标的上下文信息。
  2. 将提示词和上下文代码作为输入,通过modelfusion调用大模型得到输出。
  3. 将输出内容插入到光标所在位置,通过Declaration在vscode页面进行显示。
  4. 设置快捷键,如果代码补全正确,按下快捷键后自动插入代码。反之光标移动,代码自动消失。

下面直接上代码。
extension.ts 文件:

import * as vscode from 'vscode';
import {BaseUrlApiConfiguration,openaicompatible,streamText,} from 'modelfusion';
import{ previewInsertion, getBeforeText, getAfterText }from '../src/main'export function activate(context: vscode.ExtensionContext) {// Use the console to output diagnostic information (console.log) and errors (console.error)// This line of code will only be executed once when your extension is activatedconsole.log('Congratulations, your extension "dytest" is now active!');let globalText:string|undefined ; let globalindex: vscode.Position | undefined;// 如何删除字符const editor = vscode.window.activeTextEditor;// 代码补全命令const disposable = vscode.commands.registerCommand('dytest.helloWorld', async () => {if (!editor) {return;}// 代码所在位置const code =editor.document.getText();//光标所在位置const offset =editor.document.offsetAt(editor.selection.active);const index = editor.document.positionAt(offset);const position = editor.selection.active;const document = editor.document;const beforeText = getBeforeText(document, position);const afterText = getAfterText(document, position);// 调用大模型const code_prompt='提示词';const code_instruction='{{{prefix}}}[BLANK]{{{suffix}}}';const code_instruction_2=code_instruction.replace("{{{prefix}}}", beforeText).replace("{{{suffix}}}",afterText)console.log(code_instruction_2)
const text2 = await streamText({model: openaicompatible.ChatTextGenerator({// 这里使用的是自己部署的大模型,url和openai的一样。但是模型不是用的openai系列的。如果要改,可以换成openai的。api: new BaseUrlApiConfiguration({baseUrl: "模型的url",headers: {Authorization: `模型的api`,},}),provider: "openaicompatible-fireworksai", // optional, only needed for logging and custom configsmodel: "自己的模型",}).withInstructionPrompt(),prompt: {system:code_prompt,instruction:code_instruction_2},});let responseUntilNow = "";for await (const textPart of text2) {// process.stdout.write(textPart);responseUntilNow += textPart;}console.log(responseUntilNow)// 进行代码补全的提示const previewinsertion =previewInsertion(editor,index,responseUntilNow);globalText=responseUntilNow;globalindex=indexvscode.window.showInformationMessage('Hello World from dy_test!');});context.subscriptions.push(disposable);const disposable2 = vscode.commands.registerCommand('extension.myCommand', async () => {editor?.edit((editBuilder => {if (!globalindex || !globalText){return;}const lines = globalText.split(/\r\n|\n/); // 分割文本editBuilder.insert(globalindex, lines[0])globalindex=undefined;globalText=undefined;}));vscode.window.showInformationMessage('Hello World from myextension!');});let timeout: NodeJS.Timeout | undefined;context.subscriptions.push(disposable2);// 注册事件监听器以在特定条件下调用命令context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(editor => {if (editor) {// 延迟调用命令if (timeout) {clearTimeout(timeout);}timeout = setTimeout(() => {vscode.commands.executeCommand('dytest.helloWorld');}, 200); // 延迟}}));context.subscriptions.push(vscode.window.onDidChangeTextEditorSelection(event => {if (timeout) {clearTimeout(timeout);}timeout = setTimeout(() => {vscode.commands.executeCommand('dytest.helloWorld');}, 200); // 延迟}));
}
export function deactivate() {}

main.ts文件:


import {parse}from '@babel/parser'
import traverse from '@babel/traverse'
import * as vscode from 'vscode';// 代码补全插入
export function previewInsertion(editor: vscode.TextEditor, position: vscode.Position, text: string, ) {const range = new vscode.Range(position, position.translate({characterDelta: text.length}));let currentDecoration: vscode.DecorationOptions[] | undefined = undefined;let decorationType: vscode.TextEditorDecorationType | undefined = undefined;const lines = text.split(/\r\n|\n/); // 分割文本
let lineCount = 0;
let totalCharacterCount = 0;// 计算总行数和总字符数
for (const line of lines) {lineCount++;totalCharacterCount += line.length;
}
totalCharacterCount--;
console.log(lineCount); // 输出非空行数if (!decorationType) {decorationType = vscode.window.createTextEditorDecorationType({light: { // Light theme settingsafter: {contentText: lines[0],fontStyle: 'italic',color: '#7f8c8d', // 灰色backgroundColor: 'transparent',//  textDecoration: 'none',margin: '0 0 0 0',},},dark: { // Dark theme settingsafter: {contentText: lines[0],fontStyle: 'italic',color: '#95a5a6', // 灰色,适合深色主题backgroundColor: 'transparent',//  textDecoration: 'none',margin: '0 0 0 0',}, }
});
}const endPosition=position.translate({lineDelta:lineCount-1,characterDelta:totalCharacterCount })
console.log("position:",position)
console.log("endPosition:",endPosition)// 创建装饰器选项currentDecoration = [{range: new vscode.Range(position, position),hoverMessage: new vscode.MarkdownString('按“tab”键确认'),
}];// 应用装饰器
editor.setDecorations(decorationType, currentDecoration);// 监听鼠标移动事件,移除装饰
const mouseMoveDisposable = vscode.window.onDidChangeTextEditorSelection((event) => {if (event.textEditor === editor) {editor.setDecorations(decorationType, []);currentDecoration = undefined;}},null,);}// 获取文本上下文信息
export function getBeforeText(document: vscode.TextDocument, position: vscode.Position): string {const range = new vscode.Range(new vscode.Position(0, 0), position);return document.getText(range);
}
export function getAfterText(document: vscode.TextDocument, position: vscode.Position): string {const lastLine = document.lineCount - 1;const lastLineLength = document.lineAt(lastLine).text.length;const range = new vscode.Range(position, new vscode.Position(lastLine, lastLineLength));return document.getText(range);
}

package.json

添加两个命令

"commands": [{"command": "dytest.helloWorld","title": "Hello World"},{  "command": "extension.myCommand","title": "My Command"}
]

快捷键

   "keybindings": [{"command": "extension.myCommand","key": "ctrl+shift","when": "editorTextFocus"}]

实现效果:

代码补全(2)

目前遇到的问题:函数级代码生成后,通过Decoration装饰器无法显示全部的。希望有大佬指点一下。

http://www.lryc.cn/news/408302.html

相关文章:

  • @JSONField(format = “yyyyMMddHH“)的作用和使用
  • 计算机网络 6.1Internet概念
  • 编写SpringBoot的自定义starter包
  • 【LeetCode:3106. 满足距离约束且字典序最小的字符串 + 贪心】
  • 25 Python常用函数——reduce()
  • oracle登录报“ORA-27101: shared memory realm does not exist”
  • 界面控件Telerik UI for WPF 2024 Q2亮点 - 全新的AIPrompt组件
  • IT服务运营过程中的资源要素管理(至简)
  • wodpress设置固定链接的方式和好处【SEO优化】
  • 【C#】 CancellationTokenSource 与Thread的启动、取消的区别?
  • 基于 HTML+ECharts 实现智慧运维数据可视化大屏(含源码)
  • AIGC(Artificial Intelligence Generated Content)
  • 02 MySQL数据库管理
  • C++编程: 使用 Nanomsg 进行 PUB-SUB 模式基准测试
  • 【Unity2D 2022:Data】读取csv格式文件的数据
  • 美团测开面经整理大汇总!!
  • 微信公众号获取用户openid(PHP版,snsapi_base模式)
  • DuckDB核心模块揭秘 | 第1期 | 向量化执行引擎之Pipeline
  • Vue如何让用户通过a链接点击下载一个excel文档
  • 美摄科技企业级视频拍摄与编辑SDK解决方案
  • MySQL:增删改查、临时表、授权相关示例
  • 初识git工具~~上传代码到gitee仓库的方法
  • Redis知识点总价
  • 大语言模型-GPT-Generative Pre-Training
  • mybatis批量插入、mybatis-plus批量插入、mybatis实现insertList、mybatis自定义实现批量插入
  • Springboot项目的行为验证码AJ-Captcha(源码解读)
  • 【初阶数据结构篇】时间(空间)复杂度
  • C# 设计模式分类
  • 前端模块化CommonJS、AMD、CMD、ES6
  • 论文阅读:(DETR)End-to-End Object Detection with Transformers