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

给web增加简单的ai对话功能

自从 ChatGPT 火了之后,越来越多人开始对 AI 感兴趣,AI 的使用也越来越普遍了。现在你随便点开个知名网站或者 APP,基本都能看到 AI 的影子,而且这些 AI 大多都是用 “问答” 的形式跟人互动,说白了就是 “聊天”。

当然啦,现在的 AI 也不是完美的,比如有时候会瞎编东西(就是大家说的 “AI 幻觉”),但给 APP 加个 AI 功能,确实能让它变好玩、互动感更强。那咱们自己的 APP,怎么快速加上 AI 功能呢?其实不用自己从头搞,直接用现成平台提供的模型和 API 就行,今天就来聊聊怎么用阿里云百炼。

它是阿里云出的大模型服务平台,把复杂的技术都打包好了,就算你没什么 AI 基础,也能很快把 AI 功能集成到自己的 APP 里。

以下内容可配合视频一起食用

前端基础项目搭建

首先我们先搭建一个基础的前端项目,我这里用的是vue框架,UI组件使用了ant-design-vue和ant-design-x-vue,其中ant-design-x-vue增加了对ai交互的支持,可以让开发效率更高。

接下来我们就来尝试「直接」使用通义千问API来实现ai对话功能。

前置准备

在编写代码之前,我们先完成一些准备工作,注册登录,以及获取API key。

构造请求并显示返回结果

然后我们就可以开始构造请求进行API的调用了。

// ...
const handleSubmit = message => {const newMessage: chatItem = {key: chatList.value.length,role: 'user',content: message,};chatList.value.push(newMessage);fetchReply();
}const fetchReply = async () => {return fetch( // +'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions', // +{ // +method: 'POST', // +headers: { // +Authorization: `Bearer ${import.meta.env.VITE_ALIYUN_API_APPKEY}`, // +'Content-Type': 'application/json', // +}, // +body: JSON.stringify({ // +model: 'qwen-plus', // +messages: chatList.value // +}) // +} // +) // +
};
// ...

参数model是指定了我们使用的模型,我们还给接口传递了一个messages的消息数组,这是因为通义千问API是无状态的,它不会自动记录历史对话,所以要实现多轮对话,就需要在每次请求中显式地传递完整的上下文信息,很显然这样随着聊天记录增加,请求体会变得越来越大,文档后面呢也提供了一些优化策略,不过这不是我们今天的重点。

现在我们刷新页面试着发送消息去请求一下API,就可以看到接口返回的ai消息了,消息的内容就在choices数组里message的content属性里。

ai_api2

我们把它显示到页面上就可以了。

const handleSubmit = message => {const newMessage: chatItem = {key: chatList.value.length,role: 'user',content: message,};chatList.value.push(newMessage);fetchReply() // M.then (response => response.json()) // +.then(result => { // +const newReply: chatItem = { // +key: chatList.value.length, // +role: 'assistant', // +content: result.choices[0].message.content, // +}; // +chatList.value.push(newReply); // +}); // +
}

ai_chat1

问题1:长时间等待

这时我们再发送消息,让ai输出更详细的自我介绍,可以注意到明显地有一段比较长的等待时间,这是因为这次返回的内容比较多。

ai_chat2

解决:改为流式输出

为了能有更好的用户体验,我们可以将返回的形式改为流式输出,在请求参数里增加stream参数的设置,将它设置为true。

const fetchReply = async () => {return fetch('https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',{method: 'POST',headers: {Authorization: `Bearer ${import.meta.env.VITE_ALIYUN_API_KEY}`,'Content-Type': 'application/json',},body: JSON.stringify({model: 'qwen-plus',messages: chatList.value,stream: true // +})})
};

当我们再次请求时,会发现这个请求返回的内容和普通的请求不一样,network显示的请求里多了一个tab,标题是EventStream。

ai_api

这是因为我们设置了流式输出。流式输出通过持续返回模型生成的文本片段,可以提供给用户更好的应用体验,避免长时间的等待,那我们要怎么处理这类请求返回的流式内容呢?

这一类请求我以前也没有处理过,所以我找了MDN的文档来参考,MDN上有一个关于fetch API response的文档:ReadableStream,对返回的流式内容进行处理,我们把它复制过来。

const handleSubmit = message => {const newMessage: chatItem = {key: chatList.value.length,role: 'user',content: message,};chatList.value.push(newMessage);const index = chatList.value.length; // +let reply = ''; // +fetchReply()// .then (response => response.json())// .then(result => {//   const newReply: chatItem = {//     key: chatList.value.length,//     role: 'assistant',//     content: result.choices[0].message.content,//   };//   chatList.value.push(newReply);// });.then(response => response.body).then(rb => {const reader = rb.getReader();return new ReadableStream({start(controller) {// The following function handles each data chunkfunction push() {// "done" is a Boolean and value a "Uint8Array"reader.read().then(({ done, value }) => {// If there is no more data to readif (done) {console.log("done", done);controller.close();return;}// Get the data and send it to the browser via the controllercontroller.enqueue(value);// Check chunks by logging to the console// console.log(done, value); // Mconst decoder = new TextDecoder(); // +const decodedString = decoder.decode(value); // +console.log(decodedString); // +push();});}push();},});});
}

我们看到这里的注释里写着,value是Uint8Array,也就是无符号整型数组,所以我们需要对他进行解析,这里我用了TextDecoder来解析,最后打印的decodedString就是解析出来的文本内容,我们先去请求一下,看一下这个内容是什么样子的。

ai_chat4

可以看到decodedString打印出来的是一个多行的内容,每一行内容都是以data:开头,消息的最后一行是一个[done]的标识。

那么我们接下来就对decodedString进行处理,将它返回的多行的内容取出来,再进行拼接。

我们刚才看到,消息的最后会返回一个data: [DONE]表示回答结束,这条内容是我们需要过滤掉的。

// ...
// console.log(decodedString);
const lines = decodedString.split('\n').filter(line => line.trim() !== ''); // +
for (const line of lines) { // +const message = line.replace(/^data: /, ''); // +if (message === '[DONE]') { // +console.log("Stream finished"); // +return; // +} else { // +const parsed = JSON.parse(message); // +const content = parsed.choices[0].delta.content; // +if (content) { // +reply += content; // +if (chatList.value.length < index + 1) { // +const newReply: chatItem = { // +key: index, // +role: 'assistant', // +content: reply, // +}; // +chatList.value.push(newReply); // +} else { // +chatList.value[index].content = reply; // +} // +} // +} // +
} // +
push();
// ...

这个时候我们再去重新开启对话,可以看到请求很快就得到了响应,并把内容一点点的显示到对话框里,这时候的用户体验就比一次性获得消息好很多。

问题2:markdown内容的显示

到这里呢,基本功能就完成了,但是页面上还存在一个很明显的问题,我们可以看到,ai返回的消息它其实是一段markdown格式的内容,如果就这样直接显示出来、显然并不太好,那么我们可以加入一个markdown-it的包,增加对markdown内容的显示处理。

解决:使用markdown-it处理

ant-design-x-vue这个UI库这里也提供了支持,可以直接按照文档来进行配置

// ...
import type { BubbleListProps, BubbleProps } from "ant-design-x-vue"; // M
// ...
import { Typography } from 'ant-design-vue'; // +
import markdownit from 'markdown-it'; // +const md = markdownit({ html: true, breaks: true }); // +
const renderMarkdown: BubbleProps['messageRender'] = (content) => // +h(Typography, null, { // +default: () => h('div', { innerHTML: md.render(content) }), // +}); // +const rolesAsObject: BubbleListProps['roles'] = {'assistant': {placement: 'start',avatar: { icon: h(UserOutlined), style: { background: '#fde3cf'} },typing: { step: 5, interval: 20 },styles: {maxWidth: '600px',},messageRender: renderMarkdown, // +},'user': {placement: 'end',avatar: { icon: h(UserOutlined), style: { background: '#87d068' } },},
};

这时我们再去发起一次对话看一下效果。

可以看到返回的markdown格式的内容在页面上的显示已经是经过转换后的了。到这里呢我们就实现了简单的ai对话功能,这也是我第一次接触,所以还没有更深入的研究,感兴趣的同学也可以动手尝试一下呀。

ai_chat

http://www.gsyq.cn/news/30374.html

相关文章:

  • 2025年10月离心干燥机厂家全景解析报告,基于专业测评的技术、性能及市场优势深度分析
  • Jetbrains IDEA or Webstorm新版本回退到之前的UI风格
  • 解码Linux文件IO之开机动画原理与实现
  • 2025 年异构烷供应厂家推荐:异构十二烷、异构十四烷、异构十六烷、异构二十烷最新推荐榜,聚焦企业技术实力与市场口碑深度解析
  • 2025 年镀锌方管制造厂家最新推荐排行榜:聚焦广东佛山优质品牌,助力工程采购精准选型异形/Q235/冷轧带钢/热浸/热/冷/热镀锌方管立柱厂家推荐
  • AppSec与事件响应的融合实践
  • PlantAssistant-免费查看RVM/VUE
  • 2025 年对焊机源头厂家最新推荐排行榜权威发布,含闪光 / 成型 / 打圈 / T 型 / 双头 T 型对焊机行业口碑榜单
  • 2025市面上双曲铝单板品牌、行业内双曲铝单板厂家、市场双曲铝单板产品、口碑好的双曲铝单板厂家、2025年双曲铝单板供应商权威排名
  • 2025市面上双曲铝单板品牌、行业内双曲铝单板生产厂家、市场双曲铝单板供应厂家、目前双曲铝单板实力厂家、口碑好的双曲铝单板公司排行榜
  • 2025 年调直机厂家最新推荐排行榜权威发布:聚焦伺服 / 高速 / 铁线 / 扁铁机型,揭秘行业优质企业
  • 2025年市面上中压电缆品牌、行业内中压电缆公司、口碑好的中压电缆品牌、有实力的中压电缆产品、中压电缆公司推荐榜单深度解析
  • 高等数学 —— 微分的具体形式
  • docker 端口映射
  • 251025
  • 关于我:新的开始,新的记录
  • 2025 年知识库应用平台最新推荐排行榜!企业 / 个人 / 协同 / 智能等多场景适配,附权威测评与选择指南
  • 深入解析:深度学习调参指南:Batch Size的选择策略与实践
  • 2025 厨房排烟安装公司最新推荐榜:实力品牌服务与工艺解析及选择指南饭店/商用/罩/系统/厨房排烟管道专业服务公司推荐
  • 【Linux网络】Socket编程:UDP网络编程达成ChatServer
  • 2025年工业木托盘批发厂家权威推荐榜单:实木叉车托盘/物流木托盘/免熏蒸木托源头厂家精选
  • 2025年托辊输送带直销厂家权威推荐榜单:输送机托辊/托辊设备/托辊配件源头厂家精选
  • 2025 年最新冲压油供应厂家权威榜单:聚焦空调加工适配性与免清洗技术,助力企业精准选品免清洗/铝翅片/定子转子/高速冲压油厂家推荐
  • 实用指南:Nginx 访问控制、用户认证、HTTPS配置实操手册
  • 蓝队中的SOC角色解析:从初级分析师到职业发展路径
  • 2025 年载冷剂厂家最新推荐排行榜:权威协会测评 + 京津冀区位优势,严检达标优选指南超低温/乙二醇/冷库专用/食品级载冷剂公司推荐
  • 10.25日模考总结
  • Unreal:如何设置监听服务器
  • 2025年西安楼盘品牌排行推荐榜及开发商推荐权威指南
  • docker 命令补充