Vite-WeGPT聊天AI实例|vue3+pinia仿ChatGPT聊天界面

2023-06-25,,

基于vue3.x+vite4+pinia2仿chatgpt聊天模拟实例Vue3-WeGPT

基于Vite4.x+Vue3+Pinia2+VEPlus+Vue3-Markdown等技术实现仿ChatGPT聊天AI界面实例。整体界面简洁清新、支持2种界面布局、暗黑+亮色模式、全屏+半屏展示、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
样式处理:sass^1.62.0

特征

最新前端技术栈 vite4、vue3、pinia2、vue-router、vue-i18n
支持中文/英文/繁体多语言
支持dark/light两种模式
提供2种模板布局
支持半屏/全屏展示
支持更换背景皮肤
搭配轻量级vue3组件库ve-plus

项目结构

整个项目采用vite4.x搭建项目,vue3 setup语法编码,运行编译速度极快。

Vue3组件库

项目依然采用自己开发的vue3自定义UI组件库VE-Plus。提供40+常用组件,运行轻巧、风格清新。

安装使用

yarn add ve-plus
npm install ve-plus -S
cnpm install ve-plus -S

https://www.cnblogs.com/xiaoyan2017/p/17170454.html

布局模板

提供了经典+分栏两种布局展示模板。

<script setup>
import { computed } from 'vue'
import { appStore } from '@/store/modules/app' // 引入布局模板
import Classic from './layout/classic/index.vue'
import Columns from './layout/columns/index.vue' const store = appStore()
const config = computed(() => store.config) const LayoutConfig = {
classic: Classic,
columns: Columns
}
</script> <template>
<div class="vegpt__container" :class="{'is-half': store.config.halfScreen}" :style="{'--themeSkin': store.config.skin}">
<component :is="LayoutConfig[config.layout]" />
</div>
</template> <style lang="scss" scoped></style>
<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>

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'
}
}
}
})

Vue3主入口文件

在main.js引入路由、Pinia状态管理及注册一些公共组件。

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')

chatgpt聊天框

聊天框使用Input组件实现,设置type=textarea,支持多行自适应高度。

<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 class="dot"></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>
<script setup>
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 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)
}
} // ...
</script>

vue3项目现在比较推荐pinia替代vuex进行状态管理。使用 pinia 和 pinia-plugin-persistedstate 看看本地存储。

import { createPinia } from 'pinia'
// 引入pinia本地持久化存储
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' const pinia = createPinia()
pinia.use(piniaPluginPersistedstate) export default pinia

/**
* 聊天状态管理
* @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'] // 设置缓存键
} */
})

OK,以上就是vue3.x开发仿制ChatGPT聊天功能的介绍,希望大家喜欢~~

最后附上一个Vite+Electron桌面MacUI实例

https://www.cnblogs.com/xiaoyan2017/p/14926338.html

Vite-WeGPT聊天AI实例|vue3+pinia仿ChatGPT聊天界面的相关教程结束。

《Vite-WeGPT聊天AI实例|vue3+pinia仿ChatGPT聊天界面.doc》

下载本文的Word格式文档,以方便收藏与打印。