Skip to content

语翼数字人 h5

语翼数字人是一款录制音色、视频生成结合商品文案生成门店销售的数字人系统,可以一键发布到抖音、快手等各个平台的自动化平台,还包含 ai 数字人直播、直播台词生成、违禁词审核。

AI 台词流式生成

当时接到这个需求,最开始是调用后端的接口,由后端将内容全部生成完成后,再返回给前端。因为直播台词可能很长,少则 2、3 分钟,多则十几分钟,这在调试阶段和最后测试的时候都非常麻烦。

随后给产品提出的流式渲染,接到这个需求后,我当前觉得很好实现,之前做过类似的,用的 v-html 进行渲染,不过由于 v-html 是全量渲染的,内容多了会造成页面卡顿和抖动。

于是尝试借助 vnode 进行由于,因为 vnode 可以绑定 key,可以优化渲染,从而实现增量更新。

具体的实现思路是采用 markdown-it 将 markdown 文本转为 token,针对于不同的节点类型手动创建 vnode 节点,然后通过动态组件渲染到页面上。

由于封装的是通用组件,当前需求可能没有过多的样式,只是纯文本,但是对于一些加粗、下划线、代码块这些格式内容也做了智能解析。

如果在解析到加粗的**的时候,如果整段内**的数量是单数,就手动在末尾补齐**,这样在渲染的时候,就可以直接渲染成加粗了。

代码块也是如此,需要在末尾补齐反引号,可以直观的看到代码块,不必等到最后代码块解析完成后才展示。

对于图片,在图片内容获取完成前,都不进行渲染,或者采用内容占位,直到图片或者链接内容完整后才进行替换。

CSS 变量抽离 + VS Code 插件开发

这是在进入公司后第一个项目,当时这个数字人短视频在公司内部使用效果不错,需要新开发一个 app,供其他公司使用。相当于是两个新旧项目同时开发,但是在老项目中的 css 颜色都是硬编码的,对于后期维护成本是非常大的,mt 把这个任务给我了,让我抽离成变量方便复用,最开始采用的是 sass 的 mixin 生成对应颜色系列的变量,但是由于项目中使用了 tailwind,由于 tailwind 采用的是静态 css,使用不了 sass 变量,要结合 sass 可能就需要结合 postcss,这样的话就增加了开发成本。

其实这个 css 变量无非就是一个命名规范的问题,先定义颜色变量基色,然后扩展语义化的变量名,然后就是把项目中用到的颜色变量替换成对应的变量名。这个过程比较枯燥,不过也是熟悉项目功能的办法。

当我将变量抽离完成后,mt 就提出了个新的问题,就是当其他人在使用的时候,来回查看 css 变量声明文件,挨个对比颜色,会非常的麻烦,有没有什么办法可以提升效率,不然后面还是会只写颜色值的。

最开始考虑的是在 git 提交的时候,进行颜色变量的替换,但是对于 vue 模版的 style 解析,边界处理稍微复杂,还要考虑多个 style 标签的情况。

所以最后考虑的是采用 VS Code 插件进行辅助编写,通过读取本地的 .autocolorvars.cjs 文件,然后通过 node 内置的 vm 模块,创建沙箱去读取并运行文件,然后得到配置文件的配置内容,有个 cssFiles 数组,可以配置变量文件的路径,然后读取文件,然后通过正则匹配,递归获取到变量的 key 和 value,然后提供一键替换和自动补全功能。

AI 提示词优化

这个内容主要是我们有个通过用户描述提示词,生成对应商品的文案,但是下面有关键词选择,例如:母婴、育儿等四字关键词。

但是这个关键词的生成,只能通过 prompt 来生成,需要用提示词描述,返回准确的 json 格式,确保前端渲染无误。

在 open ai 的标准中是有个 response_format 参数来约束生成标准的 json 格式,但是由于这个 gpt 接口是公司内部的,没有这个参数,只能从提示词下手。

有一种“邪修”,就是在描述你的需求后,给一段不完整的 json,例如一个单括号,ai 就会自动补全 json

生成关于孩子王的4字关键词,以title的json格式返回:{“title”:

当然这种办法只是概率高,就是不够优雅。

采用的是用自然语言规范 json 生成的要求,用双大括号去标识动态的模版变量,可以大大提高生成的成功率。同时 ai 生成的内容不是百分百的,所以还需要做到错误的兜底。

txt
你的任务是根据给定的企业属性,生成与企业属性和短视频拍摄相关的主题关键词。
以下是企业属性:
<企业属性>
  {{COMPANY_ATTRIBUTE}}
</企业属性>
{{COMPANY_ATTRIBUTE}}变量内容为:${promptVar}
请按照以下要求生成关键词:
1. 每个关键词的字数控制在3 - 4个字以内。
2. 生成的关键词数量必须在10 - 15个。
3. 关键词之间用','隔开,不要额外内容,便于我做切割。

这个思路在后面的违禁词检测的需求也使用到了。

源码定位插件

在公司实习的时候,我接手了一个项目,听 mt 说之前的工期比较短,很多组件都是直接 cv 的并没有进行过多的拆分,导致项目中有非常多重复的组件,不同页面相同功能的组件比比皆是,导致维护困难。

因为在我们平时上手一个新的项目的时候,需要快速上手、完成开发需求。但是如果一个项目过大,就会导致熟悉的过程变得很长。一般的流程都是:打开对应的页面的 url,去根据路由去找到对应的页面,再根据页面路径去找到对应的组件。但是有些项目路由嵌套过多,就会导致需要在不同文件之间来回进行跳转查看。有些时候不得以需要通过页面的一些关键字变量去编辑器全局搜索,有时候搜索的结果也非常多非常杂乱。对于一些动态变量,例如后端传来的数据,编辑器是无法定位到的。

而且有些时候,只是一个小需求,小 bug,需要对这个项目临时进行处理,可能并不会给太多时间让你去熟悉项目。

对于这些痛点问题,所以我开发了一款 vite 插件,可以做到点击页面元素,跳转到对应的组件文件。

我的思路是在构建、编译、运行三个阶段进行处理。

  1. 构建阶段是借助的 vite 插件,使用 transform 钩子可以识别到 .vue 文件

  2. 编译阶段是在 transform 钩子中借助 vue 的 sfc 的 parse 进行模版编译,采用自定义属性,借助 ast 树,对 vue 的根节点添加上路径标记,并对路径进行压缩,压缩是为了进行文件体积优化,同时加快 diff 效率,由于路径可能会带有服务器目录结构,产生暴露风险,压缩可以降低被暴露的风险。这一步的目的是为了给下一步提供标识的。

因为 vue3 组件可能有多个根节点,可以借助 ast 更有效的递归添加自定义属性,比 transform 的纯字符串更方便操作。

  1. 最后在运行时阶段,借助猴油脚本,使用 document.querySelectorAll('*')获取到所有的节点,然后通过 Array.from 转为数组后调用 filter 去过滤掉不包含自定义元素的节点,识别到页面上所有的自定义元素,解析出映射关系,并解码出对应的路径即可。

缺点:因为 vscode 出于安全考虑,打开 vscode 的 uri 需要是本地的 localhost,如果项目配置了开发的 host 就不生效了,如果 uri 不匹配,则进行了兜底,将文件路径复制出来,在 vs 中进行跳转即可。

相比于 vue-devtools,在线上的测试环境下是用不了的,没有办法定位。

数据埋点

公司的埋点方式主要是 pv 和 uv 的埋点,像一些自动埋点已经是集成在 cli 中了,例如 dom 埋点和 sentry。

我需要做的就是在这一版需求上线后,根据产品和运营的要求,对页面特点内容进行采集,例如按钮等

sdk 修改(改版后的简历无此项)

sdk 修改是因为当时语翼项目是迁移的另一个 app,但是当时使用到的 sdk,中间的环境判断是写死在老 app 的 sdk 中的,只是做了兼容处理。

同时当时遇到一个问题就是 copy 问题,同一个 sdk 的方法,需要调用原生给的方法,在安卓平台,不同的页面可能导致 copy 失效的问题,考虑到的原因可能是方法的初始化和注册时机的问题,所以 copy 代码进行了初始化时机的判断,如果没有初始化好,就采用浏览器原生的方法。