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

用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聊天室

效果图如下&#xff1a; 1、页面布局&#xff1a; <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千次&#xff0c;已列入Github官方Trending榜第一位&#xff0c;PaperswithCode热度榜第一位&#xff0c;HuggingFace Spaces趋势榜第一位。项…...

FFmpeg - 如何在Linux上安装支持CUDA的FFmpeg

FFmpeg - 如何在Linux(Ubuntu)上安装支持CUDA的FFmpeg 笔者认为现在的很多“xx教程”只讲干什么不讲为什么&#xff0c;这样即使报错了看官也不知道如何解决。 在安装过程的探索部分会记录我的整个安装过程以及报错和报错的解决办法。 在省流之一步到位的方法部分会省去安装过…...

新火种AI|商汤发布下棋机器人元萝卜,率先深入家庭场景。

作者&#xff1a;小岩 编辑&#xff1a;彩云 如今提及生成式AI&#xff08;AIGC&#xff09;&#xff0c;已经不算什么新鲜产物了。自2014年GAN神经网络出现&#xff0c;2017年Transformer架构演进&#xff0c;再加上2023年ChatGPT的大火&#xff0c;无不说明生成式AI正在有条…...

CSS实现三栏自适应布局(两边固定,中间自适应)

绝对定位的元素会脱离文档流&#xff0c;它们是相对于包含块&#xff08;通常是最近的具有相对定位、绝对定位或固定定位属性的父元素&#xff09;进行定位的。当你把一个绝对定位的元素的高度设置为100%时&#xff0c;它会相对于其包含块的高度来确定自己的高度。如果包含块是…...

MoCo 算法阅读记录

论文地址&#xff1a;&#x1f430; 何凯明大神之作&#xff0c;通过无监督对比学习预训练Image Encoder的表征能力。后也被许多VLP算法作为ITC的底层算法来使用。 一方面由于源代码本身并不复杂&#xff0c;但是要求多GPU分布式训练&#xff0c;以及需要下载ImageNet这个大规模…...

华为OD机试 - 数组连续和 - 滑动窗口(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…...

微店micro获得微店micro商品详情,API接口封装系列

微店商品详情API接口封装系列主要涉及注册账号、获取API密钥、选择API接口、发送请求以及处理响应等步骤。以下是详细的流程&#xff1a; 请求示例&#xff0c;API接口接入Anzexi58 一、注册账号并获取API密钥 首先&#xff0c;你需要在微店开放平台注册一个账号。注册成功后…...

C语言中的数据结构--链表的应用1(2)

前言 上一节我们学习了链表的概念以及链表的实现&#xff0c;那么本节我们就来了解一下链表具体有什么用&#xff0c;可以解决哪些实质性的问题&#xff0c;我们借用习题来加强对链表的理解&#xff0c;那么废话不多说&#xff0c;我们正式进入今天的学习 单链表相关经典算法O…...

.Net6 使用Autofac进行依赖注入

一、背景 刚接触.net 6&#xff0c;记录一下在.net6上是怎么使用Autofac进行动态的依赖注入的 二、注入方式 1、新建一个webapi项目&#xff0c;框架选择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 车充降压恒压控制器

同步整流恒压芯片在现代电子设备中发挥着重要作用&#xff0c;为各种设备提供了稳定、高效的电源管理解决方案。 同步整流恒压芯片是一种电源管理芯片&#xff0c;它能够在不同电压输入条件下保持输出电压恒定。这种芯片广泛应用于各种电子设备中&#xff0c;如通讯设备、液晶…...

2、Qt UI控件 -- qucsdk项目使用

前言&#xff1a;上一篇文章讲了qucsdk的环境部署&#xff0c;可以在QDesigner和Qt Creator中看到qucsdk控件&#xff0c;这一篇来讲下在项目中使用qucsdk库中的控件。 一、准备材料 要想使用第三方库&#xff0c;需要三个先决条件&#xff0c; 1、控件的头文件 2、动/静态链…...

MATLAB算法实战应用案例精讲-【人工智能】AIGC概念三部曲(三)

目录 前言 算法原理 大模型 什么是AIGC? AIGC和Chat GPT的关系 常见的AIGC应用...

外汇110:外汇交易不同货币类别及交易注意事项!

外汇市场是一个庞大而复杂的市场&#xff0c;其中有各种各样的货币品种。对于外汇投资者来说&#xff0c;了解外汇品种的特性和走势是比较重要的。1. 货币种类 外汇市场中的货币品种可以分为主要货币、次要货币和外围货币。 主要货币&#xff1a;主要指美元、欧元、英镑、日元、…...

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(近一月单笔流出金额占比(%)&#xff0c;该因子为近一月单笔流出金额占比(% 均值因子&#xff0c;用以刻画下跌时的 单成交中可能存在的抄底现象 今日为该因子跟踪第3期&#xff0c;跟踪其在SH000852 (中证1000) 中的表现&#xff0c;要点如下…...

使用QT 开发不规则窗体

使用QT 开发不规则窗体 不规则窗体贴图法的不规则窗体创建UI模板创建一个父类创建业务窗体main函数直接调用user_dialog创建QSS文件 完整的QT工程 不规则窗体 QT中开发不规则窗体有两种方法&#xff1a;&#xff08;1&#xff09;第一种方法&#xff0c;使用QWidget::setMask函…...

如何构建企业经营所需的商业智能(BI)能力

构建企业经营所需的商业智能&#xff08;BI&#xff09;能力是一项涉及诸多关键环节与细致考量的系统工程&#xff0c;通过科学的数据处理、分析与应用&#xff0c;赋能企业实现精准决策&#xff0c;提升运营效率&#xff0c;优化业务流程&#xff0c;并在竞争激烈的市场环境中…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...