├── .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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/public/input.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
8 |
9 |
10 |
11 |
12 | GPT-Meeting
13 |
14 |
15 | Communicate with GPT.
16 |
17 |
18 |
19 |
27 | {{ title }}
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
78 |
79 |
136 |
--------------------------------------------------------------------------------
/public/evaluate.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
13 |
39 |
40 |
41 |
42 |
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 |
9 |
10 |
设置
11 |
12 |
13 |
17 |
21 |
25 |
26 |
27 |
31 |
35 |
39 |
43 |
47 |
51 |
55 |
56 |
57 |
58 |
65 |
66 |
67 |
74 |
75 |
76 |
81 | 更新
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
118 |
119 |
136 |
141 |
--------------------------------------------------------------------------------
/src/pages/meeting-template/components/MeetingNode.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
15 |
16 | {{ nodeName }}
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 | {{ description }}
28 |
29 |
30 |
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 |
92 |
93 |
105 |
110 |
111 | thinking...
112 |
113 |
114 |
115 |
116 |
198 |
--------------------------------------------------------------------------------
/src/pages/meeting-template/components/PublicMeetingRepo.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
28 |
29 |
37 |
38 |
43 |
44 |
{{ item.name }}
45 |
{{ item.description }}
46 |
47 | 下载次数: {{ item.starCount }}
48 | 创建人: 皮皮虾
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
108 |
109 |
--------------------------------------------------------------------------------
/src/pages/meeting/components/OutputComp.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 | Process Prompt
11 |
12 |
13 |
17 |
18 |
24 |
25 |
26 |
32 |
33 |
34 |
35 |
36 |
42 | 处理
43 |
44 |
45 |
46 | Output Data
47 |
48 |
49 |
53 |
54 |
55 |
61 | 完成
62 |
63 |
64 |
65 |
66 |
67 |
205 |
206 |
228 |
--------------------------------------------------------------------------------
/src/pages/role-template/components/PublicRoleRepo.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
29 |
30 |
38 |
39 |
44 |
45 |
{{ item.summary }}
46 |
{{ item.description }}
47 |
48 | Star: {{ item.starCount }}
49 | 创建人: 皮皮虾
50 |
51 |
52 |
53 |
54 |
55 |
56 |
63 |
67 |
71 |
75 |
76 |
77 | {{ detailItem.summary }}
78 |
79 |
80 | {{ detailItem.description }}
81 |
82 |
83 | {{ detailItem.example }}
84 |
85 |
86 |
87 |
93 |
94 |
95 |
96 |
97 |
165 |
166 |
--------------------------------------------------------------------------------
/src/pages/setting/components/TempComp.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ title }}
6 |
7 |
11 |
17 |
18 |
22 |
23 |
24 |
28 |
29 |
30 |
31 |
32 |
41 |
47 | 发送
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
167 |
168 |
254 |
--------------------------------------------------------------------------------
/public/common.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/pages/meeting/components/ProcessingComp.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 | Input Data
11 |
12 |
13 |
20 |
21 |
22 | Process Prompt
23 |
24 |
25 |
29 |
30 |
36 |
37 |
38 |
44 |
45 |
46 |
47 |
48 |
54 | 通用处理
55 |
56 |
57 |
58 | Output Data
59 |
60 |
61 |
65 |
66 |
67 |
73 | 完成
74 |
75 |
76 |
77 |
78 |
79 |
222 |
223 |
245 |
--------------------------------------------------------------------------------
/src/pages/meeting/components/InputComp.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
14 |
15 |
22 |
23 |
24 |
30 |
31 |
32 |
38 |
39 |
40 |
45 | 帮我优化
46 |
47 |
53 | 直接提交
54 |
55 |
61 | 没问题了,提交
62 |
63 |
64 |
68 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
239 |
240 |
--------------------------------------------------------------------------------
/src/pages/meeting-template/index.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 | 会议模版
13 |
14 |
15 | 定义会议的流程模版.
16 |
17 |
18 |
19 |
22 | 公共模版库
23 |
24 |
25 |
我的模版
26 |
30 |
31 |
32 |
33 |
34 |
35 |
42 |
43 |
44 |
48 |
52 | {{ item.name }}
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
67 |
68 |
76 |
77 | 绘制流程模版
78 |
79 |
80 |
87 |
88 |
89 |
90 |
91 |
92 | 收藏
93 |
94 | 知道了
95 |
96 |
97 |
98 | 不录了
99 |
100 |
104 | 录完了
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
229 |
230 |
306 |
311 |
--------------------------------------------------------------------------------
/src/pages/meeting/meeting.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 | GPT-Meeting
13 |
14 |
15 | {{ meetingName }}
16 |
17 |
18 |
19 |
20 |
25 |
30 |
31 |
35 |
36 | {{ item.nodeInfo.nodeName }}
37 |
38 |
39 | 开场: {{ item.nodeInfo.prologuePrompt }}
40 |
41 |
42 | 优化: {{ item.nodeInfo.optimizationPrompt }}
43 |
44 |
45 | 处理: {{ item.nodeInfo.processingPrompt }}
46 |
47 |
48 | 提问: {{ item.nodeInfo.quizPrompt }}
49 |
50 |
51 | 总结: {{ item.nodeInfo.summaryPrompt }}
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
65 |
66 |
71 |
76 | 开始
77 |
78 |
83 | 暂停
84 |
85 |
90 | 终止
91 |
92 |
98 | 下一步
99 |
100 |
101 |
102 |
103 |
104 |
105 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
324 |
325 |
384 |
--------------------------------------------------------------------------------
/src/pages/meeting/index.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 | Meeting
13 |
14 |
15 | Communicate with GPT.
16 |
17 |
18 |
22 | 创建会议
23 |
24 |
44 |
45 |
46 |
47 |
48 |
52 |
53 |
58 |
59 |
60 |
61 | Copy
62 |
63 |
68 |
69 |
70 |
71 | Download
72 |
73 |
74 |
78 | {{ curMeeting.name }}
79 |
80 |
83 | {{ curMeeting.id }}
84 |
85 |
86 | {{ formatTime(curMeeting.createdTime) }}
87 |
88 |
94 |
97 |
98 | 跳转
102 |
103 |
104 |
105 | 主题&目标
106 |
107 |
108 |
109 |
110 |
111 | 概要
112 |
113 |
114 |
115 |
116 |
117 | 最终结论
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
136 |
137 |
141 |
142 |
143 |
148 |
154 |
155 |
160 |
161 |
162 |
167 |
168 |
169 |
170 |
179 |
180 |
181 |
182 |
183 |
184 |
320 |
321 |
412 |
--------------------------------------------------------------------------------
/src/pages/role-template/index.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 | 角色模版
13 |
14 |
15 | 定义参与会议的角色.
16 |
17 |
18 |
19 |
22 | 公共模版库
23 |
24 |
25 |
我的模版
26 |
30 |
31 |
32 |
33 |
34 |
35 |
42 |
43 |
44 |
48 |
52 | {{ item.summary }}
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
68 |
69 |
70 |
76 |
77 |
78 |
79 |
82 |
89 |
94 |
98 |
99 |
100 |
101 |
102 |
105 |
110 |
111 |
114 |
119 |
120 |
121 |
125 |
128 |
133 |
134 |
137 |
141 |
142 |
143 |
144 |
145 |
146 |
165 |
166 |
167 |
168 |
169 |
341 |
342 |
424 |
425 |
447 |
--------------------------------------------------------------------------------
/src/pages/meeting-template/components/TemplateDesign.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
21 |
22 |
29 |
34 |
38 |
39 |
40 |
41 |
42 |
43 |
47 |
48 |
49 |
55 |
56 |
57 |
63 |
64 |
65 |
66 |
71 |
76 |
77 | {{ nodeInfo.nodeType }}
78 |
79 |
80 |
84 |
85 |
90 |
95 |
101 |
102 |
103 |
108 |
113 |
119 |
120 |
121 |
126 |
131 |
137 |
138 |
139 |
144 |
150 |
156 |
157 |
158 |
163 |
169 |
170 |
175 |
181 |
182 |
187 |
193 |
194 |
199 |
205 |
206 |
211 |
216 |
217 |
222 |
227 |
228 |
233 |
238 |
239 |
244 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
903 |
904 |
961 |
974 |
--------------------------------------------------------------------------------