基于vue3+pinia2仿ChatGPT聊天实例|vite4.x仿chatgpt界面
使用vue3+pinia2开发仿制chatgpt界面聊天实例Vue3-Chatgpt
基于Vue3.x+Pinia2+VueRouter+Vue3-Markdown等技术构建仿ChatGPT网页端聊天程序。支持经典+分栏界面布局、light/dark模式、全屏+半屏显示、Markdown语法解析、侧边栏隐藏等功能。


技术框架
- 编辑工具:Cursor
- 框架技术:Vue3+Vite4.x+Pinia2
- 组件库:VEPlus (基于vue3桌面端组件库)
- 国际化多语言:vue-i18n^9.2.2
- 代码高亮:highlight.js^11.7.0
- 本地存储:pinia-plugin-persistedstate^3.1.0
- markdown解析:vue3-markdown-it


项目目录结构














vite.config.js配置
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import { parseEnv } from './src/utils/env'// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {const viteEnv = loadEnv(mode, process.cwd())const env = parseEnv(viteEnv)return {plugins: [vue()],// base: '/',// mode: 'development', // development|production/*构建选项*/build: {// minify: 'esbuild', // 打包方式 esbuild(打包快)|terser// chunkSizeWarningLimit: 2000, // 打包大小警告// rollupOptions: {// output: {// chunkFileNames: 'assets/js/[name]-[hash].js',// entryFileNames: 'assets/js/[name]-[hash].js',// assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',// }// }},esbuild: {// 打包去除 console.log 和 debuggerdrop: env.VITE_DROP_CONSOLE ? ['console', 'debugger'] : []},/*开发服务器选项*/server: {// 端口port: env.VITE_PORT,// 是否浏览器自动打开open: env.VITE_OPEN,// 开启httpshttps: env.VITE_HTTPS,// 代理配置proxy: {// ...}},resolve: {// 设置别名alias: {'@': resolve(__dirname, 'src'),'@assets': resolve(__dirname, 'src/assets'),'@components': resolve(__dirname, 'src/components'),'@views': resolve(__dirname, 'src/views'),// 解决vue-i18n警告提示:You are running the esm-bundler build of vue-i18n.'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js'}}}
})
main.js主入口
import { createApp } from 'vue'
import App from './App.vue'// 引入Router和Store
import Router from './router'
import Store from './store'// 引入插件配置
import Plugins from './plugins'const app = createApp(App)app
.use(Router)
.use(Store)
.use(Plugins)
.mount('#app')
vue3.x组件库
项目中使用的组件库是基于vue3自定义UI组件库Ve-plus。一个支持40+组件的轻量级组件库。


安装组件
yarn add ve-plus
npm i ve-plus --save
https://blog.csdn.net/yanxinyun1990/article/details/129312570
整体布局
项目支持2种布局模式,整体分为顶栏+侧边栏+主体内容三大模块构成。


<div class="ve__layout-body flex1 flexbox"><!-- //中间栏 --><div class="ve__layout-menus flexbox" :class="{'hidden': store.config.collapse}"><aside class="ve__layout-aside flexbox flex-col"><ChatNew /><Scrollbar class="flex1" autohide size="4" gap="1"><ChatList /></Scrollbar><ExtraLink /><Collapse /></aside></div><!-- //右边栏 --><div class="ve__layout-main flex1 flexbox flex-col"><!-- 主内容区 --><Main /></div>
</div>
<template><div class="vegpt__editor"><div class="vegpt__editor-inner"><Flex :gap="0"><Popover placement="top" trigger="click" width="150"><Button class="btn" type="link" icon="ve-icon-yuyin1" v-tooltip="{content: '发送语音', theme: 'light', arrow: false}"></Button><template #content><div class="flexbox flex-alignc flex-col" style="padding: 15px 0;"><Icon name="ve-icon-yuyin" size="40" color="#0fa27e" /><p class="fs-12 mb-15 c-999">网络不给力</p><Button size="small"><i style="background:#f00;border-radius:50%;box-shadow:0 1px 2px #999;margin-right:5px;height:8px;width:8px;"></i>开始讲话</Button></div></template></Popover><Button class="btn" type="link" v-tooltip="{content: '发送图片', theme: 'light', arrow: false}"><Icon name="ve-icon-photo" size="16" cursor /><input ref="uploadImgRef" type="file" title="" accept="image/*" @change="handleUploadImage" /></Button><Inputclass="flex1"ref="editorRef"v-model="editorText"type="textarea":autosize="{maxRows: 4}"clearableplaceholder="Prompt..."@keydown="handleKeydown"@clear="handleClear"style="margin: 0 5px;"/><Button class="btn" type="link" icon="ve-icon-submit" @click="handleSubmit"></Button></Flex></div></div>
</template>
import { ref, watch } from 'vue'
import { guid } from '@/utils'
import { chatStore } from '@/store/modules/chat'const props = defineProps({value: { type: [String, Number] }
})
const emit = defineEmits(['clear'])const chatState = chatStore()const uploadImgRef = ref()
const editorRef = ref()
const editorText = ref(props.value)// ...// 发送会话
const handleSubmit = () => {editorRef.value.focus()if(!editorText.value) returnlet data = {type: 'text',role: 'User',key: guid(),content: editorText.value}chatState.addSession(data)// 清空editorText.value = ''
}
const handleKeydown = (e) => {// ctrl+enterif(e.ctrlKey && e.keyCode == 13) {handleSubmit()}
}
const handleClear = () => {emit('clear')
}
// 选择图片
const handleUploadImage = () => {let file = uploadImgRef.value.files[0]if(!file) returnlet size = Math.floor(file.size / 1024)console.log(size)if(size > 2*1024) {Message.danger('图片大小不能超过2M')uploadImgRef.value.value = ''return false}let reader = new FileReader()reader.readAsDataURL(file)reader.onload = function() {let img = this.resultlet data = {type: 'image',role: 'User',key: guid(),content: img}chatState.addSession(data)}
}

/*** 聊天状态管理* @author YXY Q:282310962*/import { defineStore } from 'pinia'
import { guid, isEmpty } from '@/utils'export const chatStore = defineStore('chat', {state: () => ({// 聊天会话记录sessionId: '',session: []}),getters: {},actions: {// 创建新会话createSession(ssid) {this.sessionId = ssidthis.session.push({sessionId: ssid,title: '',data: []})},// 新增会话addSession(message) {// 判断当前会话uuid是否存在,不存在创建新会话if(!this.sessionId) {const ssid = guid()this.createSession(ssid)}this.session.map(item => {if(item.sessionId == this.sessionId) {if(!item.title) {item.title = message.content}item.data.push(message)}})// ...},// 获取会话getSession() {return this.session.find(item => item.sessionId == this.sessionId)},// 移除会话removeSession(ssid) {const index = this.session.findIndex(item => item?.sessionId === ssid)if(index > -1) {this.session.splice(index, 1)}this.sessionId = ''},// 删除某一条会话deleteSession(ssid) {// ...},// 清空会话clearSession() {this.session = []this.sessionId = ''}},// 本地持久化存储(默认存储localStorage)persist: true/* persist: {// key: 'chatStore', // 不设置则是默认appstorage: localStorage,paths: ['aa', 'bb'] // 设置缓存键} */
})
好了,基于vue3+vite4+pinia2开发模仿chatgpt聊天就分享到这里。
Tauri-Vue3聊天实例|Tauri跨端聊天
uniapp-ttlive短视频聊天|uniapp+uview仿抖音实例

相关文章:
基于vue3+pinia2仿ChatGPT聊天实例|vite4.x仿chatgpt界面
使用vue3pinia2开发仿制chatgpt界面聊天实例Vue3-Chatgpt 基于Vue3.xPinia2VueRouterVue3-Markdown等技术构建仿ChatGPT网页端聊天程序。支持经典分栏界面布局、light/dark模式、全屏半屏显示、Markdown语法解析、侧边栏隐藏等功能。 技术框架 编辑工具:Cursor框架…...
JDK动态代理和CGLIB动态代理
JDK动态代理和CGLIB动态代理 JDK动态代理和CGLIB动态代理 JDK动态代理和CGLIB动态代理 ① JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,在获取代理对象时&#x…...
Jetpack Hilt 框架的基本使用
什么是 Hilt? Hilt 是一个功能强大、用法简单的依赖注入框架,于 2020 年加入到 Jetpack 家族中。它是 Android 团队联系了 Dagger2 团队,一起开发出来的一个专门面向 Android 的依赖注入框架。相比于 Dagger2,Hilt 最明显的特征就…...
exec()在不同namespace执行结果的区别
记录一个很tricky的问题,下面这段code在执行func1时会出现NameError: name List is not defined,但执行func2时一切正常。 import typescontent """ from typing import Listclass GeneratedData:qna: List"""def func1…...
人工智能革命中的22个隐藏职业:推动科技行业的变革
作者 | Manas Sadangi 随着人工智能技术的不断发展,它正在创造一系列前所未有的就业机会。虽然数据科学家、机器学习工程师和人工智能研究人员等传统的人工智能角色得到了广泛认可,但在推动科技行业变革方面,还有一些鲜为人知的职业同样重要。…...
算法题3 — 求字符串中的最长子串
文章目录 题目示例示例1示例2示例3 解题解法1解法2 leetcode 题目 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 示例1 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例…...
【FreeRTOS】——中断优先级设置中断相关寄存器临界段代码保护调度器挂起与恢复
目录 前言: 一、中断优先级设置 二、中断相关寄存器(STM32-Cortex M3) 三、临界段代码保护 四、任务调度器的挂起和恢复 总结: 前言: 博客笔记根据正点原子视频教程编辑,仅供学习交流使用࿰…...
1.2 什么是eBPF?(下)
四,eBPF的优势 4.1 eBPF程序的动态加载 eBPF程序可以动态地加载到内核中,或从内核中删除。这个要与内核模块的加载与卸载区分开来。这里顺便讨论下eBPF程序与内核模块的区别,如下: 而Linux内核模块是面向内核API编程的,可以直接运行在内核当中。eBPF程序是面向BPF体系结构…...
掌握哪些测试技术才能说自己已经学成了?
一、过硬的基础能力 其实所有的测试大佬都是从底层基础开始的,随着时间,经验的积累慢慢变成大佬。要想稳扎稳打在测试行业深耕,成为测试大牛,首当其冲的肯定就是拥有过硬的基础,所有的基础都是根基,后期所…...
什么是C语言?
C语言是一种高级编程语言,于1972年由Dennis Ritchie在贝尔实验室开发出来。它是一种通用的、结构化的编程语言,被广泛用于系统软件、嵌入式系统、游戏开发以及科学计算等领域。 C语言的设计目标是提供一种简洁、高效、可移植的编程语言,以便…...
SAP-物料主数据-质量管理视图字段解析
过账到质检库存:要勾选,否则收货后库存不进入质检库存HU检验:收货到启用HU管理的库位时产生检验批,例如某个成品物料是收货到C002库位,该库位启用了HU管理,那么此处要勾选。但是如果勾选了,却收…...
TOP RPA·脱普×实在丨日用品企业脱普签约实在智能,构建全域数据智能运营系统
近日,实在智能与脱普日用化学品(中国)有限公司(简称“脱普企业”)在脱普企业上海总部举行“全域数据智能运营”项目启动会,双方领导及项目组关键成员共同参会,就项目目标、实施进程、沟通机制等…...
【Android】Handler(四)Looper的相关知识点
Handler 机制是 Android 多线程间通信的一种常见方式。每个 Handler 对象由一个 Looper 和一个 MessageQueue 组成,用于将 Message 对象处理到指定的线程中。通过创建 Handler 实例,在子线程中创建 Message 对象并通过sendMessage()方法发送给 Handler&a…...
Redis缓存雪崩及解决办法
缓存雪崩 1.缓存雪崩是指在同- -时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到 达数据库,带来巨大压力。 2.解决方案: ◆给不同的Key的TTL添加随机值 ◆利用Redis集群提高服务的可用性 ◆给缓存业务添加降级限流策略 降级可做为系统的保底…...
Maven私服仓库配置-Nexus详解
目录 一、什么是Maven私服?二、Maven 私服优势三、Maven 私服搭建四、Sonatype Nexus介绍五、Nexus仓库属性和分类六、Nexus仓库配置以及创建仓库七、Nexus配置用户角色八、Maven SNAPSHOT(快照)九、项目当中配置Nexus上传依赖十、项目当中配置Nexus下载依赖十一、测…...
Systrace系列10 —— Binder 和锁竞争解读
本文主要是对 Systrace 中的 Binder 和锁信息进行简单介绍,简单介绍了 Binder 的情况,介绍了 Systrace 中 Binder 通信的表现形式,以及 Binder 信息查看,SystemServer 锁竞争分析等。 Binder 概述 Android 的大部分进程间通信都使用 Binder,这里对 Binder 不做过多的解释…...
React Hooks中使用useState异步回调获取不到最新值的问题
ReactHook中useState异步回调获取不到最新值及解决⽅案 预先了解 setState 的两种传参⽅式 1、直接传⼊新值 setState(options); 列如: const [state, setState] useState(0); setState(state 1); 2、传⼊回调函数 setState(callBack); 例如: …...
JavaScript 高级 (完结)
目录 深浅拷贝 浅拷贝 深拷贝 递归实现深拷贝 js库lodash里面cloneDeep内部实现了深拷贝 JSON序列化 异常处理 throw 抛异常 try /catch 捕获异常 debugg 处理this this指向 普通函数 箭头函数 改变this call() apply() bind() call apply bind 总结 性能优化…...
【P30】JMeter 事务控制器(Transaction Controller)
文章目录 一、事务控制器(Transaction Controller)参数说明二、测试计划设计2.2.1、勾选 Generate parent sample2.2.1、勾选 Include duration of timer and pre-post processors in generated sample 一、事务控制器(Transaction Controlle…...
【MySQL】MySQL的事务原理和实现?
文章目录 MySQL事务的底层实现原理一、事务的目的可靠性和并发处理 二、实现事务功能的三个技术2.1 redo log 与 undo log介绍2.1.1 redo log2.1.2undo log 2.2 mysql锁技术2.2.1 mysql锁技术 2.3 MVCC基础 三、事务的实现3.1 原子性的实现3.1.1 undo log 的生成3.1.2 根据undo…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
