├── .dockerignore ├── .eslintignore ├── public ├── favicon.ico ├── vite.svg ├── discussion.svg ├── thinking.svg ├── input.svg ├── output.svg ├── evaluate.svg └── common.svg ├── src ├── assets │ ├── bg02.jpeg │ ├── bg03.jpg │ ├── logo.png │ └── original.png ├── styles │ └── index.scss ├── components │ ├── index.ts │ └── Markdown │ │ └── index.vue ├── types │ ├── setting.ts │ ├── shims-axios.d.ts │ ├── role-template.ts │ ├── meeting-template.ts │ └── meeting.ts ├── env.d.ts ├── store │ ├── index.ts │ ├── meeting.ts │ ├── setting.ts │ ├── role-template.ts │ └── meeting-template.ts ├── api │ ├── index.ts │ └── module │ │ ├── index.ts │ │ ├── meeting-template.ts │ │ ├── role-template.ts │ │ └── meeting.ts ├── utils │ ├── copy.ts │ ├── serialization.ts │ ├── index.ts │ └── axios.ts ├── main.ts ├── router │ └── index.ts ├── plugin │ └── el-comp.ts ├── pages │ ├── setting │ │ ├── index.vue │ │ └── components │ │ │ ├── SettingComp.vue │ │ │ └── TempComp.vue │ ├── meeting-template │ │ ├── components │ │ │ ├── MeetingNode.vue │ │ │ ├── PublicMeetingRepo.vue │ │ │ └── TemplateDesign.vue │ │ └── index.vue │ ├── meeting │ │ ├── components │ │ │ ├── OutputComp.vue │ │ │ ├── ProcessingComp.vue │ │ │ └── InputComp.vue │ │ ├── meeting.vue │ │ └── index.vue │ └── role-template │ │ ├── components │ │ └── PublicRoleRepo.vue │ │ └── index.vue └── App.vue ├── tsconfig.node.json ├── Dockerfile ├── .gitignore ├── index.html ├── tsconfig.json ├── LICENSE ├── .eslintrc.js ├── README.md ├── vite.config.ts └── package.json /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .vscode -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | index.html 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PGshen/gpt-meeting-web/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/bg02.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PGshen/gpt-meeting-web/HEAD/src/assets/bg02.jpeg -------------------------------------------------------------------------------- /src/assets/bg03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PGshen/gpt-meeting-web/HEAD/src/assets/bg03.jpg -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PGshen/gpt-meeting-web/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PGshen/gpt-meeting-web/HEAD/src/assets/original.png -------------------------------------------------------------------------------- /src/styles/index.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --main-bg-color: black; 3 | --el-color-primary: #748ffc; 4 | --el-color-primary-light-3: #92a7fa; 5 | } 6 | 7 | .root { 8 | color: var(--main-bg-color); 9 | } -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": [ 8 | "vite.config.ts" 9 | ] 10 | } -------------------------------------------------------------------------------- /src/components/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-05-25 20:47:00 5 | * @LastEditTime: 2023-06-20 23:09:14 6 | */ 7 | import Markdown from './Markdown/index.vue' 8 | 9 | export { Markdown } -------------------------------------------------------------------------------- /src/types/setting.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-07-01 16:42:52 5 | * @LastEditTime: 2023-07-01 17:15:15 6 | */ 7 | export interface Setting { 8 | apiKey: string 9 | model: string 10 | temperature: string 11 | presencePenalty: string 12 | } -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import type { DefineComponent } from 'vue'; 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 6 | const component: DefineComponent<{}, {}, any>; 7 | export default component; 8 | } 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 使用一个基本的 Node.js 镜像 2 | FROM node:alpine 3 | 4 | # 设置工作目录 5 | WORKDIR /app 6 | 7 | # 将项目文件复制到工作目录 8 | COPY . . 9 | 10 | # 安装pnpm 11 | RUN npm install -g pnpm 12 | # 安装项目的依赖 13 | RUN pnpm install 14 | 15 | # 构建项目 16 | RUN pnpm run build 17 | 18 | # 暴露项目的端口 19 | EXPOSE 8080 20 | 21 | # 启动项目 22 | CMD ["pnpm", "run", "preview"] 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-04-29 22:27:47 5 | * @LastEditTime: 2023-06-24 20:18:45 6 | */ 7 | import { createPinia } from 'pinia'; 8 | import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' 9 | 10 | 11 | const store = createPinia(); 12 | store.use(piniaPluginPersistedstate); 13 | 14 | export default store; 15 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | GPT Meeting 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/api/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Date: 2023-05-07 17:15:54 3 | * @LastEditors: Please set LastEditors 4 | * @LastEditTime: 2023-07-02 00:06:33 5 | * @FilePath: /gpt-meeting-service/Users/shen/Me/Code/plan/gpt-meeting-web/src/api/index.ts 6 | */ 7 | import * as index from './module/index'; 8 | import * as roleTemplate from './module/role-template'; 9 | import * as meetingTemplate from './module/meeting-template'; 10 | import * as meeting from './module/meeting' 11 | 12 | export default Object.assign({}, index, roleTemplate, meetingTemplate, meeting); 13 | -------------------------------------------------------------------------------- /src/utils/copy.ts: -------------------------------------------------------------------------------- 1 | export function copyToClip(text: string) { 2 | return new Promise((resolve, reject) => { 3 | try { 4 | const input: HTMLTextAreaElement = document.createElement('textarea') 5 | input.setAttribute('readonly', 'readonly') 6 | input.value = text 7 | document.body.appendChild(input) 8 | input.select() 9 | if (document.execCommand('copy')) 10 | document.execCommand('copy') 11 | document.body.removeChild(input) 12 | resolve(text) 13 | } 14 | catch (error) { 15 | reject(error) 16 | } 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-04-29 22:27:47 5 | * @LastEditTime: 2023-07-05 13:37:04 6 | */ 7 | import { createApp } from 'vue'; 8 | import App from './App.vue'; 9 | import store from './store'; 10 | import router from './router/index'; 11 | import elementPlus from './plugin/el-comp'; 12 | import 'element-plus/theme-chalk/base.css'; 13 | import 'element-plus/theme-chalk/el-overlay.css'; 14 | import '@/utils/serialization' 15 | 16 | // 创建vue实例 17 | const app = createApp(App); 18 | 19 | app.use(store); 20 | app.use(router); 21 | elementPlus(app); 22 | 23 | // 挂载实例 24 | app.mount('#app'); 25 | -------------------------------------------------------------------------------- /src/api/module/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-04-29 22:27:47 5 | * @LastEditTime: 2023-07-02 00:03:30 6 | */ 7 | import { useSettingStore } from "@/store/setting"; 8 | export interface IResponseType

{ 9 | code?: number; 10 | msg?: string; 11 | data?: P; 12 | } 13 | 14 | /** 15 | * 获取设置 16 | * @returns 17 | */ 18 | export function getSettingWithCors() { 19 | const headers = useSettingStore().getSetting() as Record; 20 | headers['Content-Type'] = 'application/json'; 21 | headers['Sec-Fetch-Mode'] = 'cors'; 22 | headers['Sec-Fetch-Dest'] = 'empty'; 23 | headers['Sec-Fetch-Site'] = 'same-site'; 24 | return headers; 25 | } -------------------------------------------------------------------------------- /src/types/shims-axios.d.ts: -------------------------------------------------------------------------------- 1 | import { AxiosRequestConfig } from 'axios'; 2 | /** 3 | * 自定义扩展axios模块 4 | * @author Maybe 5 | */ 6 | declare module 'axios' { 7 | export interface AxiosInstance { 8 | (config: AxiosRequestConfig): Promise; 9 | request(config: AxiosRequestConfig): Promise; 10 | get(url: string, config?: AxiosRequestConfig): Promise; 11 | delete(url: string, config?: AxiosRequestConfig): Promise; 12 | head(url: string, config?: AxiosRequestConfig): Promise; 13 | post(url: string, data?: any, config?: AxiosRequestConfig): Promise; 14 | put(url: string, data?: any, config?: AxiosRequestConfig): Promise; 15 | patch(url: string, data?: any, config?: AxiosRequestConfig): Promise; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/store/meeting.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-06-07 13:37:47 5 | * @LastEditTime: 2023-07-05 00:28:40 6 | */ 7 | import { FlowItem } from '@/types/meeting'; 8 | import { defineStore } from 'pinia'; 9 | 10 | export const useMeetingStore = defineStore({ 11 | id: 'meeting', 12 | state: () => { 13 | return { 14 | nowStatus: '', 15 | flowMap: new Map(), 16 | nowMeetingId: '' 17 | } 18 | }, 19 | actions: { 20 | addFlowItem(id: string, flowInfo: FlowItem): void { 21 | this.flowMap.set(id, flowInfo); 22 | }, 23 | getFlowItem(id: string): FlowItem | undefined { 24 | return this.flowMap.get(id); 25 | }, 26 | setNowMeetingId(meetingId: string) { 27 | this.nowMeetingId = meetingId; 28 | }, 29 | getNowMeetingId(): string { 30 | return this.nowMeetingId; 31 | } 32 | } 33 | }) -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "typeRoots": [ 4 | "node_modules/@types", // 默认值 5 | "src/types" 6 | ], 7 | "target": "esnext", 8 | "useDefineForClassFields": true, 9 | "module": "esnext", 10 | "moduleResolution": "node", 11 | "strict": true, 12 | "jsx": "preserve", 13 | "sourceMap": true, 14 | "resolveJsonModule": true, 15 | "esModuleInterop": true, 16 | "strictNullChecks": false, 17 | "noImplicitAny": false, 18 | "skipLibCheck": true, 19 | "lib": [ 20 | "esnext", 21 | "dom" 22 | ], 23 | "baseUrl": "./", 24 | "paths": { 25 | "@": [ 26 | "src" 27 | ], 28 | "@/*": [ 29 | "src/*" 30 | ] 31 | } 32 | }, 33 | "include": [ 34 | "src/**/*.ts", 35 | "src/**/*.d.ts", 36 | "src/**/*.tsx", 37 | "src/**/*.vue" 38 | ], 39 | "references": [ 40 | { 41 | "path": "./tsconfig.node.json" 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /src/store/setting.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-07-01 17:13:00 5 | * @LastEditTime: 2023-07-01 23:59:52 6 | */ 7 | import { Setting } from '@/types/setting' 8 | import { defineStore } from 'pinia'; 9 | 10 | export const useSettingStore = defineStore({ 11 | id: 'setting', // id必填,且需要唯一 12 | state: () => { 13 | return { 14 | setting: {} as Setting 15 | }; 16 | }, 17 | actions: { 18 | updateSetting(setting: Setting) { 19 | this.setting = setting 20 | }, 21 | getSetting() { 22 | return this.setting 23 | }, 24 | getSettingWithCors() { 25 | const headers = this.setting as Record; 26 | headers['Content-Type'] = 'application/json'; 27 | headers['Sec-Fetch-Mode'] = 'cors'; 28 | headers['Sec-Fetch-Dest'] = 'empty'; 29 | headers['Sec-Fetch-Site'] = 'same-site'; 30 | return headers; 31 | } 32 | }, 33 | persist: { 34 | paths: ['setting'] 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /src/api/module/meeting-template.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-05-11 18:18:12 5 | * @LastEditTime: 2023-05-11 18:19:57 6 | */ 7 | import request from '@/utils/axios'; 8 | import { IResponseType } from '.'; 9 | import { BoolReply, MeetingTemplate, Query } from '@/types/meeting-template'; 10 | 11 | export const createMeetingTemplate = (data: MeetingTemplate) => { 12 | return request>({ 13 | url: '/api/template/meeting', 14 | method: 'post', 15 | data: data 16 | }); 17 | } 18 | 19 | export const updateMeetingTemplate = (data: MeetingTemplate) => { 20 | return request>({ 21 | url: '/api/template/meeting', 22 | method: 'post', 23 | data: data 24 | }); 25 | } 26 | 27 | export const getMeetingTemplateList = (data: Query) => { 28 | return request({ 29 | url: '/api/template/meeting', 30 | method: 'get', 31 | params: data 32 | }).then(function(response) { 33 | return response 34 | }); 35 | } -------------------------------------------------------------------------------- /src/store/role-template.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-05-02 22:09:36 5 | * @LastEditTime: 2023-06-24 20:44:24 6 | */ 7 | import { RoleInfo } from '@/types/role-template'; 8 | import { defineStore } from 'pinia'; 9 | 10 | export const useRoleTemplateStore = defineStore({ 11 | id: 'roleTemplate', // id必填,且需要唯一 12 | state: () => { 13 | return { 14 | myTemplateMap: new Map() 15 | }; 16 | }, 17 | actions: { 18 | addMyTemplate(role: RoleInfo) { 19 | this.myTemplateMap.set(role.id, role); 20 | }, 21 | removeMyTemplate(id: string) { 22 | this.myTemplateMap.delete(id); 23 | }, 24 | getMyTemplateList() { 25 | const roleList:RoleInfo[] = [] 26 | if (this.myTemplateMap.size > 0) { 27 | this.myTemplateMap.forEach((value) => { 28 | roleList.push(value) 29 | }) 30 | } 31 | return roleList 32 | } 33 | }, 34 | persist: { 35 | paths: ['myTemplateMap'] 36 | } 37 | }); 38 | -------------------------------------------------------------------------------- /src/types/role-template.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-05-11 17:41:11 5 | * @LastEditTime: 2023-06-24 21:11:17 6 | */ 7 | 8 | export interface RoleInfo { 9 | id: string; 10 | avatar: string; 11 | summary: string; 12 | description: string; 13 | example: string; 14 | starCount: number; 15 | createdBy: string; 16 | createdTime: number; 17 | } 18 | 19 | export interface RoleList { 20 | total: number; 21 | data: RoleInfo[]; 22 | } 23 | 24 | export interface CreateRole { 25 | avatar: string; 26 | summary: string; 27 | description: string; 28 | example: string; 29 | createdBy: string; 30 | } 31 | 32 | export interface UpdateRole { 33 | id: string; 34 | avatar: string; 35 | summary: string; 36 | description: string; 37 | example: string; 38 | createdBy: string; 39 | } 40 | 41 | export interface BoolReply { 42 | ok: boolean 43 | } 44 | 45 | export interface Query { 46 | id?: string; 47 | summary?: string; 48 | pageNum?: number; 49 | pageSize?: number; 50 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 GPT-Meeting 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/api/module/role-template.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-05-01 19:13:03 5 | * @LastEditTime: 2023-07-02 16:29:09 6 | */ 7 | import request from '@/utils/axios'; 8 | import { IResponseType } from '.'; 9 | import { BoolReply, CreateRole, UpdateRole, Query } from '@/types/role-template'; 10 | 11 | export const createRole = (data: CreateRole) => { 12 | return request>({ 13 | url: '/api/template/role', 14 | method: 'post', 15 | data: data 16 | }); 17 | } 18 | 19 | 20 | export const updateRole = (data: UpdateRole) => { 21 | return request>({ 22 | url: '/api/template/role', 23 | method: 'put', 24 | data: data 25 | }); 26 | } 27 | 28 | export const deleteRole = (id: string) => { 29 | return request>({ 30 | url: '/api/template/role?id=' + id, 31 | method: 'delete' 32 | }); 33 | } 34 | 35 | export const getRoleList = (data: Query) => { 36 | return request({ 37 | url: '/api/template/role', 38 | method: 'get', 39 | params: data 40 | }).then(function(response) { 41 | return response 42 | }); 43 | } -------------------------------------------------------------------------------- /src/utils/serialization.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 使json序列化支持Set,Map类型 3 | * @version: 4 | * @Date: 2023-06-24 20:40:09 5 | * @LastEditTime: 2023-06-24 20:44:04 6 | */ 7 | const { stringify, parse } = JSON 8 | 9 | JSON.stringify = function (value, replacer, space) { 10 | const _replacer = 11 | typeof replacer === 'function' 12 | ? replacer 13 | : function (_, value) { 14 | return value 15 | } 16 | replacer = function (key, value) { 17 | value = _replacer(key, value) 18 | if (value instanceof Set) value = `Set{${stringify([...value])}}` 19 | else if (value instanceof Map) value = `Map{${stringify([...value])}}` 20 | return value 21 | } 22 | return stringify(value, replacer, space) 23 | } 24 | 25 | JSON.parse = function (value, reviver) { 26 | if (!reviver) 27 | reviver = function (key, value) { 28 | if (/Set\{\[.*\]\}/.test(value)) 29 | value = new Set(parse(value.replace(/Set\{\[(.*)\]\}/, '[$1]'))) 30 | else if (/Map\{\[.*\]\}/.test(value)) 31 | value = new Map(parse(value.replace(/Map\{\[(.*)\]\}/, '[$1]'))) 32 | return value 33 | } 34 | return parse(value, reviver) 35 | } -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Date: 2023-05-30 23:07:17 3 | * @LastEditors: peng pgs1108pgs@126.com 4 | * @LastEditTime: 2023-06-04 21:47:31 5 | * @FilePath: /gpt-meeting-service/Users/shen/Me/Code/plan/gpt-meeting-web/src/utils/index.ts 6 | */ 7 | 8 | /** 9 | * @description: 随机字符串 10 | * @return {*} 11 | */ 12 | export function genRandomString(length: number) { 13 | let result = ''; 14 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 15 | for (let i = 0; i < length; i++) { 16 | result += characters.charAt(Math.floor(Math.random() * characters.length)); 17 | } 18 | return result; 19 | } 20 | 21 | /** 22 | * @description: 时间戳格式化 23 | * @param {number} timestamp 24 | * @return {*} 25 | */ 26 | export function formatTime(timestamp: number): string { 27 | const date = new Date(timestamp * 1000); 28 | const Y = date.getFullYear(); 29 | const M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1); 30 | const D = date.getDate(); 31 | const h = date.getHours(); 32 | const m = date.getMinutes(); 33 | const s = date.getSeconds(); 34 | return Y + '-' + M + '-' + D + ' ' + h + ':' + m + ':' + s; 35 | } -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/axios.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-04-29 22:27:47 5 | * @LastEditTime: 2023-07-01 20:33:32 6 | */ 7 | import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'; 8 | import { ElMessage } from 'element-plus'; 9 | import { useSettingStore } from '@/store/setting'; 10 | 11 | const setting = useSettingStore().getSetting(); 12 | 13 | axios.defaults.headers.common['apiKey'] = setting.apiKey; 14 | axios.defaults.headers.common['model'] = setting.model; 15 | axios.defaults.headers.common['temperature'] = setting.temperature; 16 | axios.defaults.headers.common['presencePenalty'] = setting.presencePenalty; 17 | 18 | const service = axios.create(); 19 | 20 | // Request interceptors 21 | service.interceptors.request.use( 22 | (config: AxiosRequestConfig) => { 23 | // do something 24 | return config; 25 | }, 26 | (error: any) => { 27 | Promise.reject(error); 28 | } 29 | ); 30 | 31 | // Response interceptors 32 | service.interceptors.response.use( 33 | async (response: AxiosResponse) => { 34 | console.log(response); 35 | if (response.status != 200) { 36 | ElMessage.error('Request error!'); 37 | } 38 | const data = response.data 39 | if (data.code != 200) { 40 | ElMessage.error(data.msg); 41 | } 42 | 43 | return response; 44 | // do something 45 | }, 46 | (error: any) => { 47 | // do something 48 | return Promise.reject(error); 49 | } 50 | ); 51 | 52 | export default service; 53 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'vue-eslint-parser', 3 | 4 | parserOptions: { 5 | parser: '@typescript-eslint/parser', 6 | ecmaVersion: 2020, 7 | sourceType: 'module', 8 | ecmaFeatures: { 9 | jsx: true 10 | } 11 | }, 12 | 13 | extends: [ 14 | 'plugin:vue/vue3-recommended', 15 | 'plugin:@typescript-eslint/recommended' 16 | ], 17 | 18 | rules: { 19 | '@typescript-eslint/ban-ts-ignore': 'off', 20 | '@typescript-eslint/explicit-function-return-type': 'off', 21 | '@typescript-eslint/no-explicit-any': 'off', 22 | '@typescript-eslint/no-var-requires': 'off', 23 | '@typescript-eslint/no-empty-function': 'off', 24 | 'vue/custom-event-name-casing': 'off', 25 | 'no-use-before-define': 'off', 26 | '@typescript-eslint/no-use-before-define': 'off', 27 | '@typescript-eslint/ban-ts-comment': 'off', 28 | '@typescript-eslint/ban-types': 'off', 29 | '@typescript-eslint/no-non-null-assertion': 'off', 30 | '@typescript-eslint/explicit-module-boundary-types': 'off', 31 | '@typescript-eslint/no-unused-vars': [ 32 | 'error', 33 | { 34 | argsIgnorePattern: '^h$', 35 | varsIgnorePattern: '^h$' 36 | } 37 | ], 38 | 'no-unused-vars': [ 39 | 'error', 40 | { 41 | argsIgnorePattern: '^h$', 42 | varsIgnorePattern: '^h$' 43 | } 44 | ], 45 | 'space-before-function-paren': 'off', 46 | quotes: ['error', 'single'], 47 | 'comma-dangle': ['error', 'never'] 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 7 | # gpt-meeting-web 8 | ## 零、是干嘛的 9 | 1. 这是一个基于GPT的API开发的小项目。众所周知目前GPT的上下文支持就是每次把历史消息都再次发出去,方法很「简单粗暴」,而这个项目简单的说就只做了一件事:就是让上下文组织更灵活,以支持完成更加复杂一些的任务。 10 | 2. 项目最初的灵感来源是「头脑风暴」和「6顶思考帽」。头脑风暴在进行的过程中,每个环节关注的重点不同,需要不同的角色发挥作用,这一过程正好是和6顶思考帽的使用契合的。6顶思考帽的灵活配合使用可以达成不同的目的,再延伸之后就有了这个项目「会议meeting」或者叫讨论会。 11 | 3. 基于以上,项目最主要实现以下3个功能 12 | 1. 任务流程图的编排,每个环节完成一件事,串起来完成一项相对复杂的任务(也理解为会议议程设计)。 13 | 2. 让GPT自问自答,完成联想。 14 | 3. 让GPT分别扮演不同的角色,对同一个话题进行讨论。 15 | 4. 可能的应用场景 16 | 1. 头脑风暴 17 | 2. 快速联想 18 | 3. 快速评估 19 | 4. 多角色对话 20 | 21 | > 其他介绍请参考后端项目:[gpt-meeting-service](https://github.com/PGshen/gpt-meeting-service) 22 | 23 | # 开发相关 24 | ## 技术选型 25 | - 语言:TypeScript 26 | - 构建工具:vite 27 | - 框架:vue3 28 | - UI: element-plus 29 | - 状态管理: Pinia 30 | - 路由:vue-router 31 | - SSE: microsoft/fetch-event-source 32 | - 模版编排:antv X6 33 | - 图:antv G6 34 | 35 | ## 建议环境 36 | - [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). 37 | 38 | ## 跑起来 39 | ``` 40 | # 如果服务端也在本地,需要本地hosts添加如下记录,或者修改vite.config.js文件里的proxy配置 41 | 127.0.0.1 gpt-meeting-service 42 | 43 | # 依赖安装 44 | pnpm install 45 | 46 | # 本地运行 47 | pnpm run dev 48 | 49 | # 打包 50 | pnpm run build 51 | ``` 52 | 53 | ## docker镜像构建 54 | ``` 55 | docker build -t gpt-meeting-web:v1 . 56 | ``` -------------------------------------------------------------------------------- /public/discussion.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 节点_left_join 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-04-09 18:29:19 5 | * @LastEditTime: 2023-06-25 13:21:31 6 | */ 7 | import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; 8 | 9 | const routes: Array = [ 10 | { 11 | path: '/', 12 | name: 'IndexPage', 13 | meta: { 14 | title: '首页', 15 | keepAlive: true, 16 | requireAuth: true 17 | }, 18 | component: () => import('@/pages/meeting/index.vue') 19 | }, 20 | { 21 | path: '/setting', 22 | name: 'Setting', 23 | meta: { 24 | title: '信息设置', 25 | keepAlive: true, 26 | requireAuth: true 27 | }, 28 | component: () => import('@/pages/setting/index.vue') 29 | }, 30 | { 31 | path: '/meetingTemplate', 32 | name: 'MeetingTemplate', 33 | meta: { 34 | title: '会议模版', 35 | keepAlive: true, 36 | requireAuth: true 37 | }, 38 | component: () => import('@/pages/meeting-template/index.vue') 39 | }, 40 | { 41 | path: '/roleTemplate', 42 | name: 'RoleTemplate', 43 | meta: { 44 | title: '角色模版', 45 | keepAlive: true, 46 | requireAuth: true 47 | }, 48 | component: () => import('@/pages/role-template/index.vue') 49 | }, 50 | { 51 | path: '/meeting', 52 | name: 'Meeting', 53 | meta: { 54 | title: '会议管理', 55 | keepAlive: true, 56 | requireAuth: true 57 | }, 58 | component: () => import('@/pages/meeting/index.vue') 59 | }, 60 | { 61 | path: '/meeting/meeting', 62 | name: 'Meeting', 63 | meta: { 64 | title: '开会啦', 65 | keepAlive: true, 66 | requireAuth: true 67 | }, 68 | component: () => import('@/pages/meeting/meeting.vue') 69 | } 70 | ]; 71 | 72 | const router = createRouter({ 73 | history: createWebHistory(), 74 | routes 75 | }); 76 | export default router; 77 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-04-29 22:27:47 5 | * @LastEditTime: 2023-07-12 23:48:56 6 | */ 7 | import { defineConfig } from 'vite'; 8 | import vue from '@vitejs/plugin-vue'; 9 | import { 10 | createStyleImportPlugin, 11 | ElementPlusResolve 12 | } from 'vite-plugin-style-import' 13 | import * as path from 'path'; 14 | 15 | // https://vitejs.dev/config/ 16 | export default defineConfig({ 17 | resolve: { 18 | //设置别名 19 | alias: { 20 | '@': path.resolve(__dirname, 'src'), 21 | '@antv/x6': path.resolve('node_modules/@antv/x6/dist/index.js') 22 | } 23 | }, 24 | css: { 25 | preprocessorOptions: { 26 | scss: { 27 | additionalData: '@use "@/styles/index.scss" as *;' 28 | } 29 | } 30 | }, 31 | plugins: [ 32 | vue(), 33 | createStyleImportPlugin({ 34 | resolves: [ 35 | ElementPlusResolve() 36 | ], 37 | libs: [ 38 | { 39 | libraryName: 'element-plus', 40 | esModule: true, 41 | resolveStyle: (name) => { 42 | return `element-plus/theme-chalk/${name}.css` 43 | }, 44 | ensureStyleFile: true // 忽略文件是否存在, 导入不存在的CSS文件时防止错误。 45 | } 46 | ] 47 | }) 48 | ], 49 | server: { 50 | port: 8080, //启动端口 51 | hmr: { 52 | host: 'localhost', 53 | port: 8080 54 | }, 55 | // 设置代理 56 | proxy: { 57 | '/api': { 58 | target: 'http://gpt-meeting-service:8000', 59 | // target: 'http://0.0.0.0:8000', 60 | changeOrigin: true 61 | // rewrite: (path: string) => path.replace(/^\/api/, '') 62 | }, 63 | '/image': { 64 | target: 'http://gpt-meeting-service:8000', 65 | // target: 'http://0.0.0.0:8000', 66 | changeOrigin: true 67 | // rewrite: (path: string) => path.replace(/^\/api/, '') 68 | } 69 | } 70 | } 71 | }); 72 | -------------------------------------------------------------------------------- /public/thinking.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 节点_数据聚合 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /public/input.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 节点_数据表 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gpt-meeting-web", 3 | "private": true, 4 | "version": "1.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vue-tsc --noEmit && vite build --mode production", 8 | "preview": "vite preview --port 8080 --host 0.0.0.0", 9 | "eslint:comment": "使用 ESLint 检查并自动修复 src 目录下所有扩展名为 .js 和 .vue 的文件", 10 | "eslint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src" 11 | }, 12 | "config": {}, 13 | "lint-staged": { 14 | "*.{js,ts,vue}": [ 15 | "pnpm run eslint" 16 | ] 17 | }, 18 | "dependencies": { 19 | "@antv/g6": "^4.8.9", 20 | "@antv/x6": "^2.9.7", 21 | "@antv/x6-plugin-clipboard": "^2.1.6", 22 | "@antv/x6-plugin-dnd": "^2.0.5", 23 | "@antv/x6-plugin-history": "^2.2.1", 24 | "@antv/x6-plugin-keyboard": "^2.2.1", 25 | "@antv/x6-plugin-scroller": "^2.0.9", 26 | "@antv/x6-plugin-selection": "^2.1.7", 27 | "@antv/x6-plugin-snapline": "^2.1.7", 28 | "@antv/x6-plugin-stencil": "^2.0.3", 29 | "@antv/x6-plugin-transform": "^2.1.7", 30 | "@antv/x6-vue-shape": "^2.0.11", 31 | "@element-plus/icons-vue": "^2.1.0", 32 | "@microsoft/fetch-event-source": "^2.0.1", 33 | "@traptitech/markdown-it-katex": "^3.6.0", 34 | "axios": "^0.26.1", 35 | "element-plus": "^2.3.7", 36 | "highlight.js": "^11.8.0", 37 | "markdown-it": "^13.0.1", 38 | "markdown-it-highlightjs": "^4.0.1", 39 | "pinia": "^2.0.12", 40 | "pinia-plugin-persistedstate": "^3.1.0", 41 | "vue": "^3.2.25", 42 | "vue-router": "^4.0.14" 43 | }, 44 | "devDependencies": { 45 | "@types/markdown-it": "^12.2.3", 46 | "@types/markdown-it-link-attributes": "^3.0.1", 47 | "@types/node": "^17.0.23", 48 | "@typescript-eslint/eslint-plugin": "^5.16.0", 49 | "@typescript-eslint/parser": "^5.16.0", 50 | "@vitejs/plugin-vue": "^2.2.0", 51 | "consola": "^2.15.3", 52 | "eslint": "^8.12.0", 53 | "eslint-plugin-vue": "^8.5.0", 54 | "lint-staged": "^12.3.7", 55 | "markdown-it-link-attributes": "^4.0.1", 56 | "sass": "^1.61.0", 57 | "scss": "^0.2.4", 58 | "typescript": "^4.5.4", 59 | "vite": "^2.8.0", 60 | "vite-plugin-style-import": "^2.0.0", 61 | "vue-tsc": "^0.29.8" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /public/output.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | add_数据输出 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/plugin/el-comp.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 按需引入elementUI组件 3 | * @version: 4 | * @Date: 2023-04-09 22:33:53 5 | * @LastEditTime: 2023-07-02 16:30:14 6 | */ 7 | import { 8 | ElAlert, 9 | ElAside, 10 | ElButton, 11 | ElSelect, 12 | ElRow, 13 | ElCol, 14 | ElForm, 15 | ElFormItem, 16 | ElInput, 17 | ElInputNumber, 18 | ElTabs, 19 | ElTabPane, 20 | ElCheckbox, 21 | ElIcon, 22 | ElDivider, 23 | ElContainer, 24 | ElMenu, 25 | ElMenuItem, 26 | ElHeader, 27 | ElFooter, 28 | ElMain, 29 | ElCard, 30 | ElText, 31 | ElSwitch, 32 | ElSpace, 33 | ElTable, 34 | ElTableColumn, 35 | ElAvatar, 36 | ElDialog, 37 | ElOption, 38 | ElMessage, 39 | ElUpload, 40 | ElDrawer, 41 | ElTooltip, 42 | ElPopper, 43 | ElProgress, 44 | ElDropdown, 45 | ElDropdownMenu, 46 | ElDropdownItem, 47 | ElNotification, 48 | ElDescriptions, 49 | ElDescriptionsItem, 50 | ElCollapse, 51 | ElCollapseItem, 52 | ElStep, 53 | ElSteps, 54 | ElEmpty, 55 | ElScrollbar, 56 | ElAffix, 57 | ElTag, 58 | ElSlider 59 | } from 'element-plus'; 60 | 61 | 62 | // 所需的组件 63 | export const components = [ 64 | ElAlert, 65 | ElAside, 66 | ElButton, 67 | ElSelect, 68 | ElRow, 69 | ElCol, 70 | ElForm, 71 | ElFormItem, 72 | ElInput, 73 | ElInputNumber, 74 | ElTabs, 75 | ElTabPane, 76 | ElCheckbox, 77 | ElIcon, 78 | ElDivider, 79 | ElContainer, 80 | ElMenu, 81 | ElMenuItem, 82 | ElHeader, 83 | ElFooter, 84 | ElMain, 85 | ElCard, 86 | ElText, 87 | ElSwitch, 88 | ElSpace, 89 | ElTable, 90 | ElTableColumn, 91 | ElAvatar, 92 | ElDialog, 93 | ElOption, 94 | ElMessage, 95 | ElUpload, 96 | ElDrawer, 97 | ElTooltip, 98 | ElPopper, 99 | ElProgress, 100 | ElDropdown, 101 | ElDropdownMenu, 102 | ElDropdownItem, 103 | ElNotification, 104 | ElDescriptions, 105 | ElDescriptionsItem, 106 | ElCollapse, 107 | ElCollapseItem, 108 | ElStep, 109 | ElSteps, 110 | ElEmpty, 111 | ElScrollbar, 112 | ElAffix, 113 | ElTag, 114 | ElSlider 115 | ]; 116 | 117 | import * as ElementPlusIconsVue from '@element-plus/icons-vue' 118 | 119 | 120 | // 注册 121 | export default (app: any) => { 122 | components.forEach((component) => { 123 | app.component(component.name, component); 124 | }); 125 | for (const [key, component] of Object.entries(ElementPlusIconsVue)) { 126 | app.component(key, component) 127 | } 128 | }; 129 | -------------------------------------------------------------------------------- /src/store/meeting-template.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 会议相关操作 3 | * @version: 4 | * @Date: 2023-05-09 13:15:35 5 | * @LastEditTime: 2023-07-09 21:15:25 6 | */ 7 | import { MeetingTemplate, TemplateNodeInfo } from '@/types/meeting-template'; 8 | import { defineStore } from 'pinia'; 9 | 10 | 11 | export const useMeetingTemplateStore = defineStore({ 12 | id: 'meetingTemplate', 13 | state: () => { 14 | return { 15 | templateNodeMap: new Map(), // 节点信息 16 | selectedNodeId: '', // 当前选中的节点ID 17 | myTemplateMap: new Map() // 收藏的模版 18 | }; 19 | }, 20 | actions: { 21 | addNode(id: string, nodeInfo: TemplateNodeInfo): void { 22 | this.templateNodeMap.set(id, nodeInfo); 23 | }, 24 | removeNode(id: string): void { 25 | this.templateNodeMap.delete(id); 26 | }, 27 | getCurrentNode(): TemplateNodeInfo | undefined { 28 | return this.templateNodeMap.get(this.selectedNodeId); 29 | }, 30 | setSelectedNodeId(nodeId: string) { 31 | this.selectedNodeId = nodeId; 32 | }, 33 | unsetSelectedNodeId() { 34 | this.selectedNodeId = ''; 35 | }, 36 | resetTemplate() { // 重置模版 37 | this.templateNodeMap.clear(); 38 | this.selectedNodeId = ''; 39 | }, 40 | restoreTemplate(template: MeetingTemplate) { // 恢复模版数据 41 | const templateData = JSON.parse(template.templateData); 42 | const keys = Object.keys(templateData); 43 | keys.forEach(key => { 44 | const jsonNode = templateData[key]; 45 | const nodeInfo: TemplateNodeInfo = { 46 | id: jsonNode['id'], 47 | nodeType: jsonNode['nodeType'], 48 | nodeName: jsonNode['nodeName'], 49 | characters: jsonNode['characters'], 50 | associationCharacters: jsonNode['associationCharacters'], 51 | quizCharacters: jsonNode['quizCharacters'], 52 | optimizationPrompt: jsonNode['optimizationPrompt'], 53 | prologuePrompt: jsonNode['prologuePrompt'], 54 | summaryPrompt: jsonNode['summaryPrompt'], 55 | processingPrompt: jsonNode['processingPrompt'], 56 | quizPrompt: jsonNode['quizPrompt'], 57 | quizRound: jsonNode['quizRound'], 58 | quizNum: jsonNode['quizNum'], 59 | replyRound: jsonNode['replyRound'], 60 | memberIds: jsonNode['memberIds'] 61 | } 62 | // console.log(nodeInfo); 63 | this.addNode(key, nodeInfo); 64 | }); 65 | }, 66 | addMyTemplate(template: MeetingTemplate) { 67 | this.myTemplateMap.set(template.id, template); 68 | }, 69 | removeMyTemplate(id: string) { 70 | this.myTemplateMap.delete(id); 71 | }, 72 | getMyTemplateList() { 73 | const templateList: MeetingTemplate[] = []; 74 | this.myTemplateMap.forEach((value) => { 75 | templateList.push(value); 76 | }) 77 | return templateList; 78 | } 79 | }, 80 | persist: { 81 | paths: ['myTemplateMap'] 82 | } 83 | }); 84 | 85 | -------------------------------------------------------------------------------- /src/pages/setting/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 39 | 40 | 78 | 79 | 136 | -------------------------------------------------------------------------------- /public/evaluate.svg: -------------------------------------------------------------------------------- 1 | 2 | 节点_数据筛选 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 43 | 44 | 100 | 101 | -------------------------------------------------------------------------------- /src/types/meeting-template.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-05-11 17:32:21 5 | * @LastEditTime: 2023-07-09 21:14:43 6 | */ 7 | import { Cell } from '@antv/x6'; 8 | 9 | // 节点类型 10 | export enum NodeType { 11 | Input = 'Input', // 主题/目标输入 12 | Thinking = 'Thinking', // 联想思考 13 | Discussion = 'Discussion', // 主题讨论 14 | Processing = 'Processing', // 通用 15 | Output = 'Output', // 结论输出 16 | } 17 | 18 | /** 19 | * 会议模版基础信息 20 | */ 21 | export interface TemplateBaseInfo { 22 | avatar: string; 23 | templateName: string; 24 | description: string; 25 | example: string; 26 | } 27 | 28 | /** 29 | * 节点信息 30 | */ 31 | export interface TemplateNodeInfo { 32 | id: string; 33 | nodeType: string; 34 | nodeName?: string; 35 | characters?: string; // 人设 36 | associationCharacters?: string; // 联想AI人设 [thinking专用] 37 | quizCharacters?: string; // 提问AI人设 [thinking专用] 38 | optimizationPrompt?: string; // 优化 [input] 39 | prologuePrompt?: string; // 开场 [thinking,discussion] 40 | summaryPrompt?: string; // 总结 [output,thinking,discussion] 41 | processingPrompt?: string; // 处理 [processing] 42 | quizPrompt?: string; // 提问 [thinking] 43 | quizRound?: number; // 轮次 [thinking] 44 | quizNum?: number; // 次数 [thinking] 45 | replyRound?: number; // 回答轮次 [discussion] 46 | memberIds?: string[]; // 成员角色ID列表 [thinking] 47 | } 48 | 49 | /** 50 | * 会议模版 51 | */ 52 | export class MeetingTemplate { 53 | id?: string; 54 | avatar!: string; 55 | name!: string; 56 | description?: string; 57 | example?: string; 58 | templateFlow?: string; // 流程图信息 59 | templateData?: string; // 节点信息 60 | starCount?: number; 61 | createdBy?: string; 62 | 63 | constructor() { } 64 | 65 | setAvatar(avatar: string) { 66 | this.avatar = avatar; 67 | } 68 | 69 | setTemplateName(templateName: string) { 70 | this.name = templateName; 71 | } 72 | 73 | setDescription(description: string) { 74 | this.description = description; 75 | } 76 | 77 | setExample(example: string) { 78 | this.example = example; 79 | } 80 | 81 | setTemplateData(templateData: Map) { 82 | console.log(templateData); 83 | const obj: any = {}; 84 | templateData.forEach((value, key) => { 85 | obj[key] = value; 86 | }); 87 | this.templateData = JSON.stringify(obj); 88 | } 89 | 90 | setTemplateFlow(templateFlow: { cells: Cell.Properties[] }) { 91 | this.templateFlow = JSON.stringify(templateFlow); 92 | } 93 | 94 | setStarCount(starCount: number) { 95 | this.starCount = starCount; 96 | } 97 | 98 | setCreatedBy(createdBy: string) { 99 | this.createdBy = createdBy 100 | } 101 | 102 | check(obj): string[] { 103 | const emptyProperty = []; 104 | const propertyNames = Object.getOwnPropertyNames(obj); 105 | propertyNames.forEach((propertyName) => { 106 | if (propertyName === 'starCount' || propertyName == 'id') { 107 | return; 108 | } 109 | if(obj[propertyName] === undefined || obj[propertyName] === '') { 110 | emptyProperty.push(propertyName); 111 | } 112 | }) 113 | console.log(propertyNames); 114 | console.log(emptyProperty); 115 | return emptyProperty; 116 | } 117 | 118 | } 119 | 120 | export interface MeetingTemplateList { 121 | total: number; 122 | data: MeetingTemplate[]; 123 | } 124 | 125 | export interface BoolReply { 126 | ok: boolean 127 | } 128 | 129 | export interface Query { 130 | id?: string; 131 | templateName: string; 132 | pageNum?: number; 133 | pageSize?: number; 134 | } -------------------------------------------------------------------------------- /src/api/module/meeting.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Date: 2023-06-04 17:29:33 3 | * @LastEditors: peng pgs1108pgs@126.com 4 | * @LastEditTime: 2023-07-03 23:28:49 5 | * @FilePath: /gpt-meeting-service/Users/shen/Me/Code/plan/gpt-meeting-web/src/api/module/meeting.ts 6 | */ 7 | import request from '@/utils/axios'; 8 | import { IResponseType } from '.'; 9 | import { Query, NewMeeting, MeetingList, NewMeetingReply, ProgressReply, UpdateStatus, MeetingFlowItemReq, ThinkingPresets, DiscussionPresets, InputData, ThinkingData, DiscussionData, ProcessingData, OutputData} from '@/types/meeting'; 10 | 11 | export const history = (data: Query) => { 12 | return request>({ 13 | url: '/api/meeting/history', 14 | method: 'get', 15 | data: data 16 | }); 17 | } 18 | 19 | export const newMeeting = (data: NewMeeting) => { 20 | return request>({ 21 | url: '/api/meeting/newmeeting', 22 | method: 'post', 23 | data: data 24 | }) 25 | } 26 | 27 | export const progress = (meetingId: string) => { 28 | return request>({ 29 | url: '/api/meeting/progress?meetingId=' + meetingId, 30 | method: 'get' 31 | }) 32 | } 33 | 34 | export const start = async (data: UpdateStatus) => { 35 | return await request({ 36 | url: '/api/meeting/start', 37 | method: 'put', 38 | data: data 39 | }) 40 | } 41 | 42 | export const end = (data: UpdateStatus) => { 43 | return request({ 44 | url: '/api/meeting/end', 45 | method: 'put', 46 | data: data 47 | }) 48 | } 49 | 50 | export const getInputData = (meetingId: string, flowItemId: string) => { 51 | return request>({ 52 | url: '/api/meeting/getInputData?meetingId=' + meetingId + '&flowItemId=' + flowItemId, 53 | method: 'get' 54 | }) 55 | } 56 | 57 | export const submitInput = async (data: MeetingFlowItemReq) => { 58 | return await request({ 59 | url: '/api/meeting/submitInput', 60 | method: 'put', 61 | data: data 62 | }) 63 | } 64 | 65 | export const getThinkingData = (meetingId: string, flowItemId: string) => { 66 | return request>({ 67 | url: '/api/meeting/getThinkingData?meetingId=' + meetingId + '&flowItemId=' + flowItemId, 68 | method: 'get' 69 | }) 70 | } 71 | 72 | export const saveThinkingPresets = (data: ThinkingPresets) => { 73 | return request({ 74 | url: '/api/meeting/saveThinkingPresets', 75 | method: 'post', 76 | data: data 77 | }) 78 | } 79 | 80 | export const getDiscussionData = (meetingId: string, flowItemId: string) => { 81 | return request>({ 82 | url: '/api/meeting/getDiscussionData?meetingId=' + meetingId + '&flowItemId=' + flowItemId, 83 | method: 'get' 84 | }) 85 | } 86 | 87 | 88 | export const saveDiscussionPresets = (data: DiscussionPresets) => { 89 | return request({ 90 | url: '/api/meeting/saveDiscussionPresets', 91 | method: 'post', 92 | data: data 93 | }) 94 | } 95 | 96 | export const discussAndQuiz = (data: MeetingFlowItemReq) => { 97 | return request({ 98 | url: '/api/meeting/discussAndQuiz', 99 | method: 'post', 100 | data: data 101 | }) 102 | } 103 | 104 | export const getProcessingData = (meetingId: string, flowItemId: string) => { 105 | return request>({ 106 | url: '/api/meeting/getProcessingData?meetingId=' + meetingId + '&flowItemId=' + flowItemId, 107 | method: 'get' 108 | }) 109 | } 110 | 111 | export const getOutputData = (meetingId: string, flowItemId: string) => { 112 | return request>({ 113 | url: '/api/meeting/getOutputData?meetingId=' + meetingId + '&flowItemId=' + flowItemId, 114 | method: 'get' 115 | }) 116 | } 117 | -------------------------------------------------------------------------------- /src/pages/setting/components/SettingComp.vue: -------------------------------------------------------------------------------- 1 | 2 | 8 | 88 | 89 | 118 | 119 | 136 | 141 | -------------------------------------------------------------------------------- /src/pages/meeting-template/components/MeetingNode.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 95 | 96 | -------------------------------------------------------------------------------- /src/types/meeting.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 3 | * @version: 4 | * @Date: 2023-05-31 13:13:14 5 | * @LastEditTime: 2023-07-09 21:14:57 6 | */ 7 | 8 | import { TemplateNodeInfo } from './meeting-template'; 9 | 10 | export interface ThinkingTree { 11 | id: string; 12 | parentId?: string; 13 | question: string; 14 | answer: string; 15 | width: number; 16 | height: number; 17 | collapsed: boolean; 18 | children?: ThinkingTree[]; 19 | } 20 | 21 | export interface SimpleConversation { 22 | id: string, 23 | question: string, 24 | answer: string, 25 | } 26 | 27 | export interface Message { 28 | index: number, 29 | id: string, 30 | text: string 31 | member: Member, 32 | isSelf: boolean 33 | time: number 34 | } 35 | 36 | // 状态 37 | export enum MeetingStatus { 38 | IDLE = 'idle', 39 | RUNNING = 'running', 40 | DONE = 'done' 41 | } 42 | 43 | 44 | export interface Meeting { 45 | id: string; 46 | name: string; 47 | templateId: string; 48 | topicGoal: string; 49 | overview: string; 50 | conclusion: string; 51 | tokenCnt: number; 52 | createdBy: string; 53 | createdTime: number; 54 | } 55 | export interface Query { 56 | createdBy?: string; 57 | pageNum?: number; 58 | pageSize?: number; 59 | } 60 | 61 | export interface MeetingList { 62 | total: number; 63 | data: Meeting[]; 64 | } 65 | 66 | export interface NewMeeting { 67 | name: string; 68 | templateId: string; 69 | createdBy: string; 70 | } 71 | 72 | export interface FlowItem { 73 | nodeInfo: TemplateNodeInfo; 74 | upstream: string[]; 75 | status: string; 76 | } 77 | 78 | export interface NewMeetingReply { 79 | meetingId: string; 80 | meetingFlow: FlowItem[]; 81 | } 82 | 83 | export interface ProgressReply { 84 | meetingId: string; 85 | meetingName: string; 86 | nowStatus: string; 87 | nowFlowItem: FlowItem; 88 | nextFlowItem: FlowItem; 89 | progress: FlowItem[]; 90 | } 91 | 92 | export interface UpdateStatus { 93 | meetingId: string; 94 | flowItemId: string; 95 | } 96 | 97 | export interface MeetingFlowItemReq { 98 | meetingId: string, 99 | flowItemId: string, 100 | text: string 101 | } 102 | 103 | export interface Member { 104 | memberId: string 105 | memberName: string 106 | description: string 107 | color?: string 108 | } 109 | 110 | export interface ThinkingData { 111 | presets: ThinkingPresets 112 | thinking: ThinkingThinking 113 | summary: ThinkingSummary 114 | } 115 | 116 | export interface ThinkingPresets { 117 | meetingId: string 118 | flowItemId: string 119 | associationCharacters: Member 120 | quizCharacters: Member 121 | background: string 122 | curFlowItemName: string 123 | prologuePrompt: string 124 | quizPrompt: string 125 | quizRound: number 126 | quizNum: number 127 | summaryCharacters: Member 128 | summaryPrompt: string 129 | } 130 | 131 | export interface ThinkingThinking { 132 | conversationMap: Map 133 | thinkingTree: ThinkingTree 134 | } 135 | 136 | export interface ThinkingSummary { 137 | summaryText: string 138 | } 139 | 140 | export interface DiscussionData { 141 | presets: DiscussionPresets 142 | discussion: DiscussionDiscussion 143 | summary: DiscussionSummary 144 | } 145 | 146 | export interface DiscussionPresets { 147 | meetingId: string 148 | flowItemId: string 149 | background: string 150 | curFlowItemName: string 151 | memberList: Member[] 152 | prologuePrompt: string 153 | replyRound: number 154 | summaryCharacters: Member 155 | summaryPrompt: string 156 | } 157 | 158 | export interface DiscussionDiscussion { 159 | chatList: Message[] 160 | } 161 | 162 | export interface DiscussionSummary { 163 | summaryText: string 164 | } 165 | 166 | export interface ProcessingData { 167 | presets: ProcessingPresets 168 | output: string 169 | } 170 | 171 | export interface ProcessingPresets { 172 | meetingId: string 173 | flowItemId: string 174 | characters: Member 175 | background: string 176 | curFlowItemName: string 177 | processingPrompt: string 178 | } 179 | 180 | export interface InputPresets { 181 | meetingId: string 182 | flowItemId: string 183 | characters: Member 184 | curFlowItemName: string 185 | optimizationPrompt: string 186 | } 187 | 188 | export interface InputData { 189 | presets: InputPresets 190 | input: string 191 | output: string 192 | } 193 | 194 | export interface OutputPresets { 195 | meetingId: string 196 | flowItemId: string 197 | characters: Member 198 | curFlowItemName: string 199 | summaryPrompt: string 200 | } 201 | 202 | export interface OutputData { 203 | presets: OutputPresets 204 | output: string 205 | } -------------------------------------------------------------------------------- /src/components/Markdown/index.vue: -------------------------------------------------------------------------------- 1 | 90 | 91 | 115 | 116 | 198 | -------------------------------------------------------------------------------- /src/pages/meeting-template/components/PublicMeetingRepo.vue: -------------------------------------------------------------------------------- 1 | 7 | 56 | 57 | 108 | 109 | -------------------------------------------------------------------------------- /src/pages/meeting/components/OutputComp.vue: -------------------------------------------------------------------------------- 1 | 7 | 66 | 67 | 205 | 206 | 228 | -------------------------------------------------------------------------------- /src/pages/role-template/components/PublicRoleRepo.vue: -------------------------------------------------------------------------------- 1 | 7 | 96 | 97 | 165 | 166 | -------------------------------------------------------------------------------- /src/pages/setting/components/TempComp.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 55 | 167 | 168 | 254 | -------------------------------------------------------------------------------- /public/common.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 节点_数据合并 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/pages/meeting/components/ProcessingComp.vue: -------------------------------------------------------------------------------- 1 | 7 | 78 | 79 | 222 | 223 | 245 | -------------------------------------------------------------------------------- /src/pages/meeting/components/InputComp.vue: -------------------------------------------------------------------------------- 1 | 7 | 80 | 81 | 239 | 240 | -------------------------------------------------------------------------------- /src/pages/meeting-template/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 111 | 112 | 229 | 230 | 306 | 311 | -------------------------------------------------------------------------------- /src/pages/meeting/meeting.vue: -------------------------------------------------------------------------------- 1 | 7 | 120 | 121 | 324 | 325 | 384 | -------------------------------------------------------------------------------- /src/pages/meeting/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 183 | 184 | 320 | 321 | 412 | -------------------------------------------------------------------------------- /src/pages/role-template/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 168 | 169 | 341 | 342 | 424 | 425 | 447 | -------------------------------------------------------------------------------- /src/pages/meeting-template/components/TemplateDesign.vue: -------------------------------------------------------------------------------- 1 | 257 | 258 | 903 | 904 | 961 | 974 | --------------------------------------------------------------------------------