前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue3+Pinia2模拟Chatgpt聊天模板Vue3ChatGPT

Vue3+Pinia2模拟Chatgpt聊天模板Vue3ChatGPT

原创
作者头像
andy2018
发布2023-05-08 22:45:09
1.7K1
发布2023-05-08 22:45:09
举报
文章被收录于专栏:h5h5

这几天一直在了解ChatGPT,结合vite4.x构建了一个vue3版vue3-webgpt。

vue3-webgpt 搭配ve-plus组件库、支持2种界面布局、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
  • 样式处理:sass^1.62.0

特性

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

项目结构

主入口main.js

代码语言:javascript
复制
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聊天框

如上图:聊天框使用ve-plus组件库中的Input组件,设置type=textarea。

代码语言:javascript
复制
<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>
代码语言:javascript
复制
<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>
代码语言:javascript
复制
/**
 * 聊天状态管理
 * @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'] // 设置缓存键
    } */
})

项目中状态管理采用pinia。本地存储采用pinia-plugin-persistedstate

代码语言:javascript
复制
import { createPinia } from 'pinia'
// 引入pinia本地持久化存储
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

export default pinia

vite.config.js配置

代码语言:javascript
复制
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'
			}
		}
	}
})

OK,以上就是vue3开发仿制chatgpt聊天模板实例,希望对大家能喜欢~~

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 技术栈
  • 特性
  • 项目结构
  • 主入口main.js
  • vue3聊天框
  • vite.config.js配置
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档