基于vue3+pinia2仿ChatGPT聊天实例|vite4.x仿chatgpt界面

news2024/11/16 3:51:29

使用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 和 debugger
			drop: env.VITE_DROP_CONSOLE ? ['console', 'debugger'] : []
		},

		/*开发服务器选项*/
		server: {
			// 端口
			port: env.VITE_PORT,
			// 是否浏览器自动打开
			open: env.VITE_OPEN,
			// 开启https
			https: 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>
				<Input
					class="flex1"
					ref="editorRef"
					v-model="editorText"
					type="textarea"
					:autosize="{maxRows: 4}"
					clearable
					placeholder="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) return

	let data = {
		type: 'text',
		role: 'User',
		key: guid(),
		content: editorText.value
	}
	chatState.addSession(data)
	// 清空
	editorText.value = ''
}
const handleKeydown = (e) => {
	// ctrl+enter
	if(e.ctrlKey && e.keyCode == 13) {
		handleSubmit()
	}
}
const handleClear = () => {
	emit('clear')
}
// 选择图片
const handleUploadImage = () => {
	let file = uploadImgRef.value.files[0]
	if(!file) return
	let 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.result

		let 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 = ssid
			this.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', // 不设置则是默认app
		storage: localStorage,
		paths: ['aa', 'bb'] // 设置缓存键
	} */
})

好了,基于vue3+vite4+pinia2开发模仿chatgpt聊天就分享到这里。

Tauri-Vue3聊天实例|Tauri跨端聊天
uniapp-ttlive短视频聊天|uniapp+uview仿抖音实例

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/498160.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

精炼计算机网络——物理层(二)

文章目录 前言2.4信道复用技术2.4.1 频分复用、时分复用和统计时分复用2.4.2 波分复用2.4.3 码分复用 2.5 数字传输系统2.6 带宽接入技术2.6.1 ADSL技术2.6.2 光纤同轴混合网&#xff08;HFC网&#xff09;2.6.3 FTTx技术 总结 前言 上篇文章&#xff0c;我们初步了解了物理层…

国考省考结构化面试:应急应变事件处理,宏观全面把控,措施有效具体,着眼当前放眼未来,标本兼治

国考省考结构化面试&#xff1a; 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能&#xff0c;附带行测和申论&#xff0c;而常规国考省考最重要的还是申论和行测&#xff0c;所以大家认真准备吧&#xff0c;我讲一起屡屡申论和行测的重要知识点 遇到寒…

idea 创建java项目,引入第三方jar,打包jar包

目录 一、新建并运行项目二、下载第三方Jar三、引入第三方Jar四、将项目打成Jar包 一、新建并运行项目 前提&#xff1a;已安装好JDK&#xff0c;并且配置好了JDK环境变量。 直接点击create创建即可 刚创建完的项目可能是没有out目录的&#xff0c;当我们执行一次main方法&…

Gradio的web界面演示与交互机器学习模型,安装和使用《1》

如何快速地将机器学习模型&#xff0c;给创建和分享出去&#xff0c;让更多的人来体验&#xff1f;Gradio就是一种快速搭建web界面来演示机器学习模型的方式&#xff0c;任何人都可以在任何地方使用它。 官网地址&#xff1a;https://gradio.app/ 1、安装Gradio 前提条件:Gra…

YOLOv5:图解common.py常用模块

YOLOv5&#xff1a;图解common.py常用模块 前言前提条件相关介绍common.py基本模块ConvBottleneckBottleneckCSPC3SPPSPPFFocus未完待续 参考 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩内容&#xff0c;可点击进入YOLO系列专栏或我的个…

jieba分词(1):入门案例

1 场景介绍 大数据量的查询问题 假设我们要从商品的表里面查询一个商品 我们的数据库里面肯定有个t_goods的表&#xff0c;我们现在利用商品的名称做模糊查询 1.1 对于数据库的查询的 select * from t_goods where goodsName like “%手机%” ; 问题&#xff1a; 这个查询…

CSDN | 好久不见,甚是想念

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后端的开发语言A…

JavaScript实现在键盘输入按键,浏览器进行显示的代码

以下为实现在键盘输入按键&#xff0c;浏览器进行显示的代码和运行截图 目录 前言 一、在键盘输入按键&#xff0c;浏览器进行显示 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以在目录里进行快速查找&#xf…

《灰盒模型在非侵入式体外估计糖化血红蛋白百分比和数字脉搏波形的推导和验证》阅读笔记

目录 一、论文摘要 二、论文十问 Q1&#xff1a;论文试图解决什么问题&#xff1f; Q2&#xff1a;这是否是一个新的问题&#xff1f; Q3&#xff1a;这篇文章要验证一个什么科学假设&#xff1f; Q4&#xff1a;有哪些相关研究&#xff1f;如何归类&#xff1f;谁是这一课…

84.python input输入函数知识拓展

文章目录 1. input函数知识回顾2. input常犯错误解析3. 用函数转换从终端输入的数据3.1 输入的数为整数&#xff0c;则用int转换为整数3.2 输入的数为浮点数&#xff0c;则用float转换为浮点数3.3 不考虑输入的数据类型&#xff0c;则用eval函数转换 4. 变量的多种赋值方式4.1 …

OpenCV教程——OpenCV环境配置及第一个测试代码

1.OpenCV简介 OpenCV是一个计算机视觉的开源库。英文全称是&#xff1a;Open Source Computer Vision Library。 常用的OpenCV的核心模块&#xff1a; Image ProcessCamera Calibration and 3D ReconstructionVideo AnalysisObject DetectionMachine LearningDeep LearningG…

【Linux】Linux安装Git(图文解说详细版)

文章目录 前言第一步&#xff0c;官网下载安装包第二步&#xff0c;解压安装包第三步&#xff0c;安装编译环境第四步&#xff0c;编译源码第五步&#xff0c;安装git第六步&#xff0c;配置环境变量 前言 服务器版本&#xff1a;CentOS7.8 git官网&#xff1a;https://git-sc…

汽车出租系统【纯控制台】(Java课设)

系统类型 纯控制台类型&#xff08;没有用到数据库&#xff09; 使用范围 适合作为Java课设&#xff01;&#xff01;&#xff01; 部署环境 jdk1.8Idea或eclipse 运行效果 本系统源码地址&#xff1a;https://download.csdn.net/download/qq_50954361/87753364 更多系统…

Qt5.14.2安装教程

之所以选择安装Qt5.14.2&#xff0c;是因为从5.15.0起&#xff0c;对于开源用户&#xff0c;Qt官方不再提供独立安装文件&#xff0c;源码安装听说很繁琐&#xff0c;并且还要激活码。 官网下载链接&#xff1a;https://download.qt.io/archive/qt/5.14/5.14.2/ 1、Windows用户…

智能优化算法:基于驾驶训练的优化算法-附代码

智能优化算法&#xff1a;基于驾驶训练的优化算法 文章目录 智能优化算法&#xff1a;基于驾驶训练的优化算法1. 基于驾驶训练优化算法1.1 初始化1.2 阶段一&#xff1a;驾驶教练培训&#xff08;探索阶段&#xff09;1.3 阶段二&#xff1a;学员学习&#xff08;探索阶段&…

Jupyter notebook 如何设定默认的保存目录?

前言&#xff1a; 做智能车的时候&#xff0c;Jupter Notebook的默认保存在可怜的C盘&#xff0c;本来就很紧张的C肯定受不了&#xff0c;要改到别的地方&#xff0c;网上找了一些参考&#xff0c;说变更一下配置地址就可以了&#xff0c;照着做&#xff0c;99%的博客说&#x…

Linux驱动开发笔记(一):helloworld驱动源码编写、makefile编写以及驱动编译基本流程

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/130534343 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

算法和算法竞赛的知识点

2023年5月7日&#xff0c;周日早上&#xff1a; 虽然今天早上我作出了改变学习算法方式的决定&#xff0c;但是知识点有哪些、具体该怎么做还没搞清楚&#xff0c;于是去刷题网站截图了它们的标签。 或许看相关书籍的知识点和题单也不错。 LeetCode的知识点 力扣 蓝桥杯的知识…

2023招商Fintech数据赛道rank33 赛后分享

赛题需求&#xff1a; 本次比赛为参赛选手提供了两个数据集&#xff0c;即训练数据集(train)和测试数据集(test_A榜/test_B榜)。参赛选手需要基于训练数据集&#xff0c;通过有效的特征提取&#xff0c;构建客户进取类产品配置发生时点预测模型,并将模型应用于测试数据集上,输出…

力扣sql中等篇练习(十六)

力扣sql中等篇练习(十六) 1 不同性别每日分数统计 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 a 示例输入 b 示例输出 1.2 示例sql语句 # 分数是往后累加的 SELECT s2.gender,s2.day,sum(s1.score_points) total FROM Scores s1 CROSS JOIN Scores s2 ON s2.gen…