【可能有点用】一个简易 vscode 语音插件

前言:最近参与的项目是react,代码量不少,而我比较菜,需要在往返于各个文件里查看代码,非常繁琐,有时候找文件都翻半天,这个时候就非常想让vscode帮我处理了,比如我说,vscode,帮我跳转到xx文件夹,就打开对应的文件,想想就令人舒爽,设置口述代码,让语音接入的ai来给我写代码,这是在太酷了不是吗。

开干!

0.预览

先看看插件的预览效果,目前支持简单的光标移动,换行,插入文本。

代码地址:stillwarter/vscode-voicehandle-st: 一个vscode的简单语音处理插件 (github.com)

1.init vscode 插件

首先需要使用yo 去生成一个vscode插件嗷,具体的流程请查阅各文章(我也是看的网上的教程)或者查询 @imlinhanchao 的近期帖子,有关于插件的教程。

在生成完插件后,就需要考虑具体实现了。

2.vscode 插件 webview

鱼排是有vscode插件的,这也是我敢于直接进行插件开发的原因,跳跳大佬是做过的,不懂可以问一下。当然在开发过程中也问了其他网友。

鱼排的插件用了webview这个插件提供的功能,可以支持类似web页面的编码,在插件的提现就是使用iframe来渲染你的web代码。这就意味着你可以很方便的控制你想渲染的效果(使用html和css),当时我想把语音的图形化界面放到webview里,在webview里使用浏览器带有的语音转文字api,这样的方式来实现语音控制。

但是vscode狠狠给了我一拳😭 ,tmd这个东西没有获取语音权限的能力,我当时熬夜到2点,百度到心态破碎。

7f4fe3ae7edce3cc7753be847244819.jpg

经百度和人工询问网友,被告知vscode 插件的环境是是node,得通过node来进行录音。

😭 只能放弃使用webview来录音的想法。

3.pupperteer

webview没有获取录音权限的能力,但同类型的vscode-speech插件是如何做到录音的呢?他山之石可以白嫖,我火速打开github搜索起来。

很遗憾,我没在vscode的开源库里找到这个vscode-speech,但很幸运我看到这个库:https://github.com/M-S/vscode-speech-to-code

这个库的作者说可以用puppeteer来与浏览器连接进行语音功能的开发。斯巴拉西!很好,这下又可以继续这个插件的开发了(不然感觉就腹死胎中)。

puppeteer是一个无头浏览器的库,无头浏览器我理解为浏览器的命令版,无图形界面的那种,你可以用他对浏览器页面进行一些监控,在此之前我也没接触过这个。然后花了空闲时间用他的puppeteer-core调用本机的edge浏览器核心,通过这个来获取浏览器环境。

4.功能开发

之前在【StartNode】里面其实有一个语音转文字的功能完成,但是说实话我用StartNode的机会很少了,因为工作忙了写日常记录的时间也很少了。看等后面把这个东西能不能串联到vscode插件里面。

那么我们功能上获取语音,语音转文字的部分算是完成了。接下来就是语音文字的处理。目前我想的处理流程是:

使用插件命令--插件使用puppeteer连接无头浏览器--浏览器使用语音api获取语音文本--在语音解析中心解析文本并执行对应操作

4.1 语音文字处理中心

最简单的处理方式就是,根据不同的文字命令执行不同的操作。那么这样一来势必导致许多的if判断。那么先准备一个语音处理中心函数吧,所有命令通过这个函数来进行判断。

在这个函数执行前,我们可以先预设需要检测的函数,也就是说,在获取到语音文本后,处理中心会循环预设数组内的函数并执行,若执行完一个函数就break;

这样的效果就是,比如我的一段文本语音里包含'光标'这个指令,那么他就不会执行下一个预设函数。

/**
 * 语音检测预备流程集合
 */
const voiceCheckBeforArr = [editorSelectionCheck, editorCtxCheck];

/**
 * 语音输入检测中心
 */
const voiceCheckCenter = (word: string) => {
  // console.log(word);
  vscode.window.setStatusBarMessage(word);
  for (const item of voiceCheckBeforArr) {
    const sign: any = item(word);
    if (sign) {
      vscode.window.showInformationMessage(sign.keyvalue + "指令已运行完毕。");
      break;
    }
  }
  // voiceCheckBeforArr.map((item) => item(word));
};

4.2 预设解析函数

上个部分说过预设函数,预设函数就是对应每个指令的操作函数,比如我的语音文本里有'插入'这两个字,运行到对应预设函数是就会执行插入文本的操作,一下是插入文本操作的预设解析函数:

/**
 * 语音编辑文件内容
 */

/* 语音文本内容关键词检测 */
const ctxKeyWords = ["插入", "换行"];

function chectCtxKeyWords(word: string) {
  let re;
  for (const item of ctxKeyWords) {
    if (word.includes(item)) {
      re = item;
      break;
    }
  }
  // console.log('re:',re);
  return re;
}

/* 根据关键词不同 执行对应操作 */
const editorCtxCheck = (word: string) => {
  if (chectCtxKeyWords(word) === "插入") {
    inserText(word.replace("插入", "").replace("。", ""));
    return {
      finish: true,
      keyvalue: "插入",
    };
  }

  if (chectCtxKeyWords(word) === "换行") {
    inserText_newLine();
    return {
      finish: true,
      keyvalue: "换行",
    };
  }
};

4.3 解析完成提示

语音解析中心,执行指令后,会返回一个对象sign,这个时候会判断sign是否存在,存在的话就插件就提示对应的指令已经执行。

5.开发和使用

我暂时不会考虑发布,如果你有兴趣调试和开发的话,请先准备:

1.node 环境。(版本最好不低于18,低的话可能puppeteer兼容有问题)

2.edge浏览器以及对应exe路径位置。

由于puppeteer-core需要连接你的浏览器核心,所以你需要知道你的edge浏览器的核心路径(其实就是你c盘下,edge对应的msedge.exe文件,百度应该查得到)其实谷歌浏览器也可以,不过听说使用谷歌浏览器的语音转文字api需要翻墙?最开始我也连接的谷歌浏览器,用他的语音处理api确实没反应,edge就没这个问题。有无大手子解惑一下。

3.vscode。

当你这些准备好后,vscode打开本插件项目,按下F5,运行插件宿主环境后,(win)键盘输入shift+ctrl+p,输入openpush,就运行成功了。

6.后续

其实现在做到的功能还蛮开心了,实现了一个小想法,嘿嘿;但是我还并未打包发布过插件,最终效果好不好我也不知道,他这个api也不是很灵敏,可能最终效果也就那样,算是个玩具...(还有很多问题需要解决吧)

不过我自己是可以使用这个语音功能的,应该会在空闲时间慢慢完善,可能会对整个的一个语音解析流程做一个调整和优化吧?

其实能做语音转文本,就能做文本转语音,或许和完成与vscode(也不一定局限于vscode)的对话也可以呢?

说实话这个可能摸到了npl的门槛,在开发语音解析的时候其实很吃力,有时候并不知道怎么解析好。如果有机会有时间还是想学学一些自然语言处理的知识,看看那些高大上的算法和理论 😳

这个东西只能算一个拼装的玩具,我算应证前端裁缝这个说法了,我感觉我也只是那别人做的厉害的东西进行合并,希望未来有一天,我能做一下更底层的东西,来实现一些很酷的想法!(凭借技术力能够做到成为席卷人间的巨浪吗?)

7.参考文章,文档以及帮助者

M-S vscode-speech-to-code

如何在vscode扩展里使用webview

初识 Vscode 插件开发 - 知乎 (zhihu.com)

Puppeteer 中文网 (nodejs.cn)

javascript - Puppeteer实践:复杂的问题简单化 - 南城FE - SegmentFault 思否

Does VS Code extensions API support changing cursor position? - Stack Overflow

为什么当我输入第一个vscode扩展时没有匹配的命令?-腾讯云开发者社区-腾讯云 (tencent.com)

感谢跳跳 @imlinhanchao 和尘老的解答,以及M-S这位开源者。