• 作者:老汪软件技巧
  • 发表时间:2024-11-12 21:03
  • 浏览量:

大家好,我是双越老师,也是 wangEditor 作者。

今年我致力于开发一个 Node 全栈 AIGC 知识库项目划水AI,包括 AI 写作、多人协同编辑。复杂业务,真实上线,大家可以去注册试用。

今天和大家分享一下 划水AI 是如何开发 AI 编辑器,其中遇到了哪些问题,做了哪些优化。

没那么简单

谈论到 AIGC、 AI 应用场景的话题,很多人都会抬高鼻子说话:不就调调接口吗,有什么技术含量吗?

研发发动机的有技术含量,把发动机装配到汽车上并调教好的,也同样有很高的技术含量。只是不同的领域而已。

借助 AI 服务开发一个 AI 编辑器,这并不简单。首先富文本编辑器就挺麻烦,再集成 AI 功能就更麻烦,例如

具体的可以去 划水AI 注册试用一下,如遇到问题可提交 issue ,我们也在不断的优化改进中。

看完这几个问题,也许你能体会到:这个工作说不上多难,但它的使用场景足够复杂 —— 这其实很像我们日常工作中的项目,并不是多难多深,但业务场景很麻烦。

而我们在公司中的价值就是:使用技术手段解决复杂的业务场景和功能,而不是深挖内部和原理。

你就是熟读 V8 引擎源码,只要你去找工作,你每天也就是增删改查,并拿着相应的工资。除非你有能力自己创业。

设计了哪些功能?AI 生成文本

如文章一开始的 gif 动图,输入指令(或点击一个菜单)根据当前文章的标题和内容,让 AI 帮你写一段文字。

你可以写大纲、头脑风暴。或针对一篇已有的文章,续写、写总结。

AI 处理文本

如下图,选中一段文字,让 AI 帮你处理、优化并生成新的版本。例如让 AI 扩展、简化、翻译、切换语气等。

前几天我和一个同学评审简历,他对于工作职责不会写,我就随便写了一句话,然后选中,让 AI 帮我扩展。这样他就可以根据扩展出来的内容来写、甚至面试的时候可以根据这些来表达。

写作真难_写作太难了_

未来扩展

AI 是一个可想象空间非常大的方向。现在 划水AI 处理文本,未来可以借助 AI 的能力来处理图片、视频、文档等。

可用的 AI 接口服务

几个月前我刚开始调研时写过一篇文章 用 Node.js 调用 ChatGPT API 实现 Stream 流式聊天效果

聊天,相比于编辑器,实现起来是比较简单的,所以这里更多的是调研如何使用 AI 接口,当时 ChatGPT 还没有对国内禁用服务。

但后来 OpenAI 禁止国内访问他们的 API 服务,但我们可以借助中转服务,例如 Deepbricks ,使用方法和 ChatGPT 是一样的,价格也足够便宜。

import OpenAI from 'openai'
const openai = new OpenAI({ apiKey: 'xxxxxxxxxxxx' })
async function main() {
  const completion = await openai.chat.completions.create({
    messages: [{ role: 'user', content: 'How are you today?' }], // 消息内容
    model: 'gpt-3.5-turbo',
    max_tokens: 20, // 限制返回字符,帮你节省额度
  })
  const result = completion.choices[0]
  console.log('result: ', result)
}
main()

鉴权和计算 token

如下图,请求 AI 接口时需要携带 token ,但如果你的 token 被泄漏了或者被调用了怎么办?虽然 token 可以设置 timeout 但如果多次泄漏呢?

我当时被这个问题困扰很久,后来考虑到一个非常简单的方法:token 中加密 userId ,然后用 userId 对应 token 使用量,再配合 timeout 就不会有这个问题了。

所以,在发送请求时需要加密 token ,包含 time 和 userId

  // join token
  const dt = Date.now()
  const content = { dt, userId: user.id }
  const token = CryptoJS.AES.encrypt(JSON.stringify(content), AUTH_KEY).toString()
  url.searchParams.set('x-auth-token', token) // Add auth token

在 AI 服务中使用同样的 secret 解密 token ,解密失败就返回 error

  // decrypt token
  const authTokenRaw = query['x-auth-token'] || ''
  const tokenInfo = decryptToken(authTokenRaw)
  if (tokenInfo == null || !tokenInfo.userId) {
    const errMsg = 'invalid token'
    console.log('error: ', errMsg)
    ctx.res.write(`data: [ERROR]${errMsg}\n\n`) // 格式必须是 `data: xxx\n\n` !!!
    return
  }
  // console.log('tokenInfo.... ', tokenInfo)

然后拿 userId 去查询是否还有使用量,如何达到 limit 就要报错提示。

  // check token usage
  const { userId } = tokenInfo
  const usage = await getTokenUsage(userId)
  // console.log('usage: ', usage)
  if (usage == null) {
    const errMsg = 'token usage not found'
    console.log('error: ', errMsg)
    ctx.res.write(`data: [ERROR]${errMsg}\n\n`)
    return
  }
  const { tokensLimit, totalTokens } = usage
  if (tokensLimit <= 0) {
    const errMsg = 'token usage limit exceeded'
    console.log('error: ', errMsg)
    ctx.res.write(`data: [ERROR]${errMsg}\n\n`)
    return
  }

所以,虽然是调用第三方的 AI 服务,但在实际使用的时候会有很多情况,需要设计和实现。

最后

我在开发 划水AI 时候记录了详细的研发过程,包括调研、设计、代码修改记录、测试用例等,还有遇到的各种问题 bug 、调研、思考、修改过程。有兴趣的同学可私聊我。