AI大语言模型LLM学习-基于Vue3的AI问答页面
程序员老司机 2024-09-15 13:01:01 阅读 78
系列文章
1. AI大语言模型LLM学习-入门篇
2. AI大语言模型LLM学习-Token及流式响应
3. AI大语言模型LLM学习-WebAPI搭建
前言
在上一篇博文中,我们使用Flask这一Web框架结合LLM模型实现了后端流式WebAPI接口,本篇将基于Vue3实现AI问答页面,本人习惯使用HBuilder进行前端页面的开发,当然各位网友可以选择自己喜欢的前端开发IDE,比如VS Code。
一、设计思路
打开一个主流的AI对话页面,比如我注册的是阿里的通义千问
可以看到页面的效果如图所示:
根据页面效果,可以大致把内容分为如下3部分:
标题问答对话,右侧为用户输入的问题,左侧为AI的回答;此部分需要自定义组件,左右布局,可复用,采用循环实现底部输入区域,包含输入框及发送按钮
二、编码实现
1.项目新建
2.项目结构
3.代码部分
3.1 安装并引入element-plus
<code>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/
export default defineConfig({
plugins: [vue()],
server:{
proxy:{
'/chat':{
target:"http://127.0.0.1:2024/",
changeOrigin: true,
},
}
}
})
3.3对话组件
chat.vue代码如下:
<script setup>
import { ref } from 'vue'
defineProps({
msg: Object
})
const count = ref(0)
</script>
<template>
<div class="chat">code>
<!--问题-->
<div style="text-align: right;">code>
<div class="el-card chat-right" >code>
{ -- -->{msg.question}}
</div>
</div>
<!--AI回答-->
<div style="text-align: left;">code>
<div class="el-card chat-left">code>
{ -- -->{msg.answer}}
</div>
</div>
</div>
</template>
<style scoped>
.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>
<div class="common-layout">code>
<el-container style="height:100%;width:100%;margin: 0 auto;">code>
<el-header style="height: 50px; width: 100% ;backgroundColor:rgba(0,102,255,.06)">code>
<p class="centered-text">AI-历史人物</p>code>
</el-header>
<el-main id="chat">code>
<chat v-for="item in form.msgList" :msg=item></chat>code>
</el-main>
<el-row style="margin: 0 auto;padding-left: 20px;padding-right: 20px;">code>
<div style="width: 100%;">code>
<el-input style="float: left;width: 90%;" @keyup.enter="sendMsg" v-model="form.input"></el-input>code>
<el-button @click="sendMsg" style="float: right; height: 42px;line-height: 42px;" >发送</el-button>code>
</div>
<div style="margin: 0 auto;">code>
<p style="color: red;font-size: 11px;">code>
服务生成的所有内容均由人工智能模型生成,其生成内容的准确性和完整性无法保证,不代表我们的态度或观点
</p>
</div>
</el-row>
</el-container>
</div>
</template>
<script setup>
import { -- --> reactive,nextTick, ref } from 'vue'
import chat from './components/chat.vue'
const form = reactive({
input: '',//输入
msgList:[] //消息列表
});
async function sendMsg()
{
var keyword=form.input;
if(form.input.length>0)
{
var msg={
question:keyword,
answer:"AI生成中..."
};
form.msgList.push(msg);
form.input="";code>
setScrollToBottom();
const response=await fetch('/chat',{ -- -->
method:"post",
headers:{ 'Content-Type':'application/json'},
body:JSON.stringify({
question:keyword
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${ response.status}`);
}
const reader = response.body.getReader();
let decoder = new TextDecoder();
let resultData = '';
var str="";code>
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();
}
}
}
/*内容显示过多时自动滑动*/
async function setScrollToBottom() {
await nextTick()
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>
运行效果展示
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。