用vue3写一个AI聊天室
效果图如下:

1、页面布局:
<template><div class="body" style="background-color: rgb(244, 245, 248); height: 730px"><div class="container"><div class="right"><div class="top">AI问答</div><div class="chat" ref="chatContainer"><divv-for="(item, i) in msgList":key="i":class="item.type == '1' ? 'rightMsg' : 'leftMsg'"><imgv-if="item.type == '0'"src="../assets/images/AI.png"alt=""/><div class="msg">{{ item.content }}</div><imgv-if="item.type == '1'"src="../assets/images/me.png"alt=""/></div><!-- <div v-if="msgList.length >= 10" class="separator">-------------- 本AI问答仅显示最近10条对话 --------------</div> --></div><div class="bottom"><input v-model="value" placeholder="请输入您想提问的内容" /><button @click="onSend"><img src="../assets/images/send.png" alt="发送" /></button></div></div></div></div>
</template>
2、封转函数(用户输入问题和AI回答问题):
const msgList = reactive([]);
//提问
const userQuestion = (question) => {var userMsg = {content: question,type: "1",id: Date.now(),};msgList.push(userMsg);
};
//回答
const AIReplay = (replay) => {var autoReplyMsg = {content: replay,type: "0",id: Date.now(),};msgList.push(autoReplyMsg);
};
3、从后端获取最近的10个对话:
const getMes = () => {getQandA({}).then((res) => {console.log(res);if (res.data.status == 200) {// 获取最近五条问答信息for (var i = 0; i < 5; i++) {userQuestion(res.data.data[i].inputMessage);AIReplay(res.data.data[i].aiResult);}scrollToNew();}});
};
4、为了使用户发送问题后内容滚动在最底处,写一个函数让其自动滚动,在发送信息和获取信息时调用该函数即可
// 等待DOM更新完成。自动滚动到最新发送的消息处
const scrollToNew = async () => {await nextTick();const chatContainer = document.querySelector(".chat");if (chatContainer) {chatContainer.scrollTop = chatContainer.scrollHeight;}
};
5、点击发送按钮,发送到后端进行处理:
const onSend = () => {// 发送用户输入的消息AIQandA({inputMessage: value.value,}).then((res) => {console.log(res);if (res.data.status == 200) {console.log(6666);AIReplay(res.data.data);scrollToNew();}});userQuestion(value.value);scrollToNew();value.value = "";
};
完整代码如下:
<template><Header></Header><div class="body" style="background-color: rgb(244, 245, 248); height: 730px"><header><div class="cover"><imgsrc="1.png"alt=""style="width: 100%; height: 100%"/></div></header><main><div class="container"><div class="right"><div class="top">AI问答</div><div class="chat" ref="chatContainer"><divv-for="(item, i) in msgList":key="i":class="item.type == '1' ? 'rightMsg' : 'leftMsg'"><imgv-if="item.type == '0'"src="../assets/images/AI.png"alt=""/><div class="msg">{{ item.content }}</div><imgv-if="item.type == '1'"src="../assets/images/me.png"alt=""/></div><!-- <div v-if="msgList.length >= 10" class="separator">-------------- 本AI问答仅显示最近10条对话 --------------</div> --></div><div class="bottom"><input v-model="value" placeholder="请输入您想提问的内容" /><button @click="onSend"><img src="../assets/images/send.png" alt="发送" /></button></div></div></div></main></div><foot></foot>
</template><script setup>
import { ref, reactive, nextTick, onMounted } from "vue";
import Header from "../components/header.vue";
import foot from "../components/foot.vue";
import { AIQandA, getQandA } from "../api/AIApi";
const value = ref("");
const msgList = reactive([]);
onMounted(() => {getMes();
});
// 等待DOM更新完成。自动滚动到最新发送的消息处
const scrollToNew = async () => {await nextTick();const chatContainer = document.querySelector(".chat");if (chatContainer) {chatContainer.scrollTop = chatContainer.scrollHeight;}
};
const userQuestion = (question) => {var userMsg = {content: question,type: "1",id: Date.now(),};msgList.push(userMsg);
};
const AIReplay = (replay) => {var autoReplyMsg = {content: replay,type: "0",id: Date.now(),};msgList.push(autoReplyMsg);
};
const getMes = () => {getQandA({}).then((res) => {console.log(res);if (res.data.status == 200) {// 获取最近五条问答信息for (var i = 0; i < 5; i++) {userQuestion(res.data.data[i].inputMessage);AIReplay(res.data.data[i].aiResult);}scrollToNew();}});
};const onSend = () => {// 发送用户输入的消息AIQandA({inputMessage: value.value,}).then((res) => {console.log(res);if (res.data.status == 200) {console.log(6666);AIReplay(res.data.data);scrollToNew();}});userQuestion(value.value);scrollToNew();value.value = "";
};
</script><style scoped lang="scss">
.body {color: #fff;font-weight: 900;letter-spacing: 2px;width: 100%;height: 100%;background-size: 50%;display: flex;align-items: center;position: relative;
}
main {/* border: 1px solid red; */width: 1400px;height: 600px;margin: 100px auto;display: flex;
}
.cover {position: absolute;top: 0px;z-index: 0;height: 180px;width: 1483px;left: 50%;margin-left: -754px;overflow: hidden;
}
.body {:deep(.slick-slide) {text-align: center;height: 100%;line-height: 100%;background: #364d79;overflow: hidden;}:deep(.slick-arrow.custom-slick-arrow) {width: 25px;height: 25px;font-size: 25px;color: #fff;background-color: rgba(31, 45, 61, 0.11);transition: ease all 0.3s;opacity: 0.3;z-index: 1;}:deep(.slick-arrow.custom-slick-arrow:before) {display: none;}:deep(.slick-arrow.custom-slick-arrow:hover) {color: #fff;opacity: 0.5;}:deep(.slick-slide h3) {color: #fff;}
}.container {z-index: 1;// border: solid 1px #bebebe;width: 85%;height: 100%;margin: -6px auto;display: flex;justify-content: center;.right {flex: 1;// border-radius: 10px;background-color: white;display: flex;flex-direction: column;height: 600px;.top {height: 70px;background-color: rgba(147, 213, 255, 0.764);width: 100%;font-size: 22px;text-align: center;line-height: 70px;}.chat {flex: 1;max-height: 580px;overflow-y: auto;padding: 10px;.leftMsg,.rightMsg {display: flex;flex-direction: row;justify-content: start;align-items: center;margin: 10px;img {width: 40px;height: 40px;border-radius: 20px;overflow: hidden;object-fit: cover;margin: 0 10px;}.msg {display: inline-block;padding: 10px;word-wrap: anywhere;max-width: 600px;background-color: #364d79;border-radius: 10px;}}.rightMsg {justify-content: end;.msg {color: black;background-color: #dfdfdf;}}}.bottom {height: 45px;display: flex;align-items: center;width: 80%;margin: 10px auto;input {width: 90%;border: 1px solid rgb(171, 171, 171);border-right: none;height: 40px;color: black;text-indent: 2px;line-height: 40px;border-radius: 10px 0 0 10px;}button {cursor: pointer;width: 10%;border: none;outline: none;height: 45px;border-radius: 0 10px 10px 0;background: linear-gradient(to right,rgb(146, 197, 255),rgb(200, 134, 200));}img {width: 20px;height: 20px;}}}
}
.separator {color: rgb(133, 132, 132);text-align: center;font-size: 15px;font-weight: normal;
}
</style>
相关文章:
用vue3写一个AI聊天室
效果图如下: 1、页面布局: <template><div class"body" style"background-color: rgb(244, 245, 248); height: 730px"><div class"container"><div class"right"><div class"…...
photomaker:customizing realistic human photos via stacked id embedding
PhotoMaker: 高效个性化定制人像照片文生图 - 知乎今天分享我们团队最新的工作PhotoMaker的技术细节。该工作开源5天Githubstar数已过6千次,已列入Github官方Trending榜第一位,PaperswithCode热度榜第一位,HuggingFace Spaces趋势榜第一位。项…...
FFmpeg - 如何在Linux上安装支持CUDA的FFmpeg
FFmpeg - 如何在Linux(Ubuntu)上安装支持CUDA的FFmpeg 笔者认为现在的很多“xx教程”只讲干什么不讲为什么,这样即使报错了看官也不知道如何解决。 在安装过程的探索部分会记录我的整个安装过程以及报错和报错的解决办法。 在省流之一步到位的方法部分会省去安装过…...
新火种AI|商汤发布下棋机器人元萝卜,率先深入家庭场景。
作者:小岩 编辑:彩云 如今提及生成式AI(AIGC),已经不算什么新鲜产物了。自2014年GAN神经网络出现,2017年Transformer架构演进,再加上2023年ChatGPT的大火,无不说明生成式AI正在有条…...
CSS实现三栏自适应布局(两边固定,中间自适应)
绝对定位的元素会脱离文档流,它们是相对于包含块(通常是最近的具有相对定位、绝对定位或固定定位属性的父元素)进行定位的。当你把一个绝对定位的元素的高度设置为100%时,它会相对于其包含块的高度来确定自己的高度。如果包含块是…...
MoCo 算法阅读记录
论文地址:🐰 何凯明大神之作,通过无监督对比学习预训练Image Encoder的表征能力。后也被许多VLP算法作为ITC的底层算法来使用。 一方面由于源代码本身并不复杂,但是要求多GPU分布式训练,以及需要下载ImageNet这个大规模…...
华为OD机试 - 数组连续和 - 滑动窗口(Java 2024 C卷 100分)
华为OD机试 2024C卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷C卷)》。 刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试…...
微店micro获得微店micro商品详情,API接口封装系列
微店商品详情API接口封装系列主要涉及注册账号、获取API密钥、选择API接口、发送请求以及处理响应等步骤。以下是详细的流程: 请求示例,API接口接入Anzexi58 一、注册账号并获取API密钥 首先,你需要在微店开放平台注册一个账号。注册成功后…...
C语言中的数据结构--链表的应用1(2)
前言 上一节我们学习了链表的概念以及链表的实现,那么本节我们就来了解一下链表具体有什么用,可以解决哪些实质性的问题,我们借用习题来加强对链表的理解,那么废话不多说,我们正式进入今天的学习 单链表相关经典算法O…...
.Net6 使用Autofac进行依赖注入
一、背景 刚接触.net 6,记录一下在.net6上是怎么使用Autofac进行动态的依赖注入的 二、注入方式 1、新建一个webapi项目,框架选择net 6 2、引用Nuget包---Autofac.Extensions.Dependency 3、在Program.cs上添加如下代码 //依赖注入 builder.Host.Us…...
第十二届蓝桥杯省赛真题(C/C++大学B组)
目录 #A 空间 #B 卡片 #C 直线 #D 货物摆放 #E 路径 #F 时间显示 #G 砝码称重 #H 杨辉三角形 #I 双向排序 #J 括号序列 #A 空间 #include <bits/stdc.h> using namespace std;int main() {cout<<256 * 1024 * 1024 / 4<<endl;return 0; } #B 卡片…...
DC40V降压恒压芯片H4120 40V转5V 3A 40V降压12V 车充降压恒压控制器
同步整流恒压芯片在现代电子设备中发挥着重要作用,为各种设备提供了稳定、高效的电源管理解决方案。 同步整流恒压芯片是一种电源管理芯片,它能够在不同电压输入条件下保持输出电压恒定。这种芯片广泛应用于各种电子设备中,如通讯设备、液晶…...
2、Qt UI控件 -- qucsdk项目使用
前言:上一篇文章讲了qucsdk的环境部署,可以在QDesigner和Qt Creator中看到qucsdk控件,这一篇来讲下在项目中使用qucsdk库中的控件。 一、准备材料 要想使用第三方库,需要三个先决条件, 1、控件的头文件 2、动/静态链…...
MATLAB算法实战应用案例精讲-【人工智能】AIGC概念三部曲(三)
目录 前言 算法原理 大模型 什么是AIGC? AIGC和Chat GPT的关系 常见的AIGC应用...
外汇110:外汇交易不同货币类别及交易注意事项!
外汇市场是一个庞大而复杂的市场,其中有各种各样的货币品种。对于外汇投资者来说,了解外汇品种的特性和走势是比较重要的。1. 货币种类 外汇市场中的货币品种可以分为主要货币、次要货币和外围货币。 主要货币:主要指美元、欧元、英镑、日元、…...
gerrit 拉取失败
在浏览器gerrit的设置界面设置的邮箱地址和在命令行使用git config --gloable user.email设置的邮箱地址必须保持一致吗 在浏览器gerrit的设置界面设置的邮箱地址和在命令行使用git config --global user.email设置的邮箱地址并不一定需要保持一致。这两个邮箱地址是独立的&am…...
大数据行业英语单词巩固20240410
20240410 Communication - 沟通 Example: Effective communication is essential for project success. 有效的沟通对于项目的成功至关重要。 Collaboration - 协作 Example: Team collaboration is crucial in achieving our goals. 团队协作对于实现我们的目标至关重要。 …...
天软特色因子看板 (2024.4 第3期)
该因子看板跟踪天软特色因子A05005(近一月单笔流出金额占比(%),该因子为近一月单笔流出金额占比(% 均值因子,用以刻画下跌时的 单成交中可能存在的抄底现象 今日为该因子跟踪第3期,跟踪其在SH000852 (中证1000) 中的表现,要点如下…...
使用QT 开发不规则窗体
使用QT 开发不规则窗体 不规则窗体贴图法的不规则窗体创建UI模板创建一个父类创建业务窗体main函数直接调用user_dialog创建QSS文件 完整的QT工程 不规则窗体 QT中开发不规则窗体有两种方法:(1)第一种方法,使用QWidget::setMask函…...
如何构建企业经营所需的商业智能(BI)能力
构建企业经营所需的商业智能(BI)能力是一项涉及诸多关键环节与细致考量的系统工程,通过科学的数据处理、分析与应用,赋能企业实现精准决策,提升运营效率,优化业务流程,并在竞争激烈的市场环境中…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
