系列文章
- AI大语言模型LLM学习-入门篇
- AI大语言模型LLM学习-Token及流式响应
- AI大语言模型LLM学习-WebAPI搭建
前言
在上一篇博文中,我们使用Flask这一Web框架结合LLM模型实现了后端流式WebAPI接口,本篇将基于Vue3实现AI问答页面,本人习惯使用HBuilder进行前端页面的开发,当然各位网友可以选择自己喜欢的前端开发IDE,比如VS Code。
一、设计思路
打开一个主流的AI对话页面,比如我注册的是阿里的通义千问
可以看到页面的效果如图所示:
根据页面效果,可以大致把内容分为如下3部分:
- 标题
- 问答对话,右侧为用户输入的问题,左侧为AI的回答;此部分需要自定义组件,左右布局,可复用,采用循环实现
- 底部输入区域,包含输入框及发送按钮
二、编码实现
1.项目新建
2.项目结构
3.代码部分
3.1 安装并引入element-plus
npm install element-plus --save
关于element-plus相关组件的使用,参考element-plus官网
- mian.js配置
import{ createApp }from'vue'import App from'./App.vue'import ElementPlus from'element-plus'import'element-plus/dist/index.css'const app =createApp(App)//引入element-plus
app.use(ElementPlus)
app.mount('#app')
3.2 api接口进行代理
注意:api接口不能直接在html页面中进行调用,存在跨域访问的问题,需要在vite.config.js添加代理配置。
生产环境部署时可以采用nginx对api接口进行反向代理解决跨域问题。
import{ defineConfig }from'vite'import vue from'@vitejs/plugin-vue'// https://vitejs.dev/config/exportdefaultdefineConfig({plugins:[vue()],server:{proxy:{'/chat':{target:"http://127.0.0.1:2024/",changeOrigin:true,},}}})
3.3对话组件
chat.vue代码如下:
<scriptsetup>import{ ref }from'vue'defineProps({msg: Object
})const count =ref(0)</script><template><divclass="chat"><!--问题--><divstyle="text-align: right;"><divclass="el-card chat-right">
{{msg.question}}
</div></div><!--AI回答--><divstyle="text-align: left;"><divclass="el-card chat-left">
{{msg.answer}}
</div></div></div></template><stylescoped>.chat{max-width: 1000px;margin: 0 auto;padding-top: 10px;padding-bottom: 10px;}.ai-img{height: 36px;width: 36px;}.chat-left{background-color: #f5f6f7!important;display: inline-block;box-sizing: border-box;width: auto;text-align: left;border-radius: 12px;line-height: 24px;max-width: 100%;padding: 12px 16px;white-space: pre-wrap;}.chat-right{background-color: #e0dfff;display: inline-block;box-sizing: border-box;width: auto;color: #3f3f3f;border-radius: 12px;line-height: 24px;max-width: 100%;padding: 12px 16px;white-space: pre-wrap;}</style>
3.4主体页面
代码如下:
<template><divclass="common-layout"><el-containerstyle="height:100%;width:100%;margin: 0 auto;"><el-headerstyle="height: 50px;width: 100% ;backgroundColor:rgba(0,102,255,.06)"><pclass="centered-text">AI-历史人物</p></el-header><el-mainid="chat"><chatv-for="item in form.msgList":msg=item></chat></el-main><el-rowstyle="margin: 0 auto;padding-left: 20px;padding-right: 20px;"><divstyle="width: 100%;"><el-inputstyle="float: left;width: 90%;"@keyup.enter="sendMsg"v-model="form.input"></el-input><el-button@click="sendMsg"style="float: right;height: 42px;line-height: 42px;">发送</el-button></div><divstyle="margin: 0 auto;"><pstyle="color: red;font-size: 11px;">
服务生成的所有内容均由人工智能模型生成,其生成内容的准确性和完整性无法保证,不代表我们的态度或观点
</p></div></el-row></el-container></div></template><scriptsetup>import{ reactive,nextTick, ref }from'vue'import chat from'./components/chat.vue'const form =reactive({input:'',//输入msgList:[]//消息列表});asyncfunctionsendMsg(){var keyword=form.input;if(form.input.length>0){var msg={question:keyword,answer:"AI生成中..."};
form.msgList.push(msg);
form.input="";setScrollToBottom();const response=awaitfetch('/chat',{method:"post",headers:{'Content-Type':'application/json'},body:JSON.stringify({question:keyword
})});if(!response.ok){thrownewError(`HTTP error! status: ${response.status}`);}const reader = response.body.getReader();let decoder =newTextDecoder();let resultData ='';var str="";
msg={question:keyword,answer:str
};
form.msgList.pop();
form.msgList.push(msg);while(true){const{ done, value }=await reader.read();if(done)break;
resultData = decoder.decode(value);
console.log(resultData);
str+=resultData;
msg={question:keyword,answer:str
};
form.msgList.pop();
form.msgList.push(msg);setScrollToBottom();}}}/*内容显示过多时自动滑动*/asyncfunctionsetScrollToBottom(){awaitnextTick()let chat = document.querySelector("#chat")
chat.scrollTop = chat.scrollHeight
}</script><style>html,body{width: 100%;height: 100%;margin: 0;padding: 0;border: 0;}#app{font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;height:100%;min-width: 380px;}.common-layout{height: 100%;}#chat{height:calc(100vh - 150px);}.el-input{height: 45px;border-radius: 12px;box-sizing: border-box;}</style>
运行效果展示
版权归原作者 程序员老司机 所有, 如有侵权,请联系我们删除。