前言
随着AI越来越火热,越来越多的产品都接入了DeepSeek,今天我们就来尝试在微信小程序中集成国产顶尖大模型DeepSeek,解锁智能对话|实时翻译|长文本生成三大核心场景。
准备工作
- 注册一个微信小程序账号,并且创建本地小程序工程项目
- 小程序基础库需要在
3.7.1
及以上版本,具备 wx.cloud.extend.AI 对象 - 小程序需要开通「云开发」,可在小程序开发工具中点击工具栏里的「云开发」按钮进行开通,并创建环境(PS:对于首次使用云开发的用户,第一个月套餐免费)
开发,调用大模型
以上工作完成后,我们会得到一个云开发环境ID,接下来我们可以正式接入 DeepSeek API。这里我使用的是Taro
框架,开发过程中会遇到一些坑点,一起往下看看都是如何解决的。
初始化云开发环境
if(process.env.TARO_ENV === 'weapp') {
Taro.cloud.init({
env: 'cloud1-6gxxxxxxxxxxxx'
})
}
创建AI模型
const init = async () => {
model = Taro.cloud.extend.AI.createModel("deepseek");
// 创建模型实例,这里使用 DeepSeek 大模型
}
调用生成文本
const userInput = ref('') // 用户输入内容
const messageList = ref<ChatMessage[]>([]) // 对话列表
const send = async () => {
const res = await model.streamText({
data: {
model: "deepseek-r1", // 指定具体的模型
messages: [
{ role: "user", content: userInput.value },
],
},
})
// push 用户输入的消息到消息列表
messageList.value.push({
role: 'user',
content: userInput.value,
})
userInput.value = '' // 清空输入框
if(res.textStream) {
// 先push一条空内容,表示ai返回内容
messageList.value.push({
role: 'ai',
content: '',
})
// 接收大模型的响应
// 由于大模型的返回结果是流式的,所以我们这里需要循环接收完整的响应文本。
for await (let str of res.textStream) {
messageList.value[messageList.value.length - 1].content += str;
}
}
}
整个基本对话流程就好了,我们来看看效果,UI部分代码就不贴了,比较简单(一个输入框一个列表)
可以看到,这样我们就完成了AI对话的基本交互,但是有一个问题,AI思考过程时间比较长,用户对这个过程无感知,容易产生无响应的错觉,所以我们需要优化一下大模型思考等待过程的提示交互。
model.streamText
除了可以传入data数据,也可以传入一些事件监听,需要吐槽一下微信开发文档,写的太粗糙了,事件里面的参数及数据一个也没介绍,完全需要自己调试摸索...
const isGenerating = ref(false)
const send = async () => {
console.log('发送消息', userInput.value)
if(isGenerating.value) {
Taro.showToast({
title: '正在生成中,请稍后再试',
icon: 'none',
})
return
}
isGenerating.value = true
// 将系统提示词和用户输入,传入大模型
const res = await model.streamText({
data: {
model: "deepseek-r1", // 指定具体的模型
messages: [
{ role: "user", content: userInput.value },
],
},
onEvent: (event: any) => {
console.log('event', event);
// 处理事件流
if(event.delta) {
// 开始返回内容
console.log('开始返回内容', event.delta);
messageList.value[messageList.value.length - 1].status = 2;
}else if(event.data === '[DONE]') {
// 结束返回内容
console.log('结束返回内容');
messageList.value[messageList.value.length - 1].status = 3;
}
},
onFinish: (event: any) => {
console.log('finish', event);
// 处理完成事件
messageList.value[messageList.value.length - 1].status = 3;
},
});
// push 用户输入的消息到消息列表
messageList.value.push({
role: 'user',
content: userInput.value,
status: 3
})
userInput.value = ''
if(res.textStream) {
messageList.value.push({
role: 'ai',
content: '',
status: 0,
})
// 由于大模型的返回结果是流式的,所以我们这里需要循环接收完整的响应文本。
for await (let str of res.textStream) {
messageList.value[messageList.value.length - 1].content += str;
}
}
isGenerating.value = false
}
通过事件监听为每条消息加上了一个status
状态
status: number // 0: 发送中 1: 思考中 2: 回答中 3: 回答完成
<view v-else>
<view v-if="item.status < 2">思考中💭...</view>
<view class="ai_message" v-else v-html="item.content"></view>
</view>
再来看看此时的效果:
处理markdown
由于大模型返回的内容可能会含有markdown语法,所以我们不值简单的直接将大模型返回的内容直接进行渲染,这样就无法还原大模型吐出的排版
比如:
这些markdown语法都没有按预期排版进行渲染,为了排版更加好看,我们还需要处理markdown语法。
小程序虽然支持渲染富文本,但是如何渲染 Markdown 是一个问题。经过调研,我找到了 towxml第三方组件,它除了支持基本的 Markdown 语法,还支持下面三种格式的渲染:
- 支持 echarts 图表(3.0+)
- 支持 LaTex 数学公式(3.0+)
- 支持 yuml 流程图(3.0+)
⚠️需要注意的是:Towxml 是纯微信小程序组件,所以想要在taro项目中使用,还是有点麻烦的。
构建 Towxml
- 下载Towxml源码
git clone https://github.com/sbfkcel/towxml.git
- 安装依赖,进入项目根目录找到
config.js
,根据配置文件构建自己需要的功能
npm install
由于我只需要markdown部分的处理,所以对于echarts、laTex、yuml我都注释掉了,可以减小产物体积
- 打包,并且将产物放入taro项目中,修改
decode.json
组件引入路径
npm run build
使用Towxml组件
产物挪到项目后,就可以使用了,由于是小程序原生组件,所以需要在配置文件中进行引入
export default definePageConfig({
usingComponents: {
towxml: "./components/towxml/towxml"
}
})
调用towxmlParse方法处理markdown
import towxmlParse from './components/towxml/index'
const send = async () => {
// ...
let content = ''
for await (let str of res.textStream) {
// messageList.value[messageList.value.length - 1].content += str;
content += str;
messageList.value[messageList.value.length - 1].content = towxmlParse(content, 'markdown');
}
// ...
}
打开微信开发者工具,你会发现控制台有警告,组件也不能正常渲染
原因是 Vue 把它当做 Vue 组件来解析,我们可以修改 VueLoader 的编译配置 compilerOptions.isCustomElement
,把此组件声明为原生组件。
plugins: [
[
'@tarojs/plugin-framework-vue3',
{
vueLoaderOption: {
compilerOptions: {
isCustomElement: (tag) => tag.includes('towxml'),
whitespace: 'preserve',
// ...
},
reactivityTransform: true, // 开启vue3响应性语法糖
},
},
],
],
再重启项目来看看效果:
可以看到此时的markdown渲染就正常了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。