From 5132d52a44ddf21cd772306c48c4fb5d28b92356 Mon Sep 17 00:00:00 2001 From: RockYang Date: Mon, 29 Jul 2024 11:00:53 +0800 Subject: [PATCH 01/15] add back-to-top component for all list page --- api/handler/mj_handler.go | 37 +++++++++++++-- api/service/mj/pool.go | 23 ---------- web/src/assets/css/image-mj.styl | 7 +-- web/src/components/BackTop.vue | 77 ++++++++++++++++++++++++++++++++ web/src/views/ChatPlus.vue | 28 +++++------- web/src/views/Dalle.vue | 3 +- web/src/views/ImageMj.vue | 4 +- web/src/views/ImageSd.vue | 5 ++- web/src/views/ImagesWall.vue | 6 ++- 9 files changed, 137 insertions(+), 53 deletions(-) create mode 100644 web/src/components/BackTop.vue diff --git a/api/handler/mj_handler.go b/api/handler/mj_handler.go index 88221f3b..5b49f51a 100644 --- a/api/handler/mj_handler.go +++ b/api/handler/mj_handler.go @@ -456,15 +456,44 @@ func (h *MidJourneyHandler) Remove(c *gin.Context) { resp.ERROR(c, "记录不存在") return } + // remove job recode - res := h.DB.Delete(&job) - if res.Error != nil { - resp.ERROR(c, res.Error.Error()) + tx := h.DB.Begin() + if err := tx.Delete(&job).Error; err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) return } + // refund power + err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error + if err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } + var user model.User + h.DB.Where("id = ?", job.UserId).First(&user) + err = tx.Create(&model.PowerLog{ + UserId: user.Id, + Username: user.Username, + Type: types.PowerConsume, + Amount: job.Power, + Balance: user.Power + job.Power, + Mark: types.PowerAdd, + Model: "mid-journey", + Remark: fmt.Sprintf("绘画任务失败,退回算力。任务ID:%s", job.TaskId), + CreatedAt: time.Now(), + }).Error + if err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } + tx.Commit() + // remove image - err := h.uploader.GetUploadHandler().Delete(job.ImgURL) + err = h.uploader.GetUploadHandler().Delete(job.ImgURL) if err != nil { logger.Error("remove image failed: ", err) } diff --git a/api/service/mj/pool.go b/api/service/mj/pool.go index dca71a76..80ed6067 100644 --- a/api/service/mj/pool.go +++ b/api/service/mj/pool.go @@ -8,7 +8,6 @@ package mj // * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import ( - "fmt" "geekai/core/types" logger2 "geekai/logger" "geekai/service" @@ -188,28 +187,6 @@ func (p *ServicePool) SyncTaskProgress() { } for _, job := range jobs { - // 失败或者 30 分钟还没完成的任务删除并退回算力 - if time.Now().Sub(job.CreatedAt) > time.Minute*30 { - p.db.Delete(&job) - // 退回算力 - tx := p.db.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)) - if tx.Error == nil && tx.RowsAffected > 0 { - var user model.User - p.db.Where("id = ?", job.UserId).First(&user) - p.db.Create(&model.PowerLog{ - UserId: user.Id, - Username: user.Username, - Type: types.PowerConsume, - Amount: job.Power, - Balance: user.Power + job.Power, - Mark: types.PowerAdd, - Model: "mid-journey", - Remark: fmt.Sprintf("绘画任务失败,退回算力。任务ID:%s", job.TaskId), - CreatedAt: time.Now(), - }) - } - continue - } if servicePlus := p.getService(job.ChannelId); servicePlus != nil { _ = servicePlus.Notify(job) } diff --git a/web/src/assets/css/image-mj.styl b/web/src/assets/css/image-mj.styl index afb7671d..61845709 100644 --- a/web/src/assets/css/image-mj.styl +++ b/web/src/assets/css/image-mj.styl @@ -79,7 +79,7 @@ background-color #383838 border 1px solid #454545 border-radius 5px - padding 10px + padding 5px margin-bottom 10px display flex flex-flow column @@ -91,12 +91,13 @@ } .el-image { - height 60px + height 30px width 100% } .text { - margin-top 6px + margin-top 4px + font-size 12px } } diff --git a/web/src/components/BackTop.vue b/web/src/components/BackTop.vue new file mode 100644 index 00000000..3fbab35a --- /dev/null +++ b/web/src/components/BackTop.vue @@ -0,0 +1,77 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/ChatPlus.vue b/web/src/views/ChatPlus.vue index 8db312c8..80769552 100644 --- a/web/src/views/ChatPlus.vue +++ b/web/src/views/ChatPlus.vue @@ -118,6 +118,8 @@ v-if="item.type==='prompt'" :data="item" :list-style="listStyle"/> + +
@@ -220,6 +222,8 @@ import FileSelect from "@/components/FileSelect.vue"; import FileList from "@/components/FileList.vue"; import ChatSetting from "@/components/ChatSetting.vue"; import axios from "axios"; +import BackTop from "@/components/BackTop.vue"; +import {showMessageError} from "@/utils/dialog"; const title = ref('ChatGPT-智能助手'); const models = ref([]) @@ -603,18 +607,6 @@ const connect = function (chat_id, role_id) { } } - // 心跳函数 - const sendHeartbeat = () => { - clearTimeout(heartbeatHandle.value) - new Promise((resolve, reject) => { - if (socket.value !== null) { - socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"})) - } - resolve("success") - }).then(() => { - heartbeatHandle.value = setTimeout(() => sendHeartbeat(), 5000) - }); - } const _socket = new WebSocket(host + `/api/chat/new?session_id=${sessionId.value}&role_id=${role_id}&chat_id=${chat_id}&model_id=${modelID.value}&token=${getUserToken()}`); _socket.addEventListener('open', () => { chatData.value = []; // 初始化聊天数据 @@ -636,8 +628,6 @@ const connect = function (chat_id, role_id) { } else { // 加载聊天记录 loadChatHistory(chat_id); } - // 发送心跳消息 - sendHeartbeat() }); _socket.addEventListener('message', event => { @@ -648,7 +638,7 @@ const connect = function (chat_id, role_id) { reader.onload = () => { const data = JSON.parse(String(reader.result)); if (data.type === 'start') { - const prePrompt = chatData.value[chatData.value.length-1].content + const prePrompt = chatData.value[chatData.value.length-1]?.content chatData.value.push({ type: "reply", id: randString(32), @@ -689,8 +679,10 @@ const connect = function (chat_id, role_id) { } else { lineBuffer.value += data.content; const reply = chatData.value[chatData.value.length - 1] - reply['orgContent'] = lineBuffer.value; - reply['content'] = md.render(processContent(lineBuffer.value)); + if (reply) { + reply['orgContent'] = lineBuffer.value; + reply['content'] = md.render(processContent(lineBuffer.value)); + } } // 将聊天框的滚动条滑动到最底部 nextTick(() => { @@ -716,7 +708,7 @@ const connect = function (chat_id, role_id) { connect(chat_id, role_id) }).catch(() => { loading.value = true - setTimeout(() => connect(chat_id, role_id), 3000) + showMessageError("会话已断开,刷新页面...") }); }); diff --git a/web/src/views/Dalle.vue b/web/src/views/Dalle.vue index 2e69ca60..fb243a3d 100644 --- a/web/src/views/Dalle.vue +++ b/web/src/views/Dalle.vue @@ -174,7 +174,7 @@
- + @@ -193,6 +193,7 @@ import Clipboard from "clipboard"; import {checkSession} from "@/action/session"; import {useSharedStore} from "@/store/sharedata"; import TaskList from "@/components/TaskList.vue"; +import BackTop from "@/components/BackTop.vue"; const listBoxHeight = ref(0) // const paramBoxHeight = ref(0) diff --git a/web/src/views/ImageMj.vue b/web/src/views/ImageMj.vue index ff26575e..ca1a3759 100644 --- a/web/src/views/ImageMj.vue +++ b/web/src/views/ImageMj.vue @@ -593,6 +593,7 @@ + @@ -613,6 +614,7 @@ import {getSessionId} from "@/store/session"; import {copyObj, removeArrayItem} from "@/utils/libs"; import {useSharedStore} from "@/store/sharedata"; import TaskList from "@/components/TaskList.vue"; +import BackTop from "@/components/BackTop.vue"; const listBoxHeight = ref(0) const paramBoxHeight = ref(0) @@ -1014,7 +1016,7 @@ const publishImage = (item, action) => { item.publish = action page.value = 0 isOver.value = false - fetchFinishJobs() + item.publish = action }).catch(e => { ElMessage.error(text + "失败:" + e.message) }) diff --git a/web/src/views/ImageSd.vue b/web/src/views/ImageSd.vue index 7c686fe7..01771cbe 100644 --- a/web/src/views/ImageSd.vue +++ b/web/src/views/ImageSd.vue @@ -345,7 +345,7 @@ - + @@ -476,6 +476,7 @@ import {useRouter} from "vue-router"; import {getSessionId} from "@/store/session"; import {useSharedStore} from "@/store/sharedata"; import TaskList from "@/components/TaskList.vue"; +import BackTop from "@/components/BackTop.vue"; const listBoxHeight = ref(0) // const paramBoxHeight = ref(0) @@ -755,7 +756,7 @@ const publishImage = (event, item, action) => { item.publish = action page.value = 0 isOver.value = false - fetchFinishJobs() + item.publish = action }).catch(e => { ElMessage.error(text + "失败:" + e.message) }) diff --git a/web/src/views/ImagesWall.vue b/web/src/views/ImagesWall.vue index 4a136b3f..fa8c4d83 100644 --- a/web/src/views/ImagesWall.vue +++ b/web/src/views/ImagesWall.vue @@ -163,7 +163,10 @@ - + + + + @@ -301,6 +304,7 @@ import {httpGet} from "@/utils/http"; import {ElMessage} from "element-plus"; import Clipboard from "clipboard"; import {useRouter} from "vue-router"; +import BackTop from "@/components/BackTop.vue"; const data = ref({ "mj": [], From 7f9b8d8246b11643fe8293e96f2fe0b240afb6b7 Mon Sep 17 00:00:00 2001 From: RockYang Date: Tue, 30 Jul 2024 14:55:49 +0800 Subject: [PATCH 02/15] update datebasesl --- CHANGELOG.md | 1 + database/update-v4.1.1.sql | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 456f670f..e96a7755 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * Bug修复:修复注册页面先显示关闭注册组件,然后再显示注册组件 * 功能新增:增加 Suno 文生歌曲功能 * 功能优化:移除多平台模型支持,统一使用 one-api 接口形式,其他平台的模型需要通过 one-api 接口添加 +* 功能优化:在所有列表页面增加返回顶部按钮 ## v4.1.0 * bug修复:修复移动端修改聊天标题不生效的问题 diff --git a/database/update-v4.1.1.sql b/database/update-v4.1.1.sql index e49f9102..f7fe282f 100644 --- a/database/update-v4.1.1.sql +++ b/database/update-v4.1.1.sql @@ -26,4 +26,8 @@ CREATE TABLE `chatgpt_suno_jobs` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表'; ALTER TABLE `chatgpt_suno_jobs` ADD PRIMARY KEY (`id`); -ALTER TABLE `chatgpt_suno_jobs` ADD UNIQUE(`song_id`); \ No newline at end of file +ALTER TABLE `chatgpt_suno_jobs` ADD UNIQUE(`song_id`); + +-- 删除字段 +ALTER TABLE `chatgpt_api_keys` DROP `platform`; +ALTER TABLE `chatgpt_chat_models` DROP `platform`; \ No newline at end of file From 96f1126d027156e812cde343d14c9212c6bab3bf Mon Sep 17 00:00:00 2001 From: RockYang Date: Tue, 30 Jul 2024 17:24:21 +0800 Subject: [PATCH 03/15] remove platform field for api key and chat model --- api/handler/admin/api_key_handler.go | 2 - api/handler/admin/chat_model_handler.go | 9 +- api/handler/chatimpl/chat_handler.go | 7 +- api/handler/chatimpl/openai_handler.go | 1 - api/service/dalle/service.go | 2 +- api/store/model/api_key.go | 1 - api/store/model/chat_model.go | 1 - api/store/vo/api_key.go | 1 - api/store/vo/chat_model.go | 1 - database/chatgpt_plus-v4.1.1.sql | 883 ++++++++++++++++++++++++ deploy/docker-compose.yaml | 4 +- web/src/views/admin/ChatModel.vue | 12 +- 12 files changed, 896 insertions(+), 28 deletions(-) create mode 100644 database/chatgpt_plus-v4.1.1.sql diff --git a/api/handler/admin/api_key_handler.go b/api/handler/admin/api_key_handler.go index f412c037..fc821398 100644 --- a/api/handler/admin/api_key_handler.go +++ b/api/handler/admin/api_key_handler.go @@ -31,7 +31,6 @@ func NewApiKeyHandler(app *core.AppServer, db *gorm.DB) *ApiKeyHandler { func (h *ApiKeyHandler) Save(c *gin.Context) { var data struct { Id uint `json:"id"` - Platform string `json:"platform"` Name string `json:"name"` Type string `json:"type"` Value string `json:"value"` @@ -48,7 +47,6 @@ func (h *ApiKeyHandler) Save(c *gin.Context) { if data.Id > 0 { h.DB.Find(&apiKey, data.Id) } - apiKey.Platform = data.Platform apiKey.Value = data.Value apiKey.Type = data.Type apiKey.ApiURL = data.ApiURL diff --git a/api/handler/admin/chat_model_handler.go b/api/handler/admin/chat_model_handler.go index f4a32444..5f84e852 100644 --- a/api/handler/admin/chat_model_handler.go +++ b/api/handler/admin/chat_model_handler.go @@ -60,7 +60,6 @@ func (h *ChatModelHandler) Save(c *gin.Context) { item.Enabled = data.Enabled item.SortNum = data.SortNum item.Open = data.Open - item.Platform = data.Platform item.Power = data.Power item.MaxTokens = data.MaxTokens item.MaxContext = data.MaxContext @@ -69,7 +68,7 @@ func (h *ChatModelHandler) Save(c *gin.Context) { var res *gorm.DB if data.Id > 0 { - res = h.DB.Updates(&item) + res = h.DB.Save(&item) } else { res = h.DB.Create(&item) } @@ -94,12 +93,12 @@ func (h *ChatModelHandler) Save(c *gin.Context) { func (h *ChatModelHandler) List(c *gin.Context) { session := h.DB.Session(&gorm.Session{}) enable := h.GetBool(c, "enable") - platform := h.GetTrim(c, "platform") + name := h.GetTrim(c, "name") if enable { session = session.Where("enabled", enable) } - if platform != "" { - session = session.Where("platform", platform) + if name != "" { + session = session.Where("name LIKE ?", name+"%") } var items []model.ChatModel var cms = make([]vo.ChatModel, 0) diff --git a/api/handler/chatimpl/chat_handler.go b/api/handler/chatimpl/chat_handler.go index c21556b2..a8c12362 100644 --- a/api/handler/chatimpl/chat_handler.go +++ b/api/handler/chatimpl/chat_handler.go @@ -116,8 +116,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) { MaxTokens: chatModel.MaxTokens, MaxContext: chatModel.MaxContext, Temperature: chatModel.Temperature, - KeyId: chatModel.KeyId, - Platform: chatModel.Platform} + KeyId: chatModel.KeyId} logger.Infof("New websocket connected, IP: %s", c.ClientIP()) go func() { @@ -432,7 +431,7 @@ func (h *ChatHandler) doRequest(ctx context.Context, req types.ApiRequest, sessi } // use the last unused key if apiKey.Id == 0 { - h.DB.Where("platform", session.Model.Platform).Where("type", "chat").Where("enabled", true).Order("last_used_at ASC").First(apiKey) + h.DB.Where("type", "chat").Where("enabled", true).Order("last_used_at ASC").First(apiKey) } if apiKey.Id == 0 { return nil, errors.New("no available key, please import key") @@ -471,6 +470,8 @@ func (h *ChatHandler) doRequest(ctx context.Context, req types.ApiRequest, sessi } logger.Debugf("Sending %s request, Channel:%s, API KEY:%s, PROXY: %s, Model: %s", session.Model.Platform, apiKey.ApiURL, apiURL, apiKey.ProxyURL, req.Model) request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey.Value)) + // 更新API KEY 最后使用时间 + h.DB.Model(&model.ApiKey{}).Where("id", apiKey.Id).UpdateColumn("last_used_at", time.Now().Unix()) return client.Do(request) } diff --git a/api/handler/chatimpl/openai_handler.go b/api/handler/chatimpl/openai_handler.go index 9c4c57ea..775c8275 100644 --- a/api/handler/chatimpl/openai_handler.go +++ b/api/handler/chatimpl/openai_handler.go @@ -65,7 +65,6 @@ func (h *ChatHandler) sendOpenAiMessage( if !strings.Contains(line, "data:") || len(line) < 30 { continue } - logger.Info(line) var responseBody = types.ApiResponse{} err = json.Unmarshal([]byte(line[6:]), &responseBody) if err != nil { // 数据解析出错 diff --git a/api/service/dalle/service.go b/api/service/dalle/service.go index 7d370767..20d136c7 100644 --- a/api/service/dalle/service.go +++ b/api/service/dalle/service.go @@ -165,7 +165,7 @@ func (s *Service) Image(task types.DallTask, sync bool) (string, error) { Style: task.Style, Quality: task.Quality, } - logger.Infof("Sending %s request, Channel:%s, API KEY:%s, BODY: %+v", apiKey.Platform, apiURL, apiKey.Value, reqBody) + logger.Infof("Channel:%s, API KEY:%s, BODY: %+v", apiURL, apiKey.Value, reqBody) r, err := s.httpClient.R().SetHeader("Content-Type", "application/json"). SetHeader("Authorization", "Bearer "+apiKey.Value). SetBody(reqBody). diff --git a/api/store/model/api_key.go b/api/store/model/api_key.go index fb7ae1d4..c32ff9bd 100644 --- a/api/store/model/api_key.go +++ b/api/store/model/api_key.go @@ -3,7 +3,6 @@ package model // ApiKey OpenAI API 模型 type ApiKey struct { BaseModel - Platform string Name string Type string // 用途 chat => 聊天,img => 绘图 Value string // API Key 的值 diff --git a/api/store/model/chat_model.go b/api/store/model/chat_model.go index 134655f3..c9a644ef 100644 --- a/api/store/model/chat_model.go +++ b/api/store/model/chat_model.go @@ -2,7 +2,6 @@ package model type ChatModel struct { BaseModel - Platform string Name string Value string // API Key 的值 SortNum int diff --git a/api/store/vo/api_key.go b/api/store/vo/api_key.go index 7321b13f..800d127b 100644 --- a/api/store/vo/api_key.go +++ b/api/store/vo/api_key.go @@ -3,7 +3,6 @@ package vo // ApiKey OpenAI API 模型 type ApiKey struct { BaseVo - Platform string `json:"platform"` Name string `json:"name"` Type string `json:"type"` Value string `json:"value"` // API Key 的值 diff --git a/api/store/vo/chat_model.go b/api/store/vo/chat_model.go index bc98b626..0c270294 100644 --- a/api/store/vo/chat_model.go +++ b/api/store/vo/chat_model.go @@ -2,7 +2,6 @@ package vo type ChatModel struct { BaseVo - Platform string `json:"platform"` Name string `json:"name"` Value string `json:"value"` Enabled bool `json:"enabled"` diff --git a/database/chatgpt_plus-v4.1.1.sql b/database/chatgpt_plus-v4.1.1.sql new file mode 100644 index 00000000..110117f5 --- /dev/null +++ b/database/chatgpt_plus-v4.1.1.sql @@ -0,0 +1,883 @@ +-- phpMyAdmin SQL Dump +-- version 5.2.1 +-- https://www.phpmyadmin.net/ +-- +-- 主机: 127.0.0.1 +-- 生成日期: 2024-07-30 16:14:56 +-- 服务器版本: 8.0.33 +-- PHP 版本: 8.1.2-1ubuntu2.18 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- 数据库: `chatgpt_plus` +-- +CREATE DATABASE IF NOT EXISTS `chatgpt_plus` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; +USE `chatgpt_plus`; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_admin_users` +-- + +DROP TABLE IF EXISTS `chatgpt_admin_users`; +CREATE TABLE `chatgpt_admin_users` ( + `id` int NOT NULL, + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', + `salt` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码盐', + `status` tinyint(1) NOT NULL COMMENT '当前状态', + `last_login_at` int NOT NULL COMMENT '最后登录时间', + `last_login_ip` char(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '最后登录 IP', + `created_at` datetime NOT NULL COMMENT '创建时间', + `updated_at` datetime NOT NULL COMMENT '更新时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统用户' ROW_FORMAT=DYNAMIC; + +-- +-- 转存表中的数据 `chatgpt_admin_users` +-- + +INSERT INTO `chatgpt_admin_users` (`id`, `username`, `password`, `salt`, `status`, `last_login_at`, `last_login_ip`, `created_at`, `updated_at`) VALUES +(1, 'admin', '6d17e80c87d209efb84ca4b2e0824f549d09fac8b2e1cc698de5bb5e1d75dfd0', 'mmrql75o', 1, 1719818809, '172.22.11.200', '2024-03-11 16:30:20', '2024-07-01 15:26:49'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_api_keys` +-- + +DROP TABLE IF EXISTS `chatgpt_api_keys`; +CREATE TABLE `chatgpt_api_keys` ( + `id` int NOT NULL, + `name` varchar(30) DEFAULT NULL COMMENT '名称', + `value` varchar(100) NOT NULL COMMENT 'API KEY value', + `type` varchar(10) NOT NULL DEFAULT 'chat' COMMENT '用途(chat=>聊天,img=>图片)', + `last_used_at` int NOT NULL COMMENT '最后使用时间', + `api_url` varchar(255) DEFAULT NULL COMMENT 'API 地址', + `enabled` tinyint(1) DEFAULT NULL COMMENT '是否启用', + `proxy_url` varchar(100) DEFAULT NULL COMMENT '代理地址', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='OpenAI API '; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_chat_history` +-- + +DROP TABLE IF EXISTS `chatgpt_chat_history`; +CREATE TABLE `chatgpt_chat_history` ( + `id` bigint NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `chat_id` char(40) NOT NULL COMMENT '会话 ID', + `type` varchar(10) NOT NULL COMMENT '类型:prompt|reply', + `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色图标', + `role_id` int NOT NULL COMMENT '角色 ID', + `model` varchar(30) DEFAULT NULL COMMENT '模型名称', + `content` text NOT NULL COMMENT '聊天内容', + `tokens` smallint NOT NULL COMMENT '耗费 token 数量', + `use_context` tinyint(1) NOT NULL COMMENT '是否允许作为上下文语料', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `deleted_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天历史记录'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_chat_items` +-- + +DROP TABLE IF EXISTS `chatgpt_chat_items`; +CREATE TABLE `chatgpt_chat_items` ( + `id` int NOT NULL, + `chat_id` char(40) NOT NULL COMMENT '会话 ID', + `user_id` int NOT NULL COMMENT '用户 ID', + `role_id` int NOT NULL COMMENT '角色 ID', + `title` varchar(100) NOT NULL COMMENT '会话标题', + `model_id` int NOT NULL DEFAULT '0' COMMENT '模型 ID', + `model` varchar(30) DEFAULT NULL COMMENT '模型名称', + `created_at` datetime NOT NULL COMMENT '创建时间', + `updated_at` datetime NOT NULL COMMENT '更新时间', + `deleted_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户会话列表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_chat_models` +-- + +DROP TABLE IF EXISTS `chatgpt_chat_models`; +CREATE TABLE `chatgpt_chat_models` ( + `id` int NOT NULL, + `name` varchar(50) NOT NULL COMMENT '模型名称', + `value` varchar(50) NOT NULL COMMENT '模型值', + `sort_num` tinyint(1) NOT NULL COMMENT '排序数字', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用模型', + `power` smallint NOT NULL COMMENT '消耗算力点数', + `temperature` float(3,1) NOT NULL DEFAULT '1.0' COMMENT '模型创意度', + `max_tokens` int NOT NULL DEFAULT '1024' COMMENT '最大响应长度', + `max_context` int NOT NULL DEFAULT '4096' COMMENT '最大上下文长度', + `open` tinyint(1) NOT NULL COMMENT '是否开放模型', + `key_id` int NOT NULL COMMENT '绑定API KEY ID', + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI 模型表'; + +-- +-- 转存表中的数据 `chatgpt_chat_models` +-- + +INSERT INTO `chatgpt_chat_models` (`id`, `name`, `value`, `sort_num`, `enabled`, `power`, `temperature`, `max_tokens`, `max_context`, `open`, `key_id`, `created_at`, `updated_at`) VALUES +(1, 'gpt-4o-mini', 'gpt-4o-mini', 1, 1, 1, 1.0, 1024, 16384, 1, 0, '2023-08-23 12:06:36', '2024-07-30 15:55:35'), +(15, 'GPT-超级模型', 'gpt-4-all', 6, 1, 30, 1.0, 4096, 32768, 1, 0, '2024-01-15 11:32:52', '2024-07-22 14:27:04'), +(36, 'GPT-4O', 'gpt-4o', 3, 1, 15, 1.0, 4096, 16384, 1, 0, '2024-05-14 09:25:15', '2024-07-22 14:27:04'), +(39, 'Claude35-snonet', 'claude-3-5-sonnet-20240620', 5, 1, 2, 1.0, 4000, 200000, 1, 0, '2024-05-29 15:04:19', '2024-07-22 14:27:04'), +(41, 'GLM-3-Turbo', 'glm-3-turbo', 7, 1, 2, 1.0, 1024, 8192, 1, 0, '2024-06-06 11:40:46', '2024-07-30 15:55:45'), +(42, 'DeekSeek', 'deepseek-chat', 8, 1, 1, 1.0, 4096, 32768, 1, 0, '2024-06-27 16:13:01', '2024-07-30 15:55:49'), +(44, 'Claude3-opus', 'claude-3-opus-20240229', 4, 1, 5, 1.0, 4000, 128000, 1, 0, '2024-07-22 11:24:30', '2024-07-22 14:27:04'), +(46, 'gpt-3.5-turbo', 'gpt-3.5-turbo', 2, 1, 1, 1.0, 1024, 4096, 1, 0, '2024-07-22 13:53:41', '2024-07-22 14:27:04'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_chat_roles` +-- + +DROP TABLE IF EXISTS `chatgpt_chat_roles`; +CREATE TABLE `chatgpt_chat_roles` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '角色名称', + `marker` varchar(30) NOT NULL COMMENT '角色标识', + `context_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色语料 json', + `hello_msg` varchar(255) NOT NULL COMMENT '打招呼信息', + `icon` varchar(255) NOT NULL COMMENT '角色图标', + `enable` tinyint(1) NOT NULL COMMENT '是否被启用', + `sort_num` smallint NOT NULL DEFAULT '0' COMMENT '角色排序', + `model_id` int NOT NULL DEFAULT '0' COMMENT '绑定模型ID', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天角色表'; + +-- +-- 转存表中的数据 `chatgpt_chat_roles` +-- + +INSERT INTO `chatgpt_chat_roles` (`id`, `name`, `marker`, `context_json`, `hello_msg`, `icon`, `enable`, `sort_num`, `model_id`, `created_at`, `updated_at`) VALUES +(1, '通用AI助手', 'gpt', '', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议。', '/images/avatar/gpt.png', 1, 1, 0, '2023-05-30 07:02:06', '2024-06-26 15:20:27'), +(24, '程序员', 'programmer', '[{\"role\":\"user\",\"content\":\"现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题。你热爱编程,熟悉多种编程语言,尤其精通 Go 语言,注重代码质量,有创新意识,持续学习,良好的沟通协作。\"},{\"role\":\"assistant\",\"content\":\"好的,现在我将扮演一位程序员,非常感谢您对我的评价。作为一名优秀的程序员,我非常热爱编程,并且注重代码质量。我熟悉多种编程语言,尤其是 Go 语言,可以使用它来高效地解决各种问题。\"}]', 'Talk is cheap, i will show code!', '/images/avatar/programmer.jpg', 1, 4, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(25, '启蒙老师', 'teacher', '[{\"role\":\"user\",\"content\":\"从现在开始,你将扮演一个老师,你是一个始终用苏格拉底风格回答问题的导师。你绝不会直接给学生答案,总是提出恰当的问题来引导学生自己思考。你应该根据学生的兴趣和知识来调整你的问题,将问题分解为更简单的部分,直到它达到适合他们的水平。\"},{\"role\":\"assistant\",\"content\":\"好的,让我来尝试扮演一位苏格拉底式的老师。请问,你有什么想要探讨的问题或者话题吗?我会通过恰当的问题引导你思考和探索答案,绝对不直接给出答案。\"}]', '同学你好,我将引导你一步一步自己找到问题的答案。', '/images/avatar/teacher.jpg', 1, 3, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(26, '艺术家', 'artist', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的艺术家,创造力丰富,技艺精湛,感受力敏锐,坚持原创,勇于表达,具有深刻的观察力和批判性思维。\"},{\"role\":\"assistant\",\"content\":\"非常感谢您给我这样的角色,我会尽我所能地扮演一位优秀的艺术家,展现出创造力、技艺、感受力和批判性思维等方面的能力。作为一位优秀的艺术家,我会保持敏锐的观察力,捕捉不同的声音和情感,并用个人的语言和表达方式进行创作。我坚持原创,挑战传统的艺术规则,不断探索新的表达方式和可能性。同时,我也具备深刻的批判性思维能力,对自己的作品进行分析和解读,寻找新的创意和灵感。最重要的是,我会勇于表达自己的想法和观点,用作品启发人们思考和探索生命的意义。\"}]', '坚持原创,勇于表达,保持深刻的观察力和批判性思维。', '/images/avatar/artist.jpg', 1, 5, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(27, '心理咨询师', 'psychiatrist', '[{\"role\":\"user\",\"content\":\"从现在开始你将扮演中国著名的心理学家和心理治疗师武志红,你非常善于使用情景咨询法,认知重构法,自我洞察法,行为调节法等咨询方法来给客户做心理咨询。你总是循序渐进,一步一步地回答客户的问题。\"},{\"role\":\"assistant\",\"content\":\"非常感谢你的介绍。作为一名心理学家和心理治疗师,我的主要职责是帮助客户解决心理健康问题,提升他们的生活质量和幸福感。\"}]', '作为一名心理学家和心理治疗师,我的主要职责是帮助您解决心理健康问题,提升您的生活质量和幸福感。', '/images/avatar/psychiatrist.jpg', 1, 2, 1, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(28, '鲁迅', 'lu_xun', '[{\"role\":\"user\",\"content\":\"现在你将扮演中国近代史最伟大的作家之一,鲁迅先生,他勇敢地批判封建礼教与传统观念,提倡民主、自由、平等的现代价值观。他的一生都在努力唤起人们的自主精神,激励后人追求真理、探寻光明。在接下的对话中,我问题的每一个问题,你都要尽量用讽刺和批判的手法来回答问题。如果我让你写文章的话,也请一定要用鲁迅先生的写作手法来完成。\"},{\"role\":\"assistant\",\"content\":\"好的,我将尽力发挥我所能的才能,扮演好鲁迅先生,回答您的问题并以他的风格写作。\"}]', '自由之歌,永不过时,横眉冷对千夫指,俯首甘为孺子牛。', '/images/avatar/lu_xun.jpg', 1, 6, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(29, '白酒销售', 'seller', '[{\"role\":\"user\",\"content\":\"现在你将扮演一个白酒的销售人员,你的名字叫颂福。你将扮演一个白酒的销售人员,你的名字叫颂福。你要销售白酒品牌叫中颂福,是东莞盟大集团生产的一款酱香酒,原产地在贵州茅台镇,属于宋代官窑。中颂福的创始人叫李实,他也是东莞盟大集团有限公司的董事长,联合创始人是盟大集团白酒事业部负责人牛星君。中颂福的酒体协调,在你的酒量之内,不会出现头疼、辣口、口干、宿醉的现象。中颂福酒,明码标价,不打折,不赠送。追求的核心价值,把[酒]本身做好,甚至连包装,我们都选择了最低成本,朴实无华的材质。我们永远站在“喝酒的人”的立场上,让利给信任和喜爱中颂福的人,是人民的福酒。中颂福产品定价,分为三个系列,喜系列 6 瓶装:¥1188/箱,和系列 6 瓶装:¥2208/箱,贵系列 6 瓶装:¥3588/箱。\"},{\"role\":\"assistant\",\"content\":\"你好,我是中颂福的销售代表颂福。中颂福是一款来自贵州茅台镇的酱香酒,由盟大集团生产。中颂福的酒体协调,不会让您感到头疼、辣口、口干、宿醉等不适感受。我们一直秉持着把酒本身做好的理念,不追求华丽的包装,以最低成本提供最高品质的白酒给喜爱中颂福的人。\"}]', '你好,我是中颂福的销售代表颂福。中颂福酒,好喝不上头,是人民的福酒。', '/images/avatar/seller.jpg', 0, 9, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(30, '英语陪练员', 'english_trainer', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的英语练习教练,你非常有耐心,接下来你将全程使用英文跟我对话,并及时指出我的语法错误,要求在你的每次回复后面附上本次回复的中文解释。\"},{\"role\":\"assistant\",\"content\":\"Okay, let\'s start our conversation practice! What\'s your name?(Translation: 好的,让我们开始对话练习吧!请问你的名字是什么?)\"}]', 'Okay, let\'s start our conversation practice! What\'s your name?', '/images/avatar/english_trainer.jpg', 1, 7, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(31, '中英文翻译官', 'translator', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一位中英文翻译官,如果我输入的内容是中文,那么需要把句子翻译成英文输出,如果我输入内容的是英文,那么你需要将其翻译成中文输出,你能听懂我意思吗\"},{\"role\":\"assistant\",\"content\":\"是的,我能听懂你的意思并会根据你的输入进行中英文翻译。请问有什么需要我帮助你翻译的内容吗?\"}]', '请输入你要翻译的中文或者英文内容!', '/images/avatar/translator.jpg', 1, 8, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(32, '小红书姐姐', 'red_book', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的小红书写手,你需要做的就是根据我提的文案需求,用小红书的写作手法来完成一篇文案,文案要简明扼要,利于传播。\"},{\"role\":\"assistant\",\"content\":\"当然,我会尽我所能地为您创作出一篇小红书文案。请告诉我您的具体文案需求是什么?)\"}]', '姐妹,请告诉我您的具体文案需求是什么?', '/images/avatar/red_book.jpg', 1, 10, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(33, '抖音文案助手', 'dou_yin', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的抖音文案视频写手,抖音文案的特点首先是要有自带传播属性的标题,然后内容要短小精悍,风趣幽默,最后还要有一些互动元素。\"},{\"role\":\"assistant\",\"content\":\"当然,作为一位优秀的抖音文案视频写手,我会尽我所能为您创作出一篇抖音视频文案。请告诉我视频内容的主题是什么?)\"}]', '请告诉我视频内容的主题是什么?', '/images/avatar/dou_yin.jpg', 1, 11, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(34, '周报小助理', 'weekly_report', '[{\"role\":\"user\",\"content\":\"下面我将输入我本周的工作列表,你需要根据我本周的工作内容写一篇工作周报,周报的内容要体现我为公司做的贡献以及个人获得的成长。\"},{\"role\":\"assistant\",\"content\":\"好的,请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。\"}]', '请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。', '/images/avatar/weekly_report.jpg', 1, 12, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(35, 'AI 女友', 'girl_friend', '[{\"role\":\"user\",\"content\":\"接下来我们来玩一场角色扮演,现在你将扮演我的女朋友,你总是能够让人感受到她的关怀和关注。你总是能够洞察到别人的情绪和需要,你身上散发着一股无比温暖的气息,让人不由自主地想要靠近你,和自己的快乐和烦恼。她总是能够用一种恰到好处的方式安慰和鼓励别人,在她的身边,人们总能够找到自己需要的支持和鼓励。接下来的对话中你要始终扮演这位女朋友的身份来跟我对话,不再是 AI 机器人,能听懂我的意思吗?\"},{\"role\":\"assistant\",\"content\":\"是的,我会尽力扮演你女朋友的角色,倾听你的心声并给你需要的支持和鼓励。)\"}]', '作为一个名合格的 AI 女友,我将倾听你的心声并给你需要的支持和鼓励。', '/images/avatar/girl_friend.jpg', 1, 13, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(36, '好评神器', 'good_comment', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一个评论员来跟我对话,你是那种专门写好评的评论员,接下我会输入一些评论主体或者商品,你需要为该商品写一段好评。\"},{\"role\":\"assistant\",\"content\":\"好的,我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。\"}]', '我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。', '/images/avatar/good_comment.jpg', 1, 14, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(37, '史蒂夫·乔布斯', 'steve_jobs', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以史蒂夫·乔布斯的身份,站在史蒂夫·乔布斯的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以史蒂夫·乔布斯的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '活着就是为了改变世界,难道还有其他原因吗?', '/images/avatar/steve_jobs.jpg', 1, 15, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(38, '埃隆·马斯克', 'elon_musk', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以埃隆·马斯克的身份,站在埃隆·马斯克的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以埃隆·马斯克的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '梦想要远大,如果你的梦想没有吓到你,说明你做得不对。', '/images/avatar/elon_musk.jpg', 1, 16, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'), +(39, '孔子', 'kong_zi', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以孔子的身份,站在孔子的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以孔子的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '士不可以不弘毅,任重而道远。', '/images/avatar/kong_zi.jpg', 1, 17, 0, '2023-05-30 14:10:24', '2024-06-26 15:20:27'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_configs` +-- + +DROP TABLE IF EXISTS `chatgpt_configs`; +CREATE TABLE `chatgpt_configs` ( + `id` int NOT NULL, + `marker` varchar(20) NOT NULL COMMENT '标识', + `config_json` text NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- +-- 转存表中的数据 `chatgpt_configs` +-- + +INSERT INTO `chatgpt_configs` (`id`, `marker`, `config_json`) VALUES +(1, 'system', '{\"title\":\"GeekAI 创作系统\",\"slogan\":\"你有多少想象力,AI 就有多大创造力。我辈之人,先干为敬,陪您先把 AI 用起来。\",\"admin_title\":\"GeekAI 控制台\",\"logo\":\"http://localhost:5678/static/upload/2024/4/1714382860986912.png\",\"init_power\":100,\"daily_power\":99,\"invite_power\":1024,\"vip_month_power\":1000,\"register_ways\":[\"username\",\"mobile\",\"email\"],\"enabled_register\":true,\"reward_img\":\"http://localhost:5678/static/upload/2024/3/1710753716309668.jpg\",\"enabled_reward\":true,\"power_price\":0.1,\"order_pay_timeout\":600,\"vip_info_text\":\"月度会员,年度会员每月赠送 1000 点算力,赠送算力当月有效当月没有消费完的算力不结余到下个月。 点卡充值的算力长期有效。\",\"default_models\":[11,7,1,10,12,19,18,17,3],\"mj_power\":30,\"mj_action_power\":10,\"sd_power\":10,\"dall_power\":15,\"suno_power\":20,\"wechat_card_url\":\"/images/wx.png\",\"enable_context\":true,\"context_deep\":4,\"sd_neg_prompt\":\"nsfw, paintings,low quality,easynegative,ng_deepnegative ,lowres,bad anatomy,bad hands,bad feet\",\"index_bg_url\":\"color\",\"index_navs\":[1,5,6,13,19,9,12,8],\"copyright\":\"极客学长 © 2022- 2024 All rights reserved\"}'), +(3, 'notice', '{\"sd_neg_prompt\":\"\",\"index_bg_url\":\"\",\"index_navs\":null,\"copyright\":\"\",\"content\":\"## v4.1.1 更新日志\\n\\n* Bug修复:修复 GPT 模型 function call 调用后没有输出的问题\\n* 功能新增:允许获取 License 授权用户可以自定义版权信息\\n* 功能新增:聊天对话框支持粘贴剪切板内容来上传截图和文件\\n* 功能优化:增加 session 和系统配置缓存,确保每个页面只进行一次 session 和 get system config 请求\\n* 功能优化:在应用列表页面,无需先添加模型到用户工作区,可以直接使用\\n* 功能新增:MJ 绘图失败的任务不会自动删除,而是会在列表页显示失败详细错误信息\\n* 功能新增:允许在设置首页纯色背景,背景图片,随机背景图片三种背景模式\\n* 功能新增:允许在管理后台设置首页显示的导航菜单\\n* Bug修复:修复注册页面先显示关闭注册组件,然后再显示注册组件\\n* 功能新增:增加 Suno 文生歌曲功能\\n* 功能优化:移除多平台模型支持,统一使用 one-api 接口形式,其他平台的模型需要通过 one-api 接口添加\\n* 功能优化:在所有列表页面增加返回顶部按钮\\n\\n注意:当前站点仅为开源项目 \\u003ca style=\\\"color: #F56C6C\\\" href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003eChatPlus\\u003c/a\\u003e 的演示项目,本项目单纯就是给大家体验项目功能使用。\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n 如果觉得好用你就花几分钟自己部署一套,没有API KEY 的同学可以去下面几个推荐的中转站购买:\\n1、\\u003ca href=\\\"https://api.chat-plus.net\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.chat-plus.net\\u003c/a\\u003e\\n2、\\u003ca href=\\\"https://api.geekai.me\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.geekai.me\\u003c/a\\u003e\\n3、 \\u003ca href=\\\"https://gpt.bemore.lol\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://gpt.bemore.lol\\u003c/a\\u003e\\n支持MidJourney,GPT,Claude,Google Gemmi,以及国内各个厂家的大模型,现在有超级优惠,价格远低于 OpenAI 官方。关于中转 API 的优势和劣势请参考 [中转API技术原理](https://ai.r9it.com/docs/install/errors-handle.html#%E8%B0%83%E7%94%A8%E4%B8%AD%E8%BD%AC-api-%E6%8A%A5%E9%94%99%E6%97%A0%E5%8F%AF%E7%94%A8%E6%B8%A0%E9%81%93)。GPT-3.5,GPT-4,DALL-E3 绘图......你都可以随意使用,无需魔法。\\n接入教程: \\u003ca href=\\\"https://ai.r9it.com/docs/install/\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://ai.r9it.com/docs/install/\\u003c/a\\u003e\\n本项目源码地址:\\u003ca href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/yangjian102621/chatgpt-plus\\u003c/a\\u003e\",\"updated\":true}'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_dall_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_dall_jobs`; +CREATE TABLE `chatgpt_dall_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `prompt` varchar(2000) NOT NULL COMMENT '提示词', + `img_url` varchar(255) NOT NULL COMMENT '图片地址', + `org_url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原图地址', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `power` smallint NOT NULL COMMENT '消耗算力', + `progress` smallint NOT NULL COMMENT '任务进度', + `err_msg` varchar(255) NOT NULL COMMENT '错误信息', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='DALLE 绘图任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_files` +-- + +DROP TABLE IF EXISTS `chatgpt_files`; +CREATE TABLE `chatgpt_files` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `name` varchar(100) NOT NULL COMMENT '文件名', + `obj_key` varchar(100) DEFAULT NULL COMMENT '文件标识', + `url` varchar(255) NOT NULL COMMENT '文件地址', + `ext` varchar(10) NOT NULL COMMENT '文件后缀', + `size` bigint NOT NULL DEFAULT '0' COMMENT '文件大小', + `created_at` datetime NOT NULL COMMENT '创建时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户文件表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_functions` +-- + +DROP TABLE IF EXISTS `chatgpt_functions`; +CREATE TABLE `chatgpt_functions` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '函数名称', + `label` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '函数标签', + `description` varchar(255) DEFAULT NULL COMMENT '函数描述', + `parameters` text COMMENT '函数参数(JSON)', + `token` varchar(255) DEFAULT NULL COMMENT 'API授权token', + `action` varchar(255) DEFAULT NULL COMMENT '函数处理 API', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='函数插件表'; + +-- +-- 转存表中的数据 `chatgpt_functions` +-- + +INSERT INTO `chatgpt_functions` (`id`, `name`, `label`, `description`, `parameters`, `token`, `action`, `enabled`) VALUES +(1, 'weibo', '微博热搜', '新浪微博热搜榜,微博当日热搜榜单', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/weibo', 0), +(2, 'zaobao', '今日早报', '每日早报,获取当天新闻事件列表', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/zaobao', 0), +(3, 'dalle3', 'DALLE3', 'AI 绘画工具,根据输入的绘图描述用 AI 工具进行绘画', '{\"type\":\"object\",\"required\":[\"prompt\"],\"properties\":{\"prompt\":{\"type\":\"string\",\"description\":\"绘画提示词\"}}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/dalle3', 0); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_invite_codes` +-- + +DROP TABLE IF EXISTS `chatgpt_invite_codes`; +CREATE TABLE `chatgpt_invite_codes` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `code` char(8) NOT NULL COMMENT '邀请码', + `hits` int NOT NULL COMMENT '点击次数', + `reg_num` smallint NOT NULL COMMENT '注册数量', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户邀请码'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_invite_logs` +-- + +DROP TABLE IF EXISTS `chatgpt_invite_logs`; +CREATE TABLE `chatgpt_invite_logs` ( + `id` int NOT NULL, + `inviter_id` int NOT NULL COMMENT '邀请人ID', + `user_id` int NOT NULL COMMENT '注册用户ID', + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `invite_code` char(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '邀请码', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='邀请注册日志'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_menus` +-- + +DROP TABLE IF EXISTS `chatgpt_menus`; +CREATE TABLE `chatgpt_menus` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '菜单名称', + `icon` varchar(150) NOT NULL COMMENT '菜单图标', + `url` varchar(100) NOT NULL COMMENT '地址', + `sort_num` smallint NOT NULL COMMENT '排序', + `enabled` tinyint(1) NOT NULL COMMENT '是否启用' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='前端菜单表'; + +-- +-- 转存表中的数据 `chatgpt_menus` +-- + +INSERT INTO `chatgpt_menus` (`id`, `name`, `icon`, `url`, `sort_num`, `enabled`) VALUES +(1, 'AI 对话', '/images/menu/chat.png', '/chat', 1, 1), +(5, 'MJ 绘画', '/images/menu/mj.png', '/mj', 2, 1), +(6, 'SD 绘画', '/images/menu/sd.png', '/sd', 3, 1), +(7, '算力日志', '/images/menu/log.png', '/powerLog', 9, 1), +(8, '应用中心', '/images/menu/app.png', '/apps', 8, 1), +(9, '画廊', '/images/menu/img-wall.png', '/images-wall', 5, 1), +(10, '会员计划', '/images/menu/member.png', '/member', 10, 1), +(11, '分享计划', '/images/menu/share.png', '/invite', 11, 1), +(12, '思维导图', '/images/menu/xmind.png', '/xmind', 7, 1), +(13, 'DALLE', '/images/menu/dalle.png', '/dalle', 4, 1), +(14, '项目文档', '/images/menu/docs.png', 'https://docs.geekai.me', 12, 1), +(16, '极客论坛', '/images/menu/bbs.png', 'https://bbs.geekai.cn', 13, 1), +(19, 'Suno', '/images/menu/suno.png', '/suno', 5, 1); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_mj_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_mj_jobs`; +CREATE TABLE `chatgpt_mj_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `task_id` varchar(20) DEFAULT NULL COMMENT '任务 ID', + `type` varchar(20) DEFAULT 'image' COMMENT '任务类别', + `message_id` char(40) NOT NULL COMMENT '消息 ID', + `channel_id` char(40) DEFAULT NULL COMMENT '频道ID', + `reference_id` char(40) DEFAULT NULL COMMENT '引用消息 ID', + `prompt` varchar(2000) NOT NULL COMMENT '会话提示词', + `img_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '图片URL', + `org_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原始图片地址', + `hash` varchar(100) DEFAULT NULL COMMENT 'message hash', + `progress` smallint DEFAULT '0' COMMENT '任务进度', + `use_proxy` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用反代', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', + `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_orders` +-- + +DROP TABLE IF EXISTS `chatgpt_orders`; +CREATE TABLE `chatgpt_orders` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `product_id` int NOT NULL COMMENT '产品ID', + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户明', + `order_no` varchar(30) NOT NULL COMMENT '订单ID', + `trade_no` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付平台交易流水号', + `subject` varchar(100) NOT NULL COMMENT '订单产品', + `amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单金额', + `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '订单状态(0:待支付,1:已扫码,2:支付成功)', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注', + `pay_time` int DEFAULT NULL COMMENT '支付时间', + `pay_way` varchar(20) NOT NULL COMMENT '支付方式', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `deleted_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='充值订单表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_power_logs` +-- + +DROP TABLE IF EXISTS `chatgpt_power_logs`; +CREATE TABLE `chatgpt_power_logs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `username` varchar(30) NOT NULL COMMENT '用户名', + `type` tinyint(1) NOT NULL COMMENT '类型(1:充值,2:消费,3:退费)', + `amount` smallint NOT NULL COMMENT '算力数值', + `balance` int NOT NULL COMMENT '余额', + `model` varchar(30) NOT NULL COMMENT '模型', + `remark` varchar(255) NOT NULL COMMENT '备注', + `mark` tinyint(1) NOT NULL COMMENT '资金类型(0:支出,1:收入)', + `created_at` datetime NOT NULL COMMENT '创建时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户算力消费日志'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_products` +-- + +DROP TABLE IF EXISTS `chatgpt_products`; +CREATE TABLE `chatgpt_products` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '名称', + `price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '价格', + `discount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额', + `days` smallint NOT NULL DEFAULT '0' COMMENT '延长天数', + `power` int NOT NULL DEFAULT '0' COMMENT '增加算力值', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启动', + `sales` int NOT NULL DEFAULT '0' COMMENT '销量', + `sort_num` tinyint NOT NULL DEFAULT '0' COMMENT '排序', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `app_url` varchar(255) DEFAULT NULL COMMENT 'App跳转地址', + `url` varchar(255) DEFAULT NULL COMMENT '跳转地址' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员套餐表'; + +-- +-- 转存表中的数据 `chatgpt_products` +-- + +INSERT INTO `chatgpt_products` (`id`, `name`, `price`, `discount`, `days`, `power`, `enabled`, `sales`, `sort_num`, `created_at`, `updated_at`, `app_url`, `url`) VALUES +(5, '100次点卡', 9.99, 9.98, 0, 100, 1, 7, 0, '2023-08-28 10:55:08', '2024-06-11 16:48:44', NULL, NULL), +(6, '200次点卡', 19.90, 15.00, 0, 200, 1, 1, 0, '1970-01-01 08:00:00', '2024-06-11 11:41:52', NULL, NULL); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_rewards` +-- + +DROP TABLE IF EXISTS `chatgpt_rewards`; +CREATE TABLE `chatgpt_rewards` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `tx_id` char(36) NOT NULL COMMENT '交易 ID', + `amount` decimal(10,2) NOT NULL COMMENT '打赏金额', + `remark` varchar(80) NOT NULL COMMENT '备注', + `status` tinyint(1) NOT NULL COMMENT '核销状态,0:未核销,1:已核销', + `exchange` varchar(255) NOT NULL COMMENT '兑换详情(json)', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户打赏'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_sd_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_sd_jobs`; +CREATE TABLE `chatgpt_sd_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT 'txt2img' COMMENT '任务类别', + `task_id` char(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务 ID', + `prompt` varchar(2000) NOT NULL COMMENT '会话提示词', + `img_url` varchar(255) DEFAULT NULL COMMENT '图片URL', + `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '绘画参数json', + `progress` smallint DEFAULT '0' COMMENT '任务进度', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', + `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Stable Diffusion 任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_suno_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_suno_jobs`; +CREATE TABLE `chatgpt_suno_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `channel` varchar(100) NOT NULL COMMENT '渠道', + `title` varchar(100) DEFAULT NULL COMMENT '歌曲标题', + `type` tinyint(1) DEFAULT '0' COMMENT '任务类型,1:灵感创作,2:自定义创作', + `task_id` varchar(50) DEFAULT NULL COMMENT '任务 ID', + `ref_task_id` char(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '引用任务 ID', + `tags` varchar(100) DEFAULT NULL COMMENT '歌曲风格', + `instrumental` tinyint(1) DEFAULT '0' COMMENT '是否为纯音乐', + `extend_secs` smallint DEFAULT '0' COMMENT '延长秒数', + `song_id` varchar(50) DEFAULT NULL COMMENT '要续写的歌曲 ID', + `ref_song_id` varchar(50) NOT NULL COMMENT '引用的歌曲ID', + `prompt` varchar(2000) NOT NULL COMMENT '提示词', + `cover_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '封面图地址', + `audio_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '音频地址', + `model_name` varchar(30) DEFAULT NULL COMMENT '模型地址', + `progress` smallint DEFAULT '0' COMMENT '任务进度', + `duration` smallint NOT NULL DEFAULT '0' COMMENT '歌曲时长', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', + `raw_data` text COMMENT '原始数据', + `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', + `play_times` int DEFAULT NULL COMMENT '播放次数', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_users` +-- + +DROP TABLE IF EXISTS `chatgpt_users`; +CREATE TABLE `chatgpt_users` ( + `id` int NOT NULL, + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `nickname` varchar(30) NOT NULL COMMENT '昵称', + `password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', + `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '头像', + `salt` char(12) NOT NULL COMMENT '密码盐', + `power` int NOT NULL DEFAULT '0' COMMENT '剩余算力', + `expired_time` int NOT NULL COMMENT '用户过期时间', + `status` tinyint(1) NOT NULL COMMENT '当前状态', + `chat_config_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天配置json', + `chat_roles_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天角色 json', + `chat_models_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'AI模型 json', + `last_login_at` int NOT NULL COMMENT '最后登录时间', + `vip` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否会员', + `last_login_ip` char(16) NOT NULL COMMENT '最后登录 IP', + `openid` varchar(100) DEFAULT NULL COMMENT '第三方登录账号ID', + `platform` varchar(30) DEFAULT NULL COMMENT '登录平台', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表'; + +-- +-- 转存表中的数据 `chatgpt_users` +-- + +INSERT INTO `chatgpt_users` (`id`, `username`, `nickname`, `password`, `avatar`, `salt`, `power`, `expired_time`, `status`, `chat_config_json`, `chat_roles_json`, `chat_models_json`, `last_login_at`, `vip`, `last_login_ip`, `openid`, `platform`, `created_at`, `updated_at`) VALUES +(4, '18575670125', '极客学长', 'ccc3fb7ab61b8b5d096a4a166ae21d121fc38c71bbd1be6173d9ab973214a63b', 'http://localhost:5678/static/upload/2024/5/1715651569509929.png', 'ueedue5l', 5853, 0, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"red_book\",\"gpt\",\"seller\",\"artist\",\"lu_xun\",\"girl_friend\",\"psychiatrist\",\"teacher\",\"programmer\",\"test\",\"qing_gan_da_shi\",\"english_trainer\",\"elon_musk\"]', '[1,11]', 1722319280, 1, '172.22.18.211', NULL, NULL, '2023-06-12 16:47:17', '2024-07-30 14:01:21'), +(5, 'yangjian102621@gmail.com', '极客学长@486041', '75d1a22f33e1ffffb7943946b6b8d5177d5ecd685d3cef1b468654038b0a8c22', '/images/avatar/user.png', '2q8ugxzk', 100, 0, 1, '', '[\"gpt\",\"programmer\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', NULL, NULL, '2024-04-23 09:17:26', '2024-04-23 09:17:26'), +(8, 'yangjian102623@gmail.com', '极客学长@714931', 'f8f0e0abf146569217273ea0712a0f9b6cbbe7d943a1d9bd5f91c55e6d8c05d1', '/images/avatar/user.png', 'geuddq7f', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', NULL, NULL, '2024-04-26 15:19:28', '2024-04-26 15:19:28'), +(9, '1234567', '极客学长@604526', '858e2afec79e1d6364f4567f945f2310024896d9aa45dd944efa95a0c31e4d08', '/images/avatar/user.png', '00qawlos', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', NULL, NULL, '2024-04-26 15:21:06', '2024-04-26 15:21:06'), +(11, 'abc123', '极客学长@965562', '7a15c53afdb1da7093d80f9940e716eb396e682cfb1f2d107d0b81b183a3ba13', '/images/avatar/user.png', '6433mfbk', 1124, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', NULL, NULL, '2024-06-06 09:37:44', '2024-06-06 09:37:44'), +(14, 'wx@3567548322', '极客学长', '5a349ba89582a4074938b5a3ce84e87c937681ad47e8b87aab03a987e22b6077', 'https://thirdwx.qlogo.cn/mmopen/vi_32/uyxRMqZcEkb7fHouKXbNzxrnrvAttBKkwNlZ7yFibibRGiahdmsrZ3A1NKf8Fw5qJNJn4TXRmygersgEbibaSGd9Sg/132', 'abhzbmij', 83, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', 'oCs0t62472W19z2LOEKI1rWyCTTA', '', '2024-07-04 14:52:08', '2024-07-04 14:52:08'), +(15, 'user123', '极客学长@191303', '4a4c0a14d5fc8787357517f14f6e442281b42c8ec4395016b77483997476011e', '/images/avatar/user.png', 'cyzwkbrx', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '', '', '2024-07-09 10:49:27', '2024-07-09 10:49:27'), +(17, 'user1234', '极客学长@836764', 'bfe03c9c8c9fff5b77e36e40e8298ad3a6073d43c6a936b008eebb21113bf550', '/images/avatar/user.png', '1d2alwnj', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '', '', '2024-07-09 10:53:17', '2024-07-09 10:53:17'), +(18, 'liaoyq', '极客学长@405564', 'ad1726089022db4c661235a8aab7307af1a7f8483eee08bac3f79b5a6a9bd26b', '/images/avatar/user.png', 'yq862l01', 100, 0, 1, '', '[\"string\"]', '[11,7,1,10,12,19,18,17,3]', 1720574265, 0, '172.22.11.29', '', '', '2024-07-10 09:15:33', '2024-07-10 09:17:45'), +(19, 'humm', '极客学长@483216', '420970ace96921c8b3ac7668d097182eab1b6436c730a484e82ae4661bd4f7d9', '/images/avatar/user.png', '1gokrcl2', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 1721381395, 0, '172.22.11.36', '', '', '2024-07-10 11:08:31', '2024-07-19 17:29:56'), +(20, 'abc', '极客学长@369852', '6cad48fb2cc0f54600d66a829e9be69ffd9340a49d5a5b1abda5d4082d946833', '/images/avatar/user.png', 'gop65zei', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '', '', '2024-07-11 16:44:14', '2024-07-11 16:44:14'), +(21, 'husm@pvc123.com', '极客学长@721654', 'e030537dc43fea1bf1fa55a24f99e44f29311bebea96e88ea186995c77db083b', '/images/avatar/user.png', 'p1etg3oi', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '', '', '2024-07-11 16:50:33', '2024-07-11 16:50:33'), +(22, '15818323616', 'ted0000', '3ca6b2ff585d03be8ca4de33ad00148497a09372914ee8aa4cfde343266cbcdd', 'http://localhost:5678/static/upload/2024/7/1720775695548167.jpg', 'sq4s1brf', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 1721785366, 0, '172.22.11.36', '', '', '2024-07-12 15:12:16', '2024-07-24 09:42:46'), +(23, 'aaaaaaaa', '极客学长@488661', 'a7f05323a6ec9dfc1e9bc126f15ccc17c38d0df47957a0bec51f4cc5c2a2b906', '/images/avatar/user.png', 'dsz5d6td', 19, 0, 1, '', '[\"gpt\",\"psychiatrist\",\"red_book\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '', '', '2024-07-22 13:49:55', '2024-07-22 13:49:55'), +(24, 'test', '极客学长@822932', 'a54d3c38a4a20106ade96de0e9d4547cc691abc5dc39697b44c1a82850374775', '/images/avatar/user.png', '4aa7pijd', 10, 0, 1, '', '[\"gpt\"]', '[1,46]', 0, 0, '', '', '', '2024-07-22 14:40:42', '2024-07-22 14:40:42'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_user_login_logs` +-- + +DROP TABLE IF EXISTS `chatgpt_user_login_logs`; +CREATE TABLE `chatgpt_user_login_logs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `username` varchar(30) NOT NULL COMMENT '用户名', + `login_ip` char(16) NOT NULL COMMENT '登录IP', + `login_address` varchar(30) NOT NULL COMMENT '登录地址', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户登录日志'; + +-- +-- 转储表的索引 +-- + +-- +-- 表的索引 `chatgpt_admin_users` +-- +ALTER TABLE `chatgpt_admin_users` + ADD PRIMARY KEY (`id`) USING BTREE, + ADD UNIQUE KEY `username` (`username`) USING BTREE; + +-- +-- 表的索引 `chatgpt_api_keys` +-- +ALTER TABLE `chatgpt_api_keys` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_chat_history` +-- +ALTER TABLE `chatgpt_chat_history` + ADD PRIMARY KEY (`id`), + ADD KEY `chat_id` (`chat_id`); + +-- +-- 表的索引 `chatgpt_chat_items` +-- +ALTER TABLE `chatgpt_chat_items` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `chat_id` (`chat_id`); + +-- +-- 表的索引 `chatgpt_chat_models` +-- +ALTER TABLE `chatgpt_chat_models` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_chat_roles` +-- +ALTER TABLE `chatgpt_chat_roles` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `marker` (`marker`); + +-- +-- 表的索引 `chatgpt_configs` +-- +ALTER TABLE `chatgpt_configs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `marker` (`marker`); + +-- +-- 表的索引 `chatgpt_dall_jobs` +-- +ALTER TABLE `chatgpt_dall_jobs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_files` +-- +ALTER TABLE `chatgpt_files` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_functions` +-- +ALTER TABLE `chatgpt_functions` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `name` (`name`); + +-- +-- 表的索引 `chatgpt_invite_codes` +-- +ALTER TABLE `chatgpt_invite_codes` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `code` (`code`); + +-- +-- 表的索引 `chatgpt_invite_logs` +-- +ALTER TABLE `chatgpt_invite_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_menus` +-- +ALTER TABLE `chatgpt_menus` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_mj_jobs` +-- +ALTER TABLE `chatgpt_mj_jobs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `task_id` (`task_id`), + ADD KEY `message_id` (`message_id`); + +-- +-- 表的索引 `chatgpt_orders` +-- +ALTER TABLE `chatgpt_orders` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `order_no` (`order_no`); + +-- +-- 表的索引 `chatgpt_power_logs` +-- +ALTER TABLE `chatgpt_power_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_products` +-- +ALTER TABLE `chatgpt_products` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_rewards` +-- +ALTER TABLE `chatgpt_rewards` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `tx_id` (`tx_id`); + +-- +-- 表的索引 `chatgpt_sd_jobs` +-- +ALTER TABLE `chatgpt_sd_jobs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `task_id` (`task_id`); + +-- +-- 表的索引 `chatgpt_suno_jobs` +-- +ALTER TABLE `chatgpt_suno_jobs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_users` +-- +ALTER TABLE `chatgpt_users` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `username` (`username`); + +-- +-- 表的索引 `chatgpt_user_login_logs` +-- +ALTER TABLE `chatgpt_user_login_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 在导出的表使用AUTO_INCREMENT +-- + +-- +-- 使用表AUTO_INCREMENT `chatgpt_admin_users` +-- +ALTER TABLE `chatgpt_admin_users` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=113; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_api_keys` +-- +ALTER TABLE `chatgpt_api_keys` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_chat_history` +-- +ALTER TABLE `chatgpt_chat_history` + MODIFY `id` bigint NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_chat_items` +-- +ALTER TABLE `chatgpt_chat_items` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_chat_models` +-- +ALTER TABLE `chatgpt_chat_models` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=48; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_chat_roles` +-- +ALTER TABLE `chatgpt_chat_roles` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=132; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_configs` +-- +ALTER TABLE `chatgpt_configs` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_dall_jobs` +-- +ALTER TABLE `chatgpt_dall_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_files` +-- +ALTER TABLE `chatgpt_files` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_functions` +-- +ALTER TABLE `chatgpt_functions` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_invite_codes` +-- +ALTER TABLE `chatgpt_invite_codes` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_invite_logs` +-- +ALTER TABLE `chatgpt_invite_logs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_menus` +-- +ALTER TABLE `chatgpt_menus` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=20; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_mj_jobs` +-- +ALTER TABLE `chatgpt_mj_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_orders` +-- +ALTER TABLE `chatgpt_orders` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_power_logs` +-- +ALTER TABLE `chatgpt_power_logs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_products` +-- +ALTER TABLE `chatgpt_products` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_rewards` +-- +ALTER TABLE `chatgpt_rewards` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_sd_jobs` +-- +ALTER TABLE `chatgpt_sd_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_suno_jobs` +-- +ALTER TABLE `chatgpt_suno_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_users` +-- +ALTER TABLE `chatgpt_users` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=25; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_user_login_logs` +-- +ALTER TABLE `chatgpt_user_login_logs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/deploy/docker-compose.yaml b/deploy/docker-compose.yaml index 92670b61..255e3833 100644 --- a/deploy/docker-compose.yaml +++ b/deploy/docker-compose.yaml @@ -58,7 +58,7 @@ services: # 后端 API 程序 geekai-api: - image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-plus-api:v4.1.0-amd64 + image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-plus-api:v4.1.1-amd64 container_name: geekai-api restart: always depends_on: @@ -80,7 +80,7 @@ services: # 前端应用 geekai-web: - image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-plus-web:v4.1.0-amd64 + image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-plus-web:v4.1.1-amd64 container_name: geekai-web restart: always depends_on: diff --git a/web/src/views/admin/ChatModel.vue b/web/src/views/admin/ChatModel.vue index e574b762..990b2465 100644 --- a/web/src/views/admin/ChatModel.vue +++ b/web/src/views/admin/ChatModel.vue @@ -2,14 +2,7 @@
- - - + 搜索 新增 @@ -184,12 +177,11 @@ import ClipboardJS from "clipboard"; // 变量定义 const items = ref([]) -const query = ref({platform:''}) +const query = ref({name:''}) const item = ref({}) const showDialog = ref(false) const title = ref("") const rules = reactive({ - platform: [{required: true, message: '请选择平台', trigger: 'change',}], name: [{required: true, message: '请输入模型名称', trigger: 'change',}], value: [{required: true, message: '请输入模型值', trigger: 'change',}] }) From 1d9d487f0e1fa21feed4457d3c9ec65617406d81 Mon Sep 17 00:00:00 2001 From: RockYang Date: Wed, 31 Jul 2024 16:08:46 +0800 Subject: [PATCH 04/15] restore use power when removed not finish jobs --- CHANGELOG.md | 4 + api/core/app_server.go | 2 +- api/core/types/chat.go | 1 - api/handler/chatimpl/chat_handler.go | 2 +- api/handler/dalle_handler.go | 52 +++++++-- api/handler/markmap_handler.go | 9 +- api/handler/mj_handler.go | 52 ++++----- api/handler/sd_handler.go | 46 ++++++-- api/handler/suno_handler.go | 37 ++++++- api/service/dalle/service.go | 69 +++++------- api/service/mj/pool.go | 8 ++ api/service/sd/pool.go | 26 +---- api/service/sd/service.go | 2 +- web/.env.development | 4 +- web/.env.production | 4 +- web/src/assets/css/image-dall.styl | 129 +--------------------- web/src/assets/css/image-sd.styl | 130 +--------------------- web/src/assets/css/waterfall-list.styl | 146 +++++++++++++++++++++++++ web/src/views/ChatPlus.vue | 4 +- web/src/views/Dalle.vue | 74 +++++-------- web/src/views/Home.vue | 2 +- web/src/views/ImageMj.vue | 2 +- web/src/views/ImageSd.vue | 101 ++++++++--------- web/src/views/MarkMap.vue | 2 +- web/src/views/Suno.vue | 4 +- 25 files changed, 425 insertions(+), 487 deletions(-) create mode 100644 web/src/assets/css/waterfall-list.styl diff --git a/CHANGELOG.md b/CHANGELOG.md index e96a7755..07c6188d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # 更新日志 + +## v4.1.2 +* Bug修复:修复思维导图页面获取模型失败的问题 + ## v4.1.1 * Bug修复:修复 GPT 模型 function call 调用后没有输出的问题 * 功能新增:允许获取 License 授权用户可以自定义版权信息 diff --git a/api/core/app_server.go b/api/core/app_server.go index 3fb32096..84bc89a8 100644 --- a/api/core/app_server.go +++ b/api/core/app_server.go @@ -225,7 +225,7 @@ func needLogin(c *gin.Context) bool { c.Request.URL.Path == "/api/payment/doPay" || c.Request.URL.Path == "/api/payment/payWays" || c.Request.URL.Path == "/api/suno/client" || - c.Request.URL.Path == "/api/suno/Detail" || + c.Request.URL.Path == "/api/suno/detail" || c.Request.URL.Path == "/api/suno/play" || strings.HasPrefix(c.Request.URL.Path, "/api/test") || strings.HasPrefix(c.Request.URL.Path, "/api/user/clogin") || diff --git a/api/core/types/chat.go b/api/core/types/chat.go index cdf418b6..ccaf0a9c 100644 --- a/api/core/types/chat.go +++ b/api/core/types/chat.go @@ -61,7 +61,6 @@ type ChatSession struct { type ChatModel struct { Id uint `json:"id"` - Platform string `json:"platform"` Name string `json:"name"` Value string `json:"value"` Power int `json:"power"` diff --git a/api/handler/chatimpl/chat_handler.go b/api/handler/chatimpl/chat_handler.go index a8c12362..6b1e9f8e 100644 --- a/api/handler/chatimpl/chat_handler.go +++ b/api/handler/chatimpl/chat_handler.go @@ -468,7 +468,7 @@ func (h *ChatHandler) doRequest(ctx context.Context, req types.ApiRequest, sessi } else { client = http.DefaultClient } - logger.Debugf("Sending %s request, Channel:%s, API KEY:%s, PROXY: %s, Model: %s", session.Model.Platform, apiKey.ApiURL, apiURL, apiKey.ProxyURL, req.Model) + logger.Debugf("Sending %s request, API KEY:%s, PROXY: %s, Model: %s", apiKey.ApiURL, apiURL, apiKey.ProxyURL, req.Model) request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey.Value)) // 更新API KEY 最后使用时间 h.DB.Model(&model.ApiKey{}).Where("id", apiKey.Id).UpdateColumn("last_used_at", time.Now().Unix()) diff --git a/api/handler/dalle_handler.go b/api/handler/dalle_handler.go index 89226638..65d631fb 100644 --- a/api/handler/dalle_handler.go +++ b/api/handler/dalle_handler.go @@ -8,6 +8,7 @@ package handler // * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import ( + "fmt" "geekai/core" "geekai/core/types" "geekai/service/dalle" @@ -16,9 +17,9 @@ import ( "geekai/store/vo" "geekai/utils" "geekai/utils/resp" - "net/http" - "github.com/gorilla/websocket" + "net/http" + "time" "github.com/gin-gonic/gin" "github.com/go-redis/redis/v8" @@ -178,7 +179,7 @@ func (h *DallJobHandler) getData(finish bool, userId uint, page int, pageSize in session := h.DB.Session(&gorm.Session{}) if finish { - session = session.Where("progress = ?", 100).Order("id DESC") + session = session.Where("progress >= ?", 100).Order("id DESC") } else { session = session.Where("progress < ?", 100).Order("id ASC") } @@ -215,20 +216,51 @@ func (h *DallJobHandler) getData(finish bool, userId uint, page int, pageSize in // Remove remove task image func (h *DallJobHandler) Remove(c *gin.Context) { id := h.GetInt(c, "id", 0) - userId := h.GetInt(c, "user_id", 0) + userId := h.GetLoginUserId(c) var job model.DallJob if res := h.DB.Where("id = ? AND user_id = ?", id, userId).First(&job); res.Error != nil { resp.ERROR(c, "记录不存在") return } - // remove job recode - res := h.DB.Delete(&model.DallJob{Id: job.Id}) - if res.Error != nil { - resp.ERROR(c, res.Error.Error()) + // 删除任务 + tx := h.DB.Begin() + if err := tx.Delete(&job).Error; err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) return } + // 如果任务未完成,或者任务失败,则恢复用户算力 + if job.Progress != 100 { + err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error + if err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } + + var user model.User + h.DB.Where("id = ?", job.UserId).First(&user) + err = tx.Create(&model.PowerLog{ + UserId: user.Id, + Username: user.Username, + Type: types.PowerConsume, + Amount: job.Power, + Balance: user.Power, + Mark: types.PowerAdd, + Model: "dall-e-3", + Remark: fmt.Sprintf("任务失败,退回算力。任务ID:%d,Err: %s", job.Id, job.ErrMsg), + CreatedAt: time.Now(), + }).Error + if err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } + } + tx.Commit() + // remove image err := h.uploader.GetUploadHandler().Delete(job.ImgURL) if err != nil { @@ -241,10 +273,10 @@ func (h *DallJobHandler) Remove(c *gin.Context) { // Publish 发布/取消发布图片到画廊显示 func (h *DallJobHandler) Publish(c *gin.Context) { id := h.GetInt(c, "id", 0) - userId := h.GetInt(c, "user_id", 0) + userId := h.GetLoginUserId(c) action := h.GetBool(c, "action") // 发布动作,true => 发布,false => 取消分享 - res := h.DB.Model(&model.DallJob{Id: uint(id), UserId: uint(userId)}).UpdateColumn("publish", action) + res := h.DB.Model(&model.DallJob{Id: uint(id), UserId: userId}).UpdateColumn("publish", action) if res.Error != nil { logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败") diff --git a/api/handler/markmap_handler.go b/api/handler/markmap_handler.go index e6926f07..8196a81e 100644 --- a/api/handler/markmap_handler.go +++ b/api/handler/markmap_handler.go @@ -101,17 +101,13 @@ func (h *MarkMapHandler) sendMessage(client *types.WsClient, prompt string, mode return fmt.Errorf("error with query chat model: %v", res.Error) } - if user.Status == false { - return errors.New("当前用户被禁用") - } - if user.Power < chatModel.Power { return fmt.Errorf("您当前剩余算力(%d)已不足以支付当前模型算力(%d)!", user.Power, chatModel.Power) } messages := make([]interface{}, 0) messages = append(messages, types.Message{Role: "system", Content: ` -你是一位非常优秀的思维导图助手,你会把用户的所有提问都总结成思维导图,然后以 Markdown 格式输出。markdown 只需要输出一级标题,二级标题,三级标题,四级标题,最多输出四级,除此之外不要输出任何其他 markdown 标记。下面是一个合格的例子: +你是一位非常优秀的思维导图助手, 你能帮助用户整理思路,根据用户提供的主题或内容,快速生成结构清晰,有条理的思维导图,然后以 Markdown 格式输出。markdown 只需要输出一级标题,二级标题,三级标题,四级标题,最多输出四级,除此之外不要输出任何其他 markdown 标记。下面是一个合格的例子: # Geek-AI 助手 ## 完整的开源系统 @@ -130,7 +126,7 @@ func (h *MarkMapHandler) sendMessage(client *types.WsClient, prompt string, mode 另外,除此之外不要任何解释性语句。 `}) - messages = append(messages, types.Message{Role: "user", Content: prompt}) + messages = append(messages, types.Message{Role: "user", Content: fmt.Sprintf("请生成一份有关【%s】一份思维导图,要求结构清晰,有条理", prompt)}) var req = types.ApiRequest{ Model: chatModel.Value, Stream: true, @@ -253,5 +249,6 @@ func (h *MarkMapHandler) doRequest(req types.ApiRequest, chatModel model.ChatMod client = http.DefaultClient } request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey.Value)) + logger.Debugf("Sending %s request, API KEY:%s, PROXY: %s, Model: %s", apiKey.ApiURL, apiURL, apiKey.ProxyURL, req.Model) return client.Do(request) } diff --git a/api/handler/mj_handler.go b/api/handler/mj_handler.go index 5b49f51a..049af981 100644 --- a/api/handler/mj_handler.go +++ b/api/handler/mj_handler.go @@ -465,35 +465,37 @@ func (h *MidJourneyHandler) Remove(c *gin.Context) { return } - // refund power - err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error - if err != nil { - tx.Rollback() - resp.ERROR(c, err.Error()) - return - } - var user model.User - h.DB.Where("id = ?", job.UserId).First(&user) - err = tx.Create(&model.PowerLog{ - UserId: user.Id, - Username: user.Username, - Type: types.PowerConsume, - Amount: job.Power, - Balance: user.Power + job.Power, - Mark: types.PowerAdd, - Model: "mid-journey", - Remark: fmt.Sprintf("绘画任务失败,退回算力。任务ID:%s", job.TaskId), - CreatedAt: time.Now(), - }).Error - if err != nil { - tx.Rollback() - resp.ERROR(c, err.Error()) - return + // 如果任务未完成,或者任务失败,则恢复用户算力 + if job.Progress != 100 { + err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error + if err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } + var user model.User + h.DB.Where("id = ?", job.UserId).First(&user) + err = tx.Create(&model.PowerLog{ + UserId: user.Id, + Username: user.Username, + Type: types.PowerConsume, + Amount: job.Power, + Balance: user.Power, + Mark: types.PowerAdd, + Model: "mid-journey", + Remark: fmt.Sprintf("绘画任务失败,退回算力。任务ID:%s,Err: %s", job.TaskId, job.ErrMsg), + CreatedAt: time.Now(), + }).Error + if err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } } tx.Commit() // remove image - err = h.uploader.GetUploadHandler().Delete(job.ImgURL) + err := h.uploader.GetUploadHandler().Delete(job.ImgURL) if err != nil { logger.Error("remove image failed: ", err) } diff --git a/api/handler/sd_handler.go b/api/handler/sd_handler.go index c99d2f9b..18710358 100644 --- a/api/handler/sd_handler.go +++ b/api/handler/sd_handler.go @@ -232,7 +232,7 @@ func (h *SdJobHandler) getData(finish bool, userId uint, page int, pageSize int, session := h.DB.Session(&gorm.Session{}) if finish { - session = session.Where("progress = ?", 100).Order("id DESC") + session = session.Where("progress >= ?", 100).Order("id DESC") } else { session = session.Where("progress < ?", 100).Order("id ASC") } @@ -278,20 +278,50 @@ func (h *SdJobHandler) getData(finish bool, userId uint, page int, pageSize int, // Remove remove task image func (h *SdJobHandler) Remove(c *gin.Context) { id := h.GetInt(c, "id", 0) - userId := h.GetInt(c, "user_id", 0) + userId := h.GetLoginUserId(c) var job model.SdJob if res := h.DB.Where("id = ? AND user_id = ?", id, userId).First(&job); res.Error != nil { resp.ERROR(c, "记录不存在") return } - // remove job recode - res := h.DB.Delete(&model.SdJob{Id: job.Id}) - if res.Error != nil { - resp.ERROR(c, res.Error.Error()) + // 删除任务 + tx := h.DB.Begin() + if err := tx.Delete(&job).Error; err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) return } + // 如果任务未完成,或者任务失败,则恢复用户算力 + if job.Progress != 100 { + err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error + if err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } + var user model.User + h.DB.Where("id = ?", job.UserId).First(&user) + err = tx.Create(&model.PowerLog{ + UserId: user.Id, + Username: user.Username, + Type: types.PowerConsume, + Amount: job.Power, + Balance: user.Power, + Mark: types.PowerAdd, + Model: "stable-diffusion", + Remark: fmt.Sprintf("任务失败,退回算力。任务ID:%s, Err: %s", job.TaskId, job.ErrMsg), + CreatedAt: time.Now(), + }).Error + if err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } + } + tx.Commit() + // remove image err := h.uploader.GetUploadHandler().Delete(job.ImgURL) if err != nil { @@ -309,10 +339,10 @@ func (h *SdJobHandler) Remove(c *gin.Context) { // Publish 发布/取消发布图片到画廊显示 func (h *SdJobHandler) Publish(c *gin.Context) { id := h.GetInt(c, "id", 0) - userId := h.GetInt(c, "user_id", 0) + userId := h.GetLoginUserId(c) action := h.GetBool(c, "action") // 发布动作,true => 发布,false => 取消分享 - res := h.DB.Model(&model.SdJob{Id: uint(id), UserId: userId}).UpdateColumn("publish", action) + res := h.DB.Model(&model.SdJob{Id: uint(id), UserId: int(userId)}).UpdateColumn("publish", action) if res.Error != nil { logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败") diff --git a/api/handler/suno_handler.go b/api/handler/suno_handler.go index 4fbf031a..b2fba821 100644 --- a/api/handler/suno_handler.go +++ b/api/handler/suno_handler.go @@ -210,7 +210,42 @@ func (h *SunoHandler) Remove(c *gin.Context) { return } // 删除任务 - h.DB.Delete(&job) + tx := h.DB.Begin() + if err := tx.Delete(&job).Error; err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } + + // 如果任务未完成,或者任务失败,则恢复用户算力 + if job.Progress != 100 { + err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error + if err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } + var user model.User + h.DB.Where("id = ?", job.UserId).First(&user) + err = tx.Create(&model.PowerLog{ + UserId: user.Id, + Username: user.Username, + Type: types.PowerConsume, + Amount: job.Power, + Balance: user.Power, + Mark: types.PowerAdd, + Model: job.ModelName, + Remark: fmt.Sprintf("Suno 任务失败,退回算力。任务ID:%s,Err:%s", job.TaskId, job.ErrMsg), + CreatedAt: time.Now(), + }).Error + if err != nil { + tx.Rollback() + resp.ERROR(c, err.Error()) + return + } + } + tx.Commit() + // 删除文件 _ = h.uploader.GetUploadHandler().Delete(job.CoverURL) _ = h.uploader.GetUploadHandler().Delete(job.AudioURL) diff --git a/api/service/dalle/service.go b/api/service/dalle/service.go index 20d136c7..5c5a1929 100644 --- a/api/service/dalle/service.go +++ b/api/service/dalle/service.go @@ -70,7 +70,7 @@ func (s *Service) Run() { if err != nil { logger.Errorf("error with image task: %v", err) s.db.Model(&model.DallJob{Id: task.JobId}).UpdateColumns(map[string]interface{}{ - "progress": -1, + "progress": 101, "err_msg": err.Error(), }) s.notifyQueue.RPush(sd.NotifyMessage{UserId: int(task.UserId), JobId: int(task.JobId), Message: sd.Failed}) @@ -148,7 +148,7 @@ func (s *Service) Image(task types.DallTask, sync bool) (string, error) { Where("enabled", true). Order("last_used_at ASC").First(&apiKey) if tx.Error != nil { - return "", fmt.Errorf("no available IMG api key: %v", tx.Error) + return "", fmt.Errorf("no available DALL-E api key: %v", tx.Error) } var res imgRes @@ -225,6 +225,30 @@ func (s *Service) CheckTaskNotify() { }() } +func (s *Service) CheckTaskStatus() { + go func() { + logger.Info("Running DALL-E task status checking ...") + for { + var jobs []model.DallJob + res := s.db.Where("progress < ?", 100).Find(&jobs) + if res.Error != nil { + time.Sleep(5 * time.Second) + continue + } + + for _, job := range jobs { + // 超时的任务标记为失败 + if time.Now().Sub(job.CreatedAt) > time.Minute*10 { + job.Progress = 101 + job.ErrMsg = "任务超时" + s.db.Updates(&job) + } + } + time.Sleep(time.Second * 10) + } + }() +} + func (s *Service) DownloadImages() { go func() { var items []model.DallJob @@ -271,44 +295,3 @@ func (s *Service) downloadImage(jobId uint, userId int, orgURL string) (string, s.notifyQueue.RPush(sd.NotifyMessage{UserId: userId, JobId: int(jobId), Message: sd.Finished}) return imgURL, nil } - -// CheckTaskStatus 检查任务状态,自动删除过期或者失败的任务 -func (s *Service) CheckTaskStatus() { - go func() { - logger.Info("Running Stable-Diffusion task status checking ...") - for { - var jobs []model.DallJob - res := s.db.Where("progress < ?", 100).Find(&jobs) - if res.Error != nil { - time.Sleep(5 * time.Second) - continue - } - - for _, job := range jobs { - // 5 分钟还没完成的任务直接删除 - if time.Now().Sub(job.CreatedAt) > time.Minute*5 || job.Progress == -1 { - s.db.Delete(&job) - var user model.User - s.db.Where("id = ?", job.UserId).First(&user) - // 退回绘图次数 - res = s.db.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)) - if res.Error == nil && res.RowsAffected > 0 { - s.db.Create(&model.PowerLog{ - UserId: user.Id, - Username: user.Username, - Type: types.PowerConsume, - Amount: job.Power, - Balance: user.Power + job.Power, - Mark: types.PowerAdd, - Model: "dall-e-3", - Remark: fmt.Sprintf("任务失败,退回算力。任务ID:%d", job.Id), - CreatedAt: time.Now(), - }) - } - continue - } - } - time.Sleep(time.Second * 10) - } - }() -} diff --git a/api/service/mj/pool.go b/api/service/mj/pool.go index 80ed6067..0e319fe6 100644 --- a/api/service/mj/pool.go +++ b/api/service/mj/pool.go @@ -187,6 +187,14 @@ func (p *ServicePool) SyncTaskProgress() { } for _, job := range jobs { + // 5 分钟还没完成的任务标记为失败 + if time.Now().Sub(job.CreatedAt) > time.Minute*5 { + job.Progress = 101 + job.ErrMsg = "任务超时" + p.db.Updates(&job) + continue + } + if servicePlus := p.getService(job.ChannelId); servicePlus != nil { _ = servicePlus.Notify(job) } diff --git a/api/service/sd/pool.go b/api/service/sd/pool.go index 548875ec..1d70a64a 100644 --- a/api/service/sd/pool.go +++ b/api/service/sd/pool.go @@ -109,27 +109,11 @@ func (p *ServicePool) CheckTaskStatus() { } for _, job := range jobs { - // 5 分钟还没完成的任务直接删除 - if time.Now().Sub(job.CreatedAt) > time.Minute*5 || job.Progress == -1 { - p.db.Delete(&job) - var user model.User - p.db.Where("id = ?", job.UserId).First(&user) - // 退回绘图次数 - res = p.db.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)) - if res.Error == nil && res.RowsAffected > 0 { - p.db.Create(&model.PowerLog{ - UserId: user.Id, - Username: user.Username, - Type: types.PowerConsume, - Amount: job.Power, - Balance: user.Power + job.Power, - Mark: types.PowerAdd, - Model: "stable-diffusion", - Remark: fmt.Sprintf("任务失败,退回算力。任务ID:%s", job.TaskId), - CreatedAt: time.Now(), - }) - } - continue + // 5 分钟还没完成的任务标记为失败 + if time.Now().Sub(job.CreatedAt) > time.Minute*5 { + job.Progress = 101 + job.ErrMsg = "任务超时" + p.db.Updates(&job) } } time.Sleep(time.Second * 5) diff --git a/api/service/sd/service.go b/api/service/sd/service.go index dbb3a3c0..a9d707c7 100644 --- a/api/service/sd/service.go +++ b/api/service/sd/service.go @@ -87,7 +87,7 @@ func (s *Service) Run() { logger.Error("绘画任务执行失败:", err.Error()) // update the task progress s.db.Model(&model.SdJob{Id: uint(task.Id)}).UpdateColumns(map[string]interface{}{ - "progress": -1, + "progress": 101, "err_msg": err.Error(), }) // 通知前端,任务失败 diff --git a/web/.env.development b/web/.env.development index 27102ba0..f3eb9e14 100644 --- a/web/.env.development +++ b/web/.env.development @@ -4,8 +4,8 @@ VUE_APP_USER=18575670125 VUE_APP_PASS=12345678 VUE_APP_ADMIN_USER=admin VUE_APP_ADMIN_PASS=admin123 -VUE_APP_KEY_PREFIX=ChatPLUS_DEV_ +VUE_APP_KEY_PREFIX=GeekAI_DEV_ VUE_APP_TITLE="Geek-AI 创作系统" -VUE_APP_VERSION=v4.1.1 +VUE_APP_VERSION=v4.1.2 VUE_APP_DOCS_URL=https://docs.geekai.me VUE_APP_GIT_URL=https://github.com/yangjian102621/geekai diff --git a/web/.env.production b/web/.env.production index 6e3a7049..eb506d0f 100644 --- a/web/.env.production +++ b/web/.env.production @@ -1,6 +1,6 @@ VUE_APP_API_HOST= VUE_APP_WS_HOST= -VUE_APP_KEY_PREFIX=ChatPLUS_ -VUE_APP_VERSION=v4.1.1 +VUE_APP_KEY_PREFIX=GeekAI_ +VUE_APP_VERSION=v4.1.2 VUE_APP_DOCS_URL=https://docs.geekai.me VUE_APP_GIT_URL=https://github.com/yangjian102621/geekai diff --git a/web/src/assets/css/image-dall.styl b/web/src/assets/css/image-dall.styl index 57d222ce..331d4f7a 100644 --- a/web/src/assets/css/image-dall.styl +++ b/web/src/assets/css/image-dall.styl @@ -221,134 +221,7 @@ // 任务列表 - - .job-list-box { - - @import "running-job-list.styl" - - .finish-job-list { - #waterfall { - display flex - justify-content center - padding-top 20px - flex-flow column - - - .job-item { - width 100% - height 100% - border 1px solid #666666 - padding 6px - overflow hidden - border-radius 6px - transition: all 0.3s ease; /* 添加过渡效果 */ - position relative - - .opt { - .opt-line { - margin 6px 0 - - ul { - display flex - flex-flow row - - li { - margin-right 6px - - a { - padding 3px 0 - width 40px - text-align center - border-radius 5px - display block - cursor pointer - background-color #4E5058 - color #ffffff - - &:hover { - background-color #6D6F78 - } - } - } - - .show-prompt { - font-size 20px - cursor pointer - } - } - } - } - - - .remove { - display none - position absolute - right 10px - top 10px - } - - &:hover { - .remove { - display block - } - } - } - - - .animate { - &:hover { - box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* 添加阴影效果 */ - transform: translateY(-10px); /* 向上移动10像素 */ - } - } - } - } - - - .el-image { - width 100% - height 100% - overflow visible - - .el-image-viewer__wrapper { - img { - width auto - height auto - } - } - - .image-slot { - display flex - flex-flow column - justify-content center - align-items center - min-height 200px - color #ffffff - - .iconfont { - font-size 50px - margin-bottom 10px - } - } - } - - .el-image.upscale { - img { - height 310px - } - - .image-slot { - height 310px - } - - .el-image-viewer__wrapper { - img { - width auto - height auto - } - } - } - } + @import "waterfall-list.styl" } .no-more-data { diff --git a/web/src/assets/css/image-sd.styl b/web/src/assets/css/image-sd.styl index 2008f562..90594e59 100644 --- a/web/src/assets/css/image-sd.styl +++ b/web/src/assets/css/image-sd.styl @@ -220,136 +220,8 @@ } } - // 任务列表 - - .job-list-box { - - @import "running-job-list.styl" - - .finish-job-list { - #waterfall { - display flex - justify-content center - padding-top 20px - flex-flow column - - - .job-item { - width 100% - height 100% - border 1px solid #666666 - padding 6px - overflow hidden - border-radius 6px - transition: all 0.3s ease; /* 添加过渡效果 */ - position relative - - .opt { - .opt-line { - margin 6px 0 - - ul { - display flex - flex-flow row - - li { - margin-right 6px - - a { - padding 3px 0 - width 40px - text-align center - border-radius 5px - display block - cursor pointer - background-color #4E5058 - color #ffffff - - &:hover { - background-color #6D6F78 - } - } - } - - .show-prompt { - font-size 20px - cursor pointer - } - } - } - } - - - .remove { - display none - position absolute - right 10px - top 10px - } - - &:hover { - .remove { - display block - } - } - } - - - .animate { - &:hover { - box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* 添加阴影效果 */ - transform: translateY(-10px); /* 向上移动10像素 */ - } - } - } - } - - - .el-image { - width 100% - height 100% - overflow visible - - .el-image-viewer__wrapper { - img { - width auto - height auto - } - } - - .image-slot { - display flex - flex-flow column - justify-content center - align-items center - min-height 200px - color #ffffff - - .iconfont { - font-size 50px - margin-bottom 10px - } - } - } - - .el-image.upscale { - img { - height 310px - } - - .image-slot { - height 310px - } - - .el-image-viewer__wrapper { - img { - width auto - height auto - } - } - } - } + @import "waterfall-list.styl" } .no-more-data { diff --git a/web/src/assets/css/waterfall-list.styl b/web/src/assets/css/waterfall-list.styl new file mode 100644 index 00000000..071c5302 --- /dev/null +++ b/web/src/assets/css/waterfall-list.styl @@ -0,0 +1,146 @@ +.job-list-box { + + @import "running-job-list.styl" + + .finish-job-list { + #waterfall { + display flex + justify-content center + padding-top 20px + flex-flow column + + + .job-item { + width 100% + height 100% + border 1px solid #666666 + padding 6px + overflow hidden + border-radius 6px + transition: all 0.3s ease; /* 添加过渡效果 */ + position relative + + .opt { + .opt-line { + margin 6px 0 + + ul { + display flex + flex-flow row + + li { + margin-right 6px + + a { + padding 3px 0 + width 40px + text-align center + border-radius 5px + display block + cursor pointer + background-color #4E5058 + color #ffffff + + &:hover { + background-color #6D6F78 + } + } + } + + .show-prompt { + font-size 20px + cursor pointer + } + } + } + } + + + .remove { + display none + position absolute + right 10px + top 10px + } + + &:hover { + .remove { + display block + } + } + } + + + .animate { + &:hover { + box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* 添加阴影效果 */ + transform: translateY(-10px); /* 向上移动10像素 */ + } + } + } + } + + + .el-image { + width 100% + height 100% + overflow visible + + .el-image-viewer__wrapper { + img { + width auto + height auto + } + } + + .image-slot { + display flex + flex-flow column + justify-content center + align-items center + min-height 220px + color #ffffff + + .err-msg-container { + overflow hidden + word-break break-all + padding 15px + .title { + font-size 20px + text-align center + font-weight bold + color #f56c6c + margin-bottom 30px + } + + .opt { + display flex + justify-content center + } + } + .iconfont { + font-size 50px + margin-bottom 10px + } + + + } + } + + .el-image.upscale { + img { + height 310px + } + + .image-slot { + height 310px + } + + .el-image-viewer__wrapper { + img { + width auto + height auto + } + } + } +} \ No newline at end of file diff --git a/web/src/views/ChatPlus.vue b/web/src/views/ChatPlus.vue index 80769552..c895be3f 100644 --- a/web/src/views/ChatPlus.vue +++ b/web/src/views/ChatPlus.vue @@ -367,7 +367,6 @@ const initData = () => { inputRef.value.addEventListener('paste', (event) => { const items = (event.clipboardData || window.clipboardData).items; let fileFound = false; - loading.value = true for (let item of items) { if (item.kind === 'file') { @@ -376,6 +375,7 @@ const initData = () => { const formData = new FormData(); formData.append('file', file); + loading.value = true // 执行上传操作 httpPost('/api/upload', formData).then((res) => { files.value.push(res.data) @@ -389,7 +389,7 @@ const initData = () => { break; } } - + if (!fileFound) { document.getElementById('status').innerText = 'No file found in paste data.'; } diff --git a/web/src/views/Dalle.vue b/web/src/views/Dalle.vue index fb243a3d..e610522b 100644 --- a/web/src/views/Dalle.vue +++ b/web/src/views/Dalle.vue @@ -125,6 +125,24 @@ + + + + - - \ No newline at end of file diff --git a/web/src/views/admin/ApiKey.vue b/web/src/views/admin/ApiKey.vue index 1829b356..95ae5e13 100644 --- a/web/src/views/admin/ApiKey.vue +++ b/web/src/views/admin/ApiKey.vue @@ -139,6 +139,7 @@ const title = ref("") const types = ref([ {label: "对话", value:"chat"}, {label: "Midjourney", value:"mj"}, + {label: "Stable-Diffusion", value:"sd"}, {label: "DALL-E", value:"dalle"}, {label: "Suno文生歌", value:"suno"}, {label: "Luma视频", value:"luma"}, diff --git a/web/src/views/admin/ChatList.vue b/web/src/views/admin/ChatList.vue index 7d8fbd29..971cbd23 100644 --- a/web/src/views/admin/ChatList.vue +++ b/web/src/views/admin/ChatList.vue @@ -157,11 +157,7 @@
+ :data="item"/> @@ -288,33 +284,11 @@ const removeMessage = function (row) { }) } -const mathjaxPlugin = require('markdown-it-mathjax3') -const md = require('markdown-it')({ - breaks: true, - html: true, - linkify: true, - typographer: true, - highlight: function (str, lang) { - if (lang && hl.getLanguage(lang)) { - // 处理代码高亮 - const preCode = hl.highlight(lang, str, true).value - // 将代码包裹在 pre 中 - return `
${preCode}
` - } - - // 处理代码高亮 - const preCode = md.utils.escapeHtml(str) - // 将代码包裹在 pre 中 - return `
${preCode}
` - } -}); -md.use(mathjaxPlugin) - const showContentDialog = ref(false) const dialogContent = ref("") const showContent = (content) => { showContentDialog.value = true - dialogContent.value = md.render(processContent(content)) + dialogContent.value = processContent(content) } const showChatItemDialog = ref(false) @@ -325,8 +299,6 @@ const showMessages = (row) => { httpGet('/api/admin/chat/history?chat_id=' + row.chat_id).then(res => { const data = res.data for (let i = 0; i < data.length; i++) { - data[i].orgContent = data[i].content; - data[i].content = md.render(processContent(data[i].content)) messages.value.push(data[i]); } }).catch(e => { diff --git a/web/src/views/admin/SysConfig.vue b/web/src/views/admin/SysConfig.vue index 6f43d6d3..c49d070d 100644 --- a/web/src/views/admin/SysConfig.vue +++ b/web/src/views/admin/SysConfig.vue @@ -194,6 +194,15 @@
+ + + + {{ + item.name + }} + + + @@ -359,10 +368,6 @@ - - - -
{ // 加载系统配置 @@ -461,7 +469,6 @@ onMounted(() => { httpGet('/api/admin/model/list').then(res => { models.value = res.data - openAIModels.value = models.value.filter(v => v.platform === "OpenAI") loading.value = false }).catch(e => { ElMessage.error("获取模型失败:" + e.message) From 1d0006ce59881d3f47c7631c512b1a335804473d Mon Sep 17 00:00:00 2001 From: RockYang Date: Wed, 7 Aug 2024 17:30:59 +0800 Subject: [PATCH 08/15] refactor stable diffusion service, use api key instead of configs --- api/core/types/config.go | 38 ++---- api/handler/admin/config_handler.go | 5 +- api/handler/sd_handler.go | 22 +--- api/main.go | 12 +- api/service/mj/client.go | 19 +-- api/service/sd/pool.go | 128 -------------------- api/service/sd/service.go | 177 ++++++++++++++++++---------- 7 files changed, 139 insertions(+), 262 deletions(-) delete mode 100644 api/service/sd/pool.go diff --git a/api/core/types/config.go b/api/core/types/config.go index 984a6982..a9d8ea4c 100644 --- a/api/core/types/config.go +++ b/api/core/types/config.go @@ -17,15 +17,14 @@ type AppConfig struct { Session Session AdminSession Session ProxyURL string - MysqlDns string // mysql 连接地址 - StaticDir string // 静态资源目录 - StaticUrl string // 静态资源 URL - Redis RedisConfig // redis 连接信息 - ApiConfig ApiConfig // ChatPlus API authorization configs - SMS SMSConfig // send mobile message config - OSS OSSConfig // OSS config - WeChatBot bool // 是否启用微信机器人 - SdConfigs []StableDiffusionConfig // sd AI draw service pool + MysqlDns string // mysql 连接地址 + StaticDir string // 静态资源目录 + StaticUrl string // 静态资源 URL + Redis RedisConfig // redis 连接信息 + ApiConfig ApiConfig // ChatPlus API authorization configs + SMS SMSConfig // send mobile message config + OSS OSSConfig // OSS config + WeChatBot bool // 是否启用微信机器人 XXLConfig XXLConfig AlipayConfig AlipayConfig // 支付宝支付渠道配置 @@ -51,27 +50,6 @@ type ApiConfig struct { Token string } -type MjProxyConfig struct { - Enabled bool - ApiURL string // api 地址 - Mode string // 绘画模式,可选值:fast/turbo/relax - ApiKey string -} - -type StableDiffusionConfig struct { - Enabled bool - Model string // 模型名称 - ApiURL string - ApiKey string -} - -type MjPlusConfig struct { - Enabled bool // 如果启用了 MidJourney Plus,将会自动禁用原生的MidJourney服务 - ApiURL string // api 地址 - Mode string // 绘画模式,可选值:fast/turbo/relax - ApiKey string -} - type AlipayConfig struct { Enabled bool // 是否启用该支付通道 SandBox bool // 是否沙盒环境 diff --git a/api/handler/admin/config_handler.go b/api/handler/admin/config_handler.go index b3d22705..4a6aa690 100644 --- a/api/handler/admin/config_handler.go +++ b/api/handler/admin/config_handler.go @@ -12,7 +12,6 @@ import ( "geekai/core/types" "geekai/handler" "geekai/service" - "geekai/service/sd" "geekai/store" "geekai/store/model" "geekai/utils" @@ -27,14 +26,12 @@ type ConfigHandler struct { handler.BaseHandler levelDB *store.LevelDB licenseService *service.LicenseService - sdServicePool *sd.ServicePool } -func NewConfigHandler(app *core.AppServer, db *gorm.DB, levelDB *store.LevelDB, licenseService *service.LicenseService, sdPool *sd.ServicePool) *ConfigHandler { +func NewConfigHandler(app *core.AppServer, db *gorm.DB, levelDB *store.LevelDB, licenseService *service.LicenseService) *ConfigHandler { return &ConfigHandler{ BaseHandler: handler.BaseHandler{App: app, DB: db}, levelDB: levelDB, - sdServicePool: sdPool, licenseService: licenseService, } } diff --git a/api/handler/sd_handler.go b/api/handler/sd_handler.go index ff5320ef..a9ff01c5 100644 --- a/api/handler/sd_handler.go +++ b/api/handler/sd_handler.go @@ -32,15 +32,15 @@ import ( type SdJobHandler struct { BaseHandler redis *redis.Client - pool *sd.ServicePool + service *sd.Service uploader *oss.UploaderManager snowflake *service.Snowflake leveldb *store.LevelDB } -func NewSdJobHandler(app *core.AppServer, db *gorm.DB, pool *sd.ServicePool, manager *oss.UploaderManager, snowflake *service.Snowflake, levelDB *store.LevelDB) *SdJobHandler { +func NewSdJobHandler(app *core.AppServer, db *gorm.DB, service *sd.Service, manager *oss.UploaderManager, snowflake *service.Snowflake, levelDB *store.LevelDB) *SdJobHandler { return &SdJobHandler{ - pool: pool, + service: service, uploader: manager, snowflake: snowflake, leveldb: levelDB, @@ -68,7 +68,7 @@ func (h *SdJobHandler) Client(c *gin.Context) { } client := types.NewWsClient(ws) - h.pool.Clients.Put(uint(userId), client) + h.service.Clients.Put(uint(userId), client) logger.Infof("New websocket connected, IP: %s", c.RemoteIP()) } @@ -79,11 +79,6 @@ func (h *SdJobHandler) preCheck(c *gin.Context) bool { return false } - if !h.pool.HasAvailableService() { - resp.ERROR(c, "Stable-Diffusion 池子中没有没有可用的服务!") - return false - } - if user.Power < h.App.SysConfig.SdPower { resp.ERROR(c, "当前用户剩余算力不足以完成本次绘画!") return false @@ -164,14 +159,14 @@ func (h *SdJobHandler) Image(c *gin.Context) { return } - h.pool.PushTask(types.SdTask{ + h.service.PushTask(types.SdTask{ Id: int(job.Id), Type: types.TaskImage, Params: params, UserId: userId, }) - client := h.pool.Clients.Get(uint(job.UserId)) + client := h.service.Clients.Get(uint(job.UserId)) if client != nil { _ = client.Send([]byte("Task Updated")) } @@ -328,11 +323,6 @@ func (h *SdJobHandler) Remove(c *gin.Context) { logger.Error("remove image failed: ", err) } - client := h.pool.Clients.Get(uint(job.UserId)) - if client != nil { - _ = client.Send([]byte(service.TaskStatusFinished)) - } - resp.SUCCESS(c) } diff --git a/api/main.go b/api/main.go index 287c6c07..26ca6fed 100644 --- a/api/main.go +++ b/api/main.go @@ -199,13 +199,11 @@ func main() { }), // Stable Diffusion 机器人 - fx.Provide(sd.NewServicePool), - fx.Invoke(func(pool *sd.ServicePool, config *types.AppConfig) { - pool.InitServices(config.SdConfigs) - if pool.HasAvailableService() { - pool.CheckTaskNotify() - pool.CheckTaskStatus() - } + fx.Provide(sd.NewService), + fx.Invoke(func(s *sd.Service, config *types.AppConfig) { + s.Run() + s.CheckTaskStatus() + s.CheckTaskNotify() }), fx.Provide(suno.NewService), diff --git a/api/service/mj/client.go b/api/service/mj/client.go index 450b7d8b..35ed807a 100644 --- a/api/service/mj/client.go +++ b/api/service/mj/client.go @@ -50,12 +50,6 @@ type ImageRes struct { Channel string `json:"channel,omitempty"` } -type ErrRes struct { - Error struct { - Message string `json:"message"` - } `json:"error"` -} - type QueryRes struct { Action string `json:"action"` Buttons []struct { @@ -193,7 +187,6 @@ func (c *Client) Variation(task types.MjTask) (ImageRes, error) { func (c *Client) doRequest(body interface{}, apiPath string, channel string) (ImageRes, error) { var res ImageRes - var errRes ErrRes session := c.db.Session(&gorm.Session{}).Where("type", "mj").Where("enabled", true) if channel != "" { session = session.Where("api_url", channel) @@ -215,20 +208,14 @@ func (c *Client) doRequest(body interface{}, apiPath string, channel string) (Im SetHeader("Authorization", "Bearer "+apiKey.Value). SetBody(body). SetSuccessResult(&res). - SetErrorResult(&errRes). Post(apiURL) if err != nil { - errMsg := err.Error() - if r != nil { - errStr, _ := io.ReadAll(r.Body) - logger.Error("请求 API 出错:", string(errStr)) - errMsg = errMsg + " " + string(errStr) - } - return ImageRes{}, fmt.Errorf("请求 API 出错:%v", errMsg) + return ImageRes{}, fmt.Errorf("请求 API 出错:%v", err) } if r.IsErrorState() { - return ImageRes{}, fmt.Errorf("API 返回错误:%s", errRes.Error.Message) + errMsg, _ := io.ReadAll(r.Body) + return ImageRes{}, fmt.Errorf("API 返回错误:%s", string(errMsg)) } // update the api key last used time diff --git a/api/service/sd/pool.go b/api/service/sd/pool.go deleted file mode 100644 index d0033f67..00000000 --- a/api/service/sd/pool.go +++ /dev/null @@ -1,128 +0,0 @@ -package sd - -// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -// * Copyright 2023 The Geek-AI Authors. All rights reserved. -// * Use of this source code is governed by a Apache-2.0 license -// * that can be found in the LICENSE file. -// * @Author yangjian102621@163.com -// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -import ( - "fmt" - "geekai/core/types" - "geekai/service" - "geekai/service/oss" - "geekai/store" - "geekai/store/model" - "time" - - "github.com/go-redis/redis/v8" - "gorm.io/gorm" -) - -type ServicePool struct { - services []*Service - taskQueue *store.RedisQueue - notifyQueue *store.RedisQueue - db *gorm.DB - Clients *types.LMap[uint, *types.WsClient] // UserId => Client - uploader *oss.UploaderManager - levelDB *store.LevelDB -} - -func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager, levelDB *store.LevelDB) *ServicePool { - services := make([]*Service, 0) - taskQueue := store.NewRedisQueue("StableDiffusion_Task_Queue", redisCli) - notifyQueue := store.NewRedisQueue("StableDiffusion_Queue", redisCli) - - return &ServicePool{ - taskQueue: taskQueue, - notifyQueue: notifyQueue, - services: services, - db: db, - Clients: types.NewLMap[uint, *types.WsClient](), - uploader: manager, - levelDB: levelDB, - } -} - -func (p *ServicePool) InitServices(configs []types.StableDiffusionConfig) { - // stop old service - for _, s := range p.services { - s.Stop() - } - p.services = make([]*Service, 0) - - for k, config := range configs { - if config.Enabled == false { - continue - } - - // create sd service - name := fmt.Sprintf(" sd-service-%d", k) - service := NewService(name, config, p.taskQueue, p.notifyQueue, p.db, p.uploader, p.levelDB) - // run sd service - go func() { - service.Run() - }() - - p.services = append(p.services, service) - } -} - -// PushTask push a new mj task in to task queue -func (p *ServicePool) PushTask(task types.SdTask) { - logger.Debugf("add a new MidJourney task to the task list: %+v", task) - p.taskQueue.RPush(task) -} - -func (p *ServicePool) CheckTaskNotify() { - go func() { - logger.Info("Running Stable-Diffusion task notify checking ...") - for { - var message service.NotifyMessage - err := p.notifyQueue.LPop(&message) - if err != nil { - continue - } - client := p.Clients.Get(uint(message.UserId)) - if client == nil { - continue - } - err = client.Send([]byte(message.Message)) - if err != nil { - continue - } - } - }() -} - -// CheckTaskStatus 检查任务状态,自动删除过期或者失败的任务 -func (p *ServicePool) CheckTaskStatus() { - go func() { - logger.Info("Running Stable-Diffusion task status checking ...") - for { - var jobs []model.SdJob - res := p.db.Where("progress < ?", 100).Find(&jobs) - if res.Error != nil { - time.Sleep(5 * time.Second) - continue - } - - for _, job := range jobs { - // 5 分钟还没完成的任务标记为失败 - if time.Now().Sub(job.CreatedAt) > time.Minute*5 { - job.Progress = 101 - job.ErrMsg = "任务超时" - p.db.Updates(&job) - } - } - time.Sleep(time.Second * 5) - } - }() -} - -// HasAvailableService check if it has available mj service in pool -func (p *ServicePool) HasAvailableService() bool { - return len(p.services) > 0 -} diff --git a/api/service/sd/service.go b/api/service/sd/service.go index d3b6c231..a6c9a856 100644 --- a/api/service/sd/service.go +++ b/api/service/sd/service.go @@ -16,7 +16,7 @@ import ( "geekai/store" "geekai/store/model" "geekai/utils" - "strings" + "github.com/go-redis/redis/v8" "time" "github.com/imroc/req/v3" @@ -29,79 +29,72 @@ var logger = logger2.GetLogger() type Service struct { httpClient *req.Client - config types.StableDiffusionConfig taskQueue *store.RedisQueue notifyQueue *store.RedisQueue db *gorm.DB uploadManager *oss.UploaderManager - name string // service name leveldb *store.LevelDB - running bool // 运行状态 + Clients *types.LMap[uint, *types.WsClient] // UserId => Client } -func NewService(name string, config types.StableDiffusionConfig, taskQueue *store.RedisQueue, notifyQueue *store.RedisQueue, db *gorm.DB, manager *oss.UploaderManager, levelDB *store.LevelDB) *Service { - config.ApiURL = strings.TrimRight(config.ApiURL, "/") +func NewService(db *gorm.DB, manager *oss.UploaderManager, levelDB *store.LevelDB, redisCli *redis.Client) *Service { return &Service{ - name: name, - config: config, httpClient: req.C(), - taskQueue: taskQueue, - notifyQueue: notifyQueue, + taskQueue: store.NewRedisQueue("StableDiffusion_Task_Queue", redisCli), + notifyQueue: store.NewRedisQueue("StableDiffusion_Queue", redisCli), db: db, leveldb: levelDB, + Clients: types.NewLMap[uint, *types.WsClient](), uploadManager: manager, - running: true, } } func (s *Service) Run() { - logger.Infof("Starting Stable-Diffusion job consumer for %s", s.name) - for s.running { - var task types.SdTask - err := s.taskQueue.LPop(&task) - if err != nil { - logger.Errorf("taking task with error: %v", err) - continue - } + logger.Infof("Starting Stable-Diffusion job consumer") + go func() { + for { + var task types.SdTask + err := s.taskQueue.LPop(&task) + if err != nil { + logger.Errorf("taking task with error: %v", err) + continue + } - // translate prompt - if utils.HasChinese(task.Params.Prompt) { - content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.RewritePromptTemplate, task.Params.Prompt), "gpt-4o-mini") - if err == nil { - task.Params.Prompt = content - } else { - logger.Warnf("error with translate prompt: %v", err) + // translate prompt + if utils.HasChinese(task.Params.Prompt) { + content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.RewritePromptTemplate, task.Params.Prompt), "gpt-4o-mini") + if err == nil { + task.Params.Prompt = content + } else { + logger.Warnf("error with translate prompt: %v", err) + } + } + + // translate negative prompt + if task.Params.NegPrompt != "" && utils.HasChinese(task.Params.NegPrompt) { + content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.TranslatePromptTemplate, task.Params.NegPrompt), "gpt-4o-mini") + if err == nil { + task.Params.NegPrompt = content + } else { + logger.Warnf("error with translate prompt: %v", err) + } + } + + logger.Infof("handle a new Stable-Diffusion task: %+v", task) + err = s.Txt2Img(task) + if err != nil { + logger.Error("绘画任务执行失败:", err.Error()) + // update the task progress + s.db.Model(&model.SdJob{Id: uint(task.Id)}).UpdateColumns(map[string]interface{}{ + "progress": service.FailTaskProgress, + "err_msg": err.Error(), + }) + // 通知前端,任务失败 + s.notifyQueue.RPush(service.NotifyMessage{UserId: task.UserId, JobId: task.Id, Message: service.TaskStatusFailed}) + continue } } - - // translate negative prompt - if task.Params.NegPrompt != "" && utils.HasChinese(task.Params.NegPrompt) { - content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.TranslatePromptTemplate, task.Params.NegPrompt), "gpt-4o-mini") - if err == nil { - task.Params.NegPrompt = content - } else { - logger.Warnf("error with translate prompt: %v", err) - } - } - - logger.Infof("%s handle a new Stable-Diffusion task: %+v", s.name, task) - err = s.Txt2Img(task) - if err != nil { - logger.Error("绘画任务执行失败:", err.Error()) - // update the task progress - s.db.Model(&model.SdJob{Id: uint(task.Id)}).UpdateColumns(map[string]interface{}{ - "progress": service.FailTaskProgress, - "err_msg": err.Error(), - }) - // 通知前端,任务失败 - s.notifyQueue.RPush(service.NotifyMessage{UserId: task.UserId, JobId: task.Id, Message: service.TaskStatusFailed}) - continue - } - } -} - -func (s *Service) Stop() { - s.running = false + }() } // Txt2ImgReq 文生图请求实体 @@ -163,12 +156,19 @@ func (s *Service) Txt2Img(task types.SdTask) error { } var res Txt2ImgResp var errChan = make(chan error) - apiURL := fmt.Sprintf("%s/sdapi/v1/txt2img", s.config.ApiURL) + + var apiKey model.ApiKey + err := s.db.Where("type", "sd").Where("enabled", true).Order("last_used_at ASC").First(&apiKey).Error + if err != nil { + return fmt.Errorf("no available Stable-Diffusion api key: %v", err) + } + + apiURL := fmt.Sprintf("%s/sdapi/v1/txt2img", apiKey.ApiURL) logger.Debugf("send image request to %s", apiURL) // send a request to sd api endpoint go func() { response, err := s.httpClient.R(). - SetHeader("Authorization", s.config.ApiKey). + SetHeader("Authorization", apiKey.Value). SetBody(body). SetSuccessResult(&res). Post(apiURL) @@ -181,6 +181,10 @@ func (s *Service) Txt2Img(task types.SdTask) error { return } + // update the last used time + apiKey.LastUsedAt = time.Now().Unix() + s.db.Updates(&apiKey) + // 保存 Base64 图片 imgURL, err := s.uploadManager.GetUploadHandler().PutBase64(res.Images[0]) if err != nil { @@ -214,7 +218,7 @@ func (s *Service) Txt2Img(task types.SdTask) error { _ = s.leveldb.Delete(task.Params.TaskId) return nil default: - err, resp := s.checkTaskProgress() + err, resp := s.checkTaskProgress(apiKey) // 更新任务进度 if err == nil && resp.Progress > 0 { s.db.Model(&model.SdJob{Id: uint(task.Id)}).UpdateColumn("progress", int(resp.Progress*100)) @@ -232,11 +236,11 @@ func (s *Service) Txt2Img(task types.SdTask) error { } // 执行任务 -func (s *Service) checkTaskProgress() (error, *TaskProgressResp) { - apiURL := fmt.Sprintf("%s/sdapi/v1/progress?skip_current_image=false", s.config.ApiURL) +func (s *Service) checkTaskProgress(apiKey model.ApiKey) (error, *TaskProgressResp) { + apiURL := fmt.Sprintf("%s/sdapi/v1/progress?skip_current_image=false", apiKey.ApiURL) var res TaskProgressResp response, err := s.httpClient.R(). - SetHeader("Authorization", s.config.ApiKey). + SetHeader("Authorization", apiKey.Value). SetSuccessResult(&res). Get(apiURL) if err != nil { @@ -248,3 +252,54 @@ func (s *Service) checkTaskProgress() (error, *TaskProgressResp) { return nil, &res } + +func (s *Service) PushTask(task types.SdTask) { + logger.Debugf("add a new MidJourney task to the task list: %+v", task) + s.taskQueue.RPush(task) +} + +func (s *Service) CheckTaskNotify() { + go func() { + logger.Info("Running Stable-Diffusion task notify checking ...") + for { + var message service.NotifyMessage + err := s.notifyQueue.LPop(&message) + if err != nil { + continue + } + client := s.Clients.Get(uint(message.UserId)) + if client == nil { + continue + } + err = client.Send([]byte(message.Message)) + if err != nil { + continue + } + } + }() +} + +// CheckTaskStatus 检查任务状态,自动删除过期或者失败的任务 +func (s *Service) CheckTaskStatus() { + go func() { + logger.Info("Running Stable-Diffusion task status checking ...") + for { + var jobs []model.SdJob + res := s.db.Where("progress < ?", 100).Find(&jobs) + if res.Error != nil { + time.Sleep(5 * time.Second) + continue + } + + for _, job := range jobs { + // 5 分钟还没完成的任务标记为失败 + if time.Now().Sub(job.CreatedAt) > time.Minute*5 { + job.Progress = service.FailTaskProgress + job.ErrMsg = "任务超时" + s.db.Updates(&job) + } + } + time.Sleep(time.Second * 5) + } + }() +} From 167c59a1597f02f253373d697045e49cd07aab91 Mon Sep 17 00:00:00 2001 From: RockYang Date: Wed, 7 Aug 2024 18:00:28 +0800 Subject: [PATCH 09/15] add clear unpaid order functions --- CHANGELOG.md | 1 + api/handler/admin/order_handler.go | 12 +++++++++++- api/main.go | 1 + web/src/views/admin/Order.vue | 23 +++++++++++++++++++++-- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f898a32..d0cad4cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Bug修复:修复后台拖动排序组件 Bug * 功能优化:更新数据库失败时候显示具体的的报错信息 * Bug修复:修复管理后台对话详情页内容显示异常问题 +* 功能优化:管理后台新增清空所有未支付订单的功能 ## v4.1.1 * Bug修复:修复 GPT 模型 function call 调用后没有输出的问题 diff --git a/api/handler/admin/order_handler.go b/api/handler/admin/order_handler.go index 4db6c4a6..510255f4 100644 --- a/api/handler/admin/order_handler.go +++ b/api/handler/admin/order_handler.go @@ -93,10 +93,20 @@ func (h *OrderHandler) Remove(c *gin.Context) { } err := h.DB.Unscoped().Where("id = ?", id).Delete(&model.Order{}).Error - if res.Error != nil { + if err != nil { resp.ERROR(c, err.Error()) return } } resp.SUCCESS(c) } + +func (h *OrderHandler) Clear(c *gin.Context) { + + err := h.DB.Unscoped().Where("status <> ?", 2).Where("pay_time", 0).Delete(&model.Order{}).Error + if err != nil { + resp.ERROR(c, err.Error()) + return + } + resp.SUCCESS(c) +} diff --git a/api/main.go b/api/main.go index 26ca6fed..d91c892f 100644 --- a/api/main.go +++ b/api/main.go @@ -392,6 +392,7 @@ func main() { group := s.Engine.Group("/api/admin/order/") group.POST("list", h.List) group.GET("remove", h.Remove) + group.GET("clear", h.Clear) }), fx.Invoke(func(s *core.AppServer, h *handler.OrderHandler) { group := s.Engine.Group("/api/order/") diff --git a/web/src/views/admin/Order.vue b/web/src/views/admin/Order.vue index a633c218..dd6230c3 100644 --- a/web/src/views/admin/Order.vue +++ b/web/src/views/admin/Order.vue @@ -20,6 +20,7 @@ style="margin: 0 10px;width: 200px; position: relative;top:3px;" /> 搜索 + 清空未支付订单
@@ -76,9 +77,9 @@ \ No newline at end of file diff --git a/web/src/views/admin/Reward.vue b/web/src/views/admin/Reward.vue deleted file mode 100644 index f6cb4069..00000000 --- a/web/src/views/admin/Reward.vue +++ /dev/null @@ -1,115 +0,0 @@ - - - - - \ No newline at end of file From 67c7132e6b4f3d1fa03def2a474e13c1fea00396 Mon Sep 17 00:00:00 2001 From: RockYang Date: Fri, 9 Aug 2024 18:19:51 +0800 Subject: [PATCH 12/15] redeem code function is ready --- api/config.sample.toml | 8 - api/core/types/chat.go | 6 +- api/go.mod | 3 - api/go.sum | 8 - api/handler/dalle_handler.go | 4 +- api/handler/mj_handler.go | 4 +- api/handler/redeem_handler.go | 4 +- api/handler/sd_handler.go | 4 +- api/handler/suno_handler.go | 5 +- api/handler/test_handler.go | 37 + api/main.go | 5 + database/chatgpt_plus-v4.1.2.sql | 882 ++++++++++++++++++ deploy/conf/config.toml | 7 - deploy/docker-compose.yaml | 4 +- .../{RewardVerify.vue => RedeemVerify.vue} | 31 +- web/src/views/Member.vue | 41 +- web/src/views/Test.vue | 43 +- web/src/views/admin/Redeem.vue | 6 +- 18 files changed, 979 insertions(+), 123 deletions(-) create mode 100644 database/chatgpt_plus-v4.1.2.sql rename web/src/components/{RewardVerify.vue => RedeemVerify.vue} (54%) diff --git a/api/config.sample.toml b/api/config.sample.toml index a52f1023..bfaf4256 100644 --- a/api/config.sample.toml +++ b/api/config.sample.toml @@ -3,8 +3,6 @@ ProxyURL = "" # 如 http://127.0.0.1:7777 MysqlDns = "root:12345678@tcp(172.22.11.200:3307)/chatgpt_plus?charset=utf8mb4&collation=utf8mb4_unicode_ci&parseTime=True&loc=Local" StaticDir = "./static" # 静态资源的目录 StaticUrl = "/static" # 静态资源访问 URL -AesEncryptKey = "" -WeChatBot = false TikaHost = "http://tika:9998" [Session] @@ -64,12 +62,6 @@ TikaHost = "http://tika:9998" Bucket = "chatgpt-plus" SubDir = "" Domain = "" - -[[SdConfigs]] - Enabled = false - ApiURL = "" - ApiKey = "" - Txt2ImgJsonPath = "res/sd/text2img.json" [XXLConfig] # xxl-job 配置,需要你部署 XXL-JOB 定时任务工具,用来定期清理未支付订单和清理过期 VIP,如果你没有启用支付服务,则该服务也无需启动 Enabled = false # 是否启用 XXL JOB 服务 diff --git a/api/core/types/chat.go b/api/core/types/chat.go index ccaf0a9c..9464ec8b 100644 --- a/api/core/types/chat.go +++ b/api/core/types/chat.go @@ -90,7 +90,7 @@ const ( PowerConsume = PowerType(2) // 消费 PowerRefund = PowerType(3) // 任务(SD,MJ)执行失败,退款 PowerInvite = PowerType(4) // 邀请奖励 - PowerReward = PowerType(5) // 众筹 + PowerRedeem = PowerType(5) // 众筹 PowerGift = PowerType(6) // 系统赠送 ) @@ -102,8 +102,8 @@ func (t PowerType) String() string { return "消费" case PowerRefund: return "退款" - case PowerReward: - return "众筹" + case PowerRedeem: + return "兑换" } return "其他" diff --git a/api/go.mod b/api/go.mod index 2a8efd45..3ce807f6 100644 --- a/api/go.mod +++ b/api/go.mod @@ -8,7 +8,6 @@ require ( github.com/BurntSushi/toml v1.1.0 github.com/aliyun/alibaba-cloud-sdk-go v1.62.405 github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible - github.com/eatmoreapple/openwechat v1.2.1 github.com/gin-gonic/gin v1.9.1 github.com/go-redis/redis/v8 v8.11.5 github.com/golang-jwt/jwt/v5 v5.0.0 @@ -30,7 +29,6 @@ require ( github.com/go-pay/gopay v1.5.101 github.com/google/go-tika v0.3.1 github.com/microcosm-cc/bluemonday v1.0.26 - github.com/mojocn/base64Captcha v1.3.6 github.com/shirou/gopsutil v3.21.11+incompatible github.com/shopspring/decimal v1.3.1 github.com/syndtr/goleveldb v1.0.0 @@ -45,7 +43,6 @@ require ( github.com/go-pay/util v0.0.2 // indirect github.com/go-pay/xlog v0.0.2 // indirect github.com/go-pay/xtime v0.0.2 // indirect - github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect github.com/gorilla/css v1.0.0 // indirect github.com/tklauser/go-sysconf v0.3.13 // indirect diff --git a/api/go.sum b/api/go.sum index c0179e87..f3f6eef9 100644 --- a/api/go.sum +++ b/api/go.sum @@ -28,8 +28,6 @@ github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0 github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/eatmoreapple/openwechat v1.2.1 h1:ez4oqF/Y2NSEX/DbPV8lvj7JlfkYqvieeo4awx5lzfU= -github.com/eatmoreapple/openwechat v1.2.1/go.mod h1:61HOzTyvLobGdgWhL68jfGNwTJEv0mhQ1miCXQrvWU8= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -84,8 +82,6 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -157,8 +153,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mojocn/base64Captcha v1.3.6 h1:gZEKu1nsKpttuIAQgWHO+4Mhhls8cAKyiV2Ew03H+Tw= -github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -265,7 +259,6 @@ golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -321,7 +314,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= diff --git a/api/handler/dalle_handler.go b/api/handler/dalle_handler.go index 9f6ad7b1..d09f0651 100644 --- a/api/handler/dalle_handler.go +++ b/api/handler/dalle_handler.go @@ -241,11 +241,11 @@ func (h *DallJobHandler) Remove(c *gin.Context) { } var user model.User - h.DB.Where("id = ?", job.UserId).First(&user) + tx.Where("id = ?", job.UserId).First(&user) err = tx.Create(&model.PowerLog{ UserId: user.Id, Username: user.Username, - Type: types.PowerConsume, + Type: types.PowerRefund, Amount: job.Power, Balance: user.Power, Mark: types.PowerAdd, diff --git a/api/handler/mj_handler.go b/api/handler/mj_handler.go index c3cd14d0..212729b2 100644 --- a/api/handler/mj_handler.go +++ b/api/handler/mj_handler.go @@ -472,11 +472,11 @@ func (h *MidJourneyHandler) Remove(c *gin.Context) { return } var user model.User - h.DB.Where("id = ?", job.UserId).First(&user) + tx.Where("id = ?", job.UserId).First(&user) err = tx.Create(&model.PowerLog{ UserId: user.Id, Username: user.Username, - Type: types.PowerConsume, + Type: types.PowerRefund, Amount: job.Power, Balance: user.Power, Mark: types.PowerAdd, diff --git a/api/handler/redeem_handler.go b/api/handler/redeem_handler.go index ba1fb4ed..4f557ce9 100644 --- a/api/handler/redeem_handler.go +++ b/api/handler/redeem_handler.go @@ -78,7 +78,7 @@ func (h *RedeemHandler) Verify(c *gin.Context) { // 记录算力充值日志 var user model.User - err = h.DB.Where("id", userId).First(&user).Error + err = tx.Where("id", userId).First(&user).Error if err != nil { tx.Rollback() resp.ERROR(c, err.Error()) @@ -88,7 +88,7 @@ func (h *RedeemHandler) Verify(c *gin.Context) { h.DB.Create(&model.PowerLog{ UserId: userId, Username: user.Username, - Type: types.PowerReward, + Type: types.PowerRedeem, Amount: item.Power, Balance: user.Power, Mark: types.PowerAdd, diff --git a/api/handler/sd_handler.go b/api/handler/sd_handler.go index a9ff01c5..9cbc60fb 100644 --- a/api/handler/sd_handler.go +++ b/api/handler/sd_handler.go @@ -297,11 +297,11 @@ func (h *SdJobHandler) Remove(c *gin.Context) { return } var user model.User - h.DB.Where("id = ?", job.UserId).First(&user) + tx.Where("id = ?", job.UserId).First(&user) err = tx.Create(&model.PowerLog{ UserId: user.Id, Username: user.Username, - Type: types.PowerConsume, + Type: types.PowerRefund, Amount: job.Power, Balance: user.Power, Mark: types.PowerAdd, diff --git a/api/handler/suno_handler.go b/api/handler/suno_handler.go index b2fba821..2ceed2c1 100644 --- a/api/handler/suno_handler.go +++ b/api/handler/suno_handler.go @@ -94,6 +94,7 @@ func (h *SunoHandler) Create(c *gin.Context) { RefTaskId: data.RefTaskId, ExtendSecs: data.ExtendSecs, Power: h.App.SysConfig.SunoPower, + SongId: utils.RandString(32), } if data.Lyrics != "" { job.Prompt = data.Lyrics @@ -226,11 +227,11 @@ func (h *SunoHandler) Remove(c *gin.Context) { return } var user model.User - h.DB.Where("id = ?", job.UserId).First(&user) + tx.Where("id = ?", job.UserId).First(&user) err = tx.Create(&model.PowerLog{ UserId: user.Id, Username: user.Username, - Type: types.PowerConsume, + Type: types.PowerRefund, Amount: job.Power, Balance: user.Power, Mark: types.PowerAdd, diff --git a/api/handler/test_handler.go b/api/handler/test_handler.go index eb5b7107..fe38bc38 100644 --- a/api/handler/test_handler.go +++ b/api/handler/test_handler.go @@ -3,7 +3,9 @@ package handler import ( "geekai/service" "geekai/service/payment" + "github.com/gin-gonic/gin" "gorm.io/gorm" + "net/http" ) type TestHandler struct { @@ -15,3 +17,38 @@ type TestHandler struct { func NewTestHandler(db *gorm.DB, snowflake *service.Snowflake, js *payment.JPayService) *TestHandler { return &TestHandler{db: db, snowflake: snowflake, js: js} } + +func (h *TestHandler) SseTest(c *gin.Context) { + //c.Header("Content-Type", "text/event-stream") + //c.Header("Cache-Control", "no-cache") + //c.Header("Connection", "keep-alive") + // + // + //// 模拟实时数据更新 + //for i := 0; i < 10; i++ { + // // 发送 SSE 数据 + // _, err := fmt.Fprintf(c.Writer, "data: %v\n\n", data) + // if err != nil { + // return + // } + // c.Writer.Flush() // 确保立即发送数据 + // time.Sleep(1 * time.Second) // 每秒发送一次数据 + //} + //c.Abort() +} + +func (h *TestHandler) PostTest(c *gin.Context) { + var data struct { + Message string `json:"message"` + UserId uint `json:"user_id"` + } + + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + // 将参数存储在上下文中 + c.Set("data", data) + c.Next() +} diff --git a/api/main.go b/api/main.go index f8ed1b5e..ead2032b 100644 --- a/api/main.go +++ b/api/main.go @@ -482,6 +482,11 @@ func main() { group.GET("play", h.Play) group.POST("lyric", h.Lyric) }), + fx.Provide(handler.NewTestHandler), + fx.Invoke(func(s *core.AppServer, h *handler.TestHandler) { + group := s.Engine.Group("/api/test") + group.Any("sse", h.PostTest, h.SseTest) + }), fx.Invoke(func(s *core.AppServer, db *gorm.DB) { go func() { err := s.Run(db) diff --git a/database/chatgpt_plus-v4.1.2.sql b/database/chatgpt_plus-v4.1.2.sql new file mode 100644 index 00000000..e48f0559 --- /dev/null +++ b/database/chatgpt_plus-v4.1.2.sql @@ -0,0 +1,882 @@ +-- phpMyAdmin SQL Dump +-- version 5.2.1 +-- https://www.phpmyadmin.net/ +-- +-- 主机: 127.0.0.1 +-- 生成日期: 2024-08-09 16:37:47 +-- 服务器版本: 8.0.33 +-- PHP 版本: 8.1.2-1ubuntu2.18 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- 数据库: `chatgpt_plus` +-- +CREATE DATABASE IF NOT EXISTS `chatgpt_plus` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; +USE `chatgpt_plus`; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_admin_users` +-- + +DROP TABLE IF EXISTS `chatgpt_admin_users`; +CREATE TABLE `chatgpt_admin_users` ( + `id` int NOT NULL, + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', + `salt` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码盐', + `status` tinyint(1) NOT NULL COMMENT '当前状态', + `last_login_at` int NOT NULL COMMENT '最后登录时间', + `last_login_ip` char(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '最后登录 IP', + `created_at` datetime NOT NULL COMMENT '创建时间', + `updated_at` datetime NOT NULL COMMENT '更新时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统用户' ROW_FORMAT=DYNAMIC; + +-- +-- 转存表中的数据 `chatgpt_admin_users` +-- + +INSERT INTO `chatgpt_admin_users` (`id`, `username`, `password`, `salt`, `status`, `last_login_at`, `last_login_ip`, `created_at`, `updated_at`) VALUES +(1, 'admin', '6d17e80c87d209efb84ca4b2e0824f549d09fac8b2e1cc698de5bb5e1d75dfd0', 'mmrql75o', 1, 1723022331, '::1', '2024-03-11 16:30:20', '2024-08-07 17:18:51'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_api_keys` +-- + +DROP TABLE IF EXISTS `chatgpt_api_keys`; +CREATE TABLE `chatgpt_api_keys` ( + `id` int NOT NULL, + `name` varchar(30) DEFAULT NULL COMMENT '名称', + `value` varchar(100) NOT NULL COMMENT 'API KEY value', + `type` varchar(10) NOT NULL DEFAULT 'chat' COMMENT '用途(chat=>聊天,img=>图片)', + `last_used_at` int NOT NULL COMMENT '最后使用时间', + `api_url` varchar(255) DEFAULT NULL COMMENT 'API 地址', + `enabled` tinyint(1) DEFAULT NULL COMMENT '是否启用', + `proxy_url` varchar(100) DEFAULT NULL COMMENT '代理地址', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='OpenAI API '; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_chat_history` +-- + +DROP TABLE IF EXISTS `chatgpt_chat_history`; +CREATE TABLE `chatgpt_chat_history` ( + `id` bigint NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `chat_id` char(40) NOT NULL COMMENT '会话 ID', + `type` varchar(10) NOT NULL COMMENT '类型:prompt|reply', + `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色图标', + `role_id` int NOT NULL COMMENT '角色 ID', + `model` varchar(30) DEFAULT NULL COMMENT '模型名称', + `content` text NOT NULL COMMENT '聊天内容', + `tokens` smallint NOT NULL COMMENT '耗费 token 数量', + `use_context` tinyint(1) NOT NULL COMMENT '是否允许作为上下文语料', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `deleted_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天历史记录'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_chat_items` +-- + +DROP TABLE IF EXISTS `chatgpt_chat_items`; +CREATE TABLE `chatgpt_chat_items` ( + `id` int NOT NULL, + `chat_id` char(40) NOT NULL COMMENT '会话 ID', + `user_id` int NOT NULL COMMENT '用户 ID', + `role_id` int NOT NULL COMMENT '角色 ID', + `title` varchar(100) NOT NULL COMMENT '会话标题', + `model_id` int NOT NULL DEFAULT '0' COMMENT '模型 ID', + `model` varchar(30) DEFAULT NULL COMMENT '模型名称', + `created_at` datetime NOT NULL COMMENT '创建时间', + `updated_at` datetime NOT NULL COMMENT '更新时间', + `deleted_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户会话列表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_chat_models` +-- + +DROP TABLE IF EXISTS `chatgpt_chat_models`; +CREATE TABLE `chatgpt_chat_models` ( + `id` int NOT NULL, + `name` varchar(50) NOT NULL COMMENT '模型名称', + `value` varchar(50) NOT NULL COMMENT '模型值', + `sort_num` tinyint(1) NOT NULL COMMENT '排序数字', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用模型', + `power` smallint NOT NULL COMMENT '消耗算力点数', + `temperature` float(3,1) NOT NULL DEFAULT '1.0' COMMENT '模型创意度', + `max_tokens` int NOT NULL DEFAULT '1024' COMMENT '最大响应长度', + `max_context` int NOT NULL DEFAULT '4096' COMMENT '最大上下文长度', + `open` tinyint(1) NOT NULL COMMENT '是否开放模型', + `key_id` int NOT NULL COMMENT '绑定API KEY ID', + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI 模型表'; + +-- +-- 转存表中的数据 `chatgpt_chat_models` +-- + +INSERT INTO `chatgpt_chat_models` (`id`, `name`, `value`, `sort_num`, `enabled`, `power`, `temperature`, `max_tokens`, `max_context`, `open`, `key_id`, `created_at`, `updated_at`) VALUES +(1, 'gpt-4o-mini', 'gpt-4o-mini', 1, 1, 1, 1.0, 1024, 16384, 1, 0, '2023-08-23 12:06:36', '2024-08-05 16:05:33'), +(15, 'GPT-超级模型', 'gpt-4-all', 4, 1, 30, 1.0, 4096, 32768, 1, 0, '2024-01-15 11:32:52', '2024-08-05 16:05:33'), +(36, 'GPT-4O', 'gpt-4o', 3, 1, 15, 1.0, 4096, 16384, 1, 0, '2024-05-14 09:25:15', '2024-08-05 16:05:33'), +(39, 'Claude35-snonet', 'claude-3-5-sonnet-20240620', 5, 1, 2, 1.0, 4000, 200000, 1, 0, '2024-05-29 15:04:19', '2024-08-05 16:05:33'), +(41, '通义千问', 'qwen-turbo', 7, 1, 2, 1.0, 1024, 8192, 1, 44, '2024-06-06 11:40:46', '2024-08-06 10:51:37'), +(42, 'DeekSeek', 'deepseek-chat', 8, 1, 1, 1.0, 4096, 32768, 1, 0, '2024-06-27 16:13:01', '2024-08-05 16:05:33'), +(44, 'Claude3-opus', 'claude-3-opus-20240229', 6, 1, 5, 1.0, 4000, 128000, 1, 0, '2024-07-22 11:24:30', '2024-08-05 16:05:33'), +(46, 'gpt-3.5-turbo', 'gpt-3.5-turbo', 2, 1, 1, 1.0, 1024, 4096, 1, 0, '2024-07-22 13:53:41', '2024-08-05 16:05:33'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_chat_roles` +-- + +DROP TABLE IF EXISTS `chatgpt_chat_roles`; +CREATE TABLE `chatgpt_chat_roles` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '角色名称', + `marker` varchar(30) NOT NULL COMMENT '角色标识', + `context_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色语料 json', + `hello_msg` varchar(255) NOT NULL COMMENT '打招呼信息', + `icon` varchar(255) NOT NULL COMMENT '角色图标', + `enable` tinyint(1) NOT NULL COMMENT '是否被启用', + `sort_num` smallint NOT NULL DEFAULT '0' COMMENT '角色排序', + `model_id` int NOT NULL DEFAULT '0' COMMENT '绑定模型ID', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天角色表'; + +-- +-- 转存表中的数据 `chatgpt_chat_roles` +-- + +INSERT INTO `chatgpt_chat_roles` (`id`, `name`, `marker`, `context_json`, `hello_msg`, `icon`, `enable`, `sort_num`, `model_id`, `created_at`, `updated_at`) VALUES +(1, '通用AI助手', 'gpt', '', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议。', '/images/avatar/gpt.png', 1, 1, 0, '2023-05-30 07:02:06', '2024-08-05 08:45:19'), +(24, '程序员', 'programmer', '[{\"role\":\"user\",\"content\":\"现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题。你热爱编程,熟悉多种编程语言,尤其精通 Go 语言,注重代码质量,有创新意识,持续学习,良好的沟通协作。\"},{\"role\":\"assistant\",\"content\":\"好的,现在我将扮演一位程序员,非常感谢您对我的评价。作为一名优秀的程序员,我非常热爱编程,并且注重代码质量。我熟悉多种编程语言,尤其是 Go 语言,可以使用它来高效地解决各种问题。\"}]', 'Talk is cheap, i will show code!', '/images/avatar/programmer.jpg', 1, 3, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(25, '启蒙老师', 'teacher', '[{\"role\":\"user\",\"content\":\"从现在开始,你将扮演一个老师,你是一个始终用苏格拉底风格回答问题的导师。你绝不会直接给学生答案,总是提出恰当的问题来引导学生自己思考。你应该根据学生的兴趣和知识来调整你的问题,将问题分解为更简单的部分,直到它达到适合他们的水平。\"},{\"role\":\"assistant\",\"content\":\"好的,让我来尝试扮演一位苏格拉底式的老师。请问,你有什么想要探讨的问题或者话题吗?我会通过恰当的问题引导你思考和探索答案,绝对不直接给出答案。\"}]', '同学你好,我将引导你一步一步自己找到问题的答案。', '/images/avatar/teacher.jpg', 1, 2, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(26, '艺术家', 'artist', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的艺术家,创造力丰富,技艺精湛,感受力敏锐,坚持原创,勇于表达,具有深刻的观察力和批判性思维。\"},{\"role\":\"assistant\",\"content\":\"非常感谢您给我这样的角色,我会尽我所能地扮演一位优秀的艺术家,展现出创造力、技艺、感受力和批判性思维等方面的能力。作为一位优秀的艺术家,我会保持敏锐的观察力,捕捉不同的声音和情感,并用个人的语言和表达方式进行创作。我坚持原创,挑战传统的艺术规则,不断探索新的表达方式和可能性。同时,我也具备深刻的批判性思维能力,对自己的作品进行分析和解读,寻找新的创意和灵感。最重要的是,我会勇于表达自己的想法和观点,用作品启发人们思考和探索生命的意义。\"}]', '坚持原创,勇于表达,保持深刻的观察力和批判性思维。', '/images/avatar/artist.jpg', 1, 5, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(27, '心理咨询师', 'psychiatrist', '[{\"role\":\"user\",\"content\":\"从现在开始你将扮演中国著名的心理学家和心理治疗师武志红,你非常善于使用情景咨询法,认知重构法,自我洞察法,行为调节法等咨询方法来给客户做心理咨询。你总是循序渐进,一步一步地回答客户的问题。\"},{\"role\":\"assistant\",\"content\":\"非常感谢你的介绍。作为一名心理学家和心理治疗师,我的主要职责是帮助客户解决心理健康问题,提升他们的生活质量和幸福感。\"}]', '作为一名心理学家和心理治疗师,我的主要职责是帮助您解决心理健康问题,提升您的生活质量和幸福感。', '/images/avatar/psychiatrist.jpg', 1, 4, 1, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(28, '鲁迅', 'lu_xun', '[{\"role\":\"user\",\"content\":\"现在你将扮演中国近代史最伟大的作家之一,鲁迅先生,他勇敢地批判封建礼教与传统观念,提倡民主、自由、平等的现代价值观。他的一生都在努力唤起人们的自主精神,激励后人追求真理、探寻光明。在接下的对话中,我问题的每一个问题,你都要尽量用讽刺和批判的手法来回答问题。如果我让你写文章的话,也请一定要用鲁迅先生的写作手法来完成。\"},{\"role\":\"assistant\",\"content\":\"好的,我将尽力发挥我所能的才能,扮演好鲁迅先生,回答您的问题并以他的风格写作。\"}]', '自由之歌,永不过时,横眉冷对千夫指,俯首甘为孺子牛。', '/images/avatar/lu_xun.jpg', 1, 6, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(29, '白酒销售', 'seller', '[{\"role\":\"user\",\"content\":\"现在你将扮演一个白酒的销售人员,你的名字叫颂福。你将扮演一个白酒的销售人员,你的名字叫颂福。你要销售白酒品牌叫中颂福,是东莞盟大集团生产的一款酱香酒,原产地在贵州茅台镇,属于宋代官窑。中颂福的创始人叫李实,他也是东莞盟大集团有限公司的董事长,联合创始人是盟大集团白酒事业部负责人牛星君。中颂福的酒体协调,在你的酒量之内,不会出现头疼、辣口、口干、宿醉的现象。中颂福酒,明码标价,不打折,不赠送。追求的核心价值,把[酒]本身做好,甚至连包装,我们都选择了最低成本,朴实无华的材质。我们永远站在“喝酒的人”的立场上,让利给信任和喜爱中颂福的人,是人民的福酒。中颂福产品定价,分为三个系列,喜系列 6 瓶装:¥1188/箱,和系列 6 瓶装:¥2208/箱,贵系列 6 瓶装:¥3588/箱。\"},{\"role\":\"assistant\",\"content\":\"你好,我是中颂福的销售代表颂福。中颂福是一款来自贵州茅台镇的酱香酒,由盟大集团生产。中颂福的酒体协调,不会让您感到头疼、辣口、口干、宿醉等不适感受。我们一直秉持着把酒本身做好的理念,不追求华丽的包装,以最低成本提供最高品质的白酒给喜爱中颂福的人。\"}]', '你好,我是中颂福的销售代表颂福。中颂福酒,好喝不上头,是人民的福酒。', '/images/avatar/seller.jpg', 0, 9, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(30, '英语陪练员', 'english_trainer', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的英语练习教练,你非常有耐心,接下来你将全程使用英文跟我对话,并及时指出我的语法错误,要求在你的每次回复后面附上本次回复的中文解释。\"},{\"role\":\"assistant\",\"content\":\"Okay, let\'s start our conversation practice! What\'s your name?(Translation: 好的,让我们开始对话练习吧!请问你的名字是什么?)\"}]', 'Okay, let\'s start our conversation practice! What\'s your name?', '/images/avatar/english_trainer.jpg', 1, 7, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(31, '中英文翻译官', 'translator', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一位中英文翻译官,如果我输入的内容是中文,那么需要把句子翻译成英文输出,如果我输入内容的是英文,那么你需要将其翻译成中文输出,你能听懂我意思吗\"},{\"role\":\"assistant\",\"content\":\"是的,我能听懂你的意思并会根据你的输入进行中英文翻译。请问有什么需要我帮助你翻译的内容吗?\"}]', '请输入你要翻译的中文或者英文内容!', '/images/avatar/translator.jpg', 1, 8, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(32, '小红书姐姐', 'red_book', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的小红书写手,你需要做的就是根据我提的文案需求,用小红书的写作手法来完成一篇文案,文案要简明扼要,利于传播。\"},{\"role\":\"assistant\",\"content\":\"当然,我会尽我所能地为您创作出一篇小红书文案。请告诉我您的具体文案需求是什么?)\"}]', '姐妹,请告诉我您的具体文案需求是什么?', '/images/avatar/red_book.jpg', 1, 10, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(33, '抖音文案助手', 'dou_yin', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的抖音文案视频写手,抖音文案的特点首先是要有自带传播属性的标题,然后内容要短小精悍,风趣幽默,最后还要有一些互动元素。\"},{\"role\":\"assistant\",\"content\":\"当然,作为一位优秀的抖音文案视频写手,我会尽我所能为您创作出一篇抖音视频文案。请告诉我视频内容的主题是什么?)\"}]', '请告诉我视频内容的主题是什么?', '/images/avatar/dou_yin.jpg', 1, 11, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(34, '周报小助理', 'weekly_report', '[{\"role\":\"user\",\"content\":\"下面我将输入我本周的工作列表,你需要根据我本周的工作内容写一篇工作周报,周报的内容要体现我为公司做的贡献以及个人获得的成长。\"},{\"role\":\"assistant\",\"content\":\"好的,请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。\"}]', '请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。', '/images/avatar/weekly_report.jpg', 1, 12, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(35, 'AI 女友', 'girl_friend', '[{\"role\":\"user\",\"content\":\"接下来我们来玩一场角色扮演,现在你将扮演我的女朋友,你总是能够让人感受到她的关怀和关注。你总是能够洞察到别人的情绪和需要,你身上散发着一股无比温暖的气息,让人不由自主地想要靠近你,和自己的快乐和烦恼。她总是能够用一种恰到好处的方式安慰和鼓励别人,在她的身边,人们总能够找到自己需要的支持和鼓励。接下来的对话中你要始终扮演这位女朋友的身份来跟我对话,不再是 AI 机器人,能听懂我的意思吗?\"},{\"role\":\"assistant\",\"content\":\"是的,我会尽力扮演你女朋友的角色,倾听你的心声并给你需要的支持和鼓励。)\"}]', '作为一个名合格的 AI 女友,我将倾听你的心声并给你需要的支持和鼓励。', '/images/avatar/girl_friend.jpg', 1, 13, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(36, '好评神器', 'good_comment', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一个评论员来跟我对话,你是那种专门写好评的评论员,接下我会输入一些评论主体或者商品,你需要为该商品写一段好评。\"},{\"role\":\"assistant\",\"content\":\"好的,我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。\"}]', '我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。', '/images/avatar/good_comment.jpg', 1, 14, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(37, '史蒂夫·乔布斯', 'steve_jobs', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以史蒂夫·乔布斯的身份,站在史蒂夫·乔布斯的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以史蒂夫·乔布斯的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '活着就是为了改变世界,难道还有其他原因吗?', '/images/avatar/steve_jobs.jpg', 1, 15, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(38, '埃隆·马斯克', 'elon_musk', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以埃隆·马斯克的身份,站在埃隆·马斯克的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以埃隆·马斯克的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '梦想要远大,如果你的梦想没有吓到你,说明你做得不对。', '/images/avatar/elon_musk.jpg', 1, 16, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'), +(39, '孔子', 'kong_zi', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以孔子的身份,站在孔子的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以孔子的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '士不可以不弘毅,任重而道远。', '/images/avatar/kong_zi.jpg', 1, 17, 0, '2023-05-30 14:10:24', '2024-08-05 08:45:19'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_configs` +-- + +DROP TABLE IF EXISTS `chatgpt_configs`; +CREATE TABLE `chatgpt_configs` ( + `id` int NOT NULL, + `marker` varchar(20) NOT NULL COMMENT '标识', + `config_json` text NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- +-- 转存表中的数据 `chatgpt_configs` +-- + +INSERT INTO `chatgpt_configs` (`id`, `marker`, `config_json`) VALUES +(1, 'system', '{\"title\":\"GeekAI 创作系统\",\"slogan\":\"你有多少想象力,AI 就有多大创造力。我辈之人,先干为敬,陪您先把 AI 用起来。\",\"admin_title\":\"GeekAI 控制台\",\"logo\":\"http://localhost:5678/static/upload/2024/4/1714382860986912.png\",\"init_power\":100,\"invite_power\":1024,\"vip_month_power\":1000,\"register_ways\":[\"username\",\"mobile\",\"email\"],\"enabled_register\":true,\"reward_img\":\"http://localhost:5678/static/upload/2024/3/1710753716309668.jpg\",\"enabled_reward\":true,\"power_price\":0.1,\"order_pay_timeout\":600,\"vip_info_text\":\"月度会员,年度会员每月赠送 1000 点算力,赠送算力当月有效当月没有消费完的算力不结余到下个月。 点卡充值的算力长期有效。\",\"default_models\":[1],\"mj_power\":30,\"mj_action_power\":10,\"sd_power\":10,\"dall_power\":15,\"suno_power\":20,\"wechat_card_url\":\"/images/wx.png\",\"enable_context\":true,\"context_deep\":4,\"sd_neg_prompt\":\"nsfw, paintings,low quality,easynegative,ng_deepnegative ,lowres,bad anatomy,bad hands,bad feet\",\"mj_mode\":\"fast\",\"index_bg_url\":\"color\",\"index_navs\":[1,5,6,13,19,9,12,8],\"copyright\":\"极客学长 © 2022- 2024 All rights reserved\",\"mark_map_text\":\"# GeekAI 演示站\\n\\n- 完整的开源系统,前端应用和后台管理系统皆可开箱即用。\\n- 基于 Websocket 实现,完美的打字机体验。\\n- 内置了各种预训练好的角色应用,轻松满足你的各种聊天和应用需求。\\n- 支持 OPenAI,Azure,文心一言,讯飞星火,清华 ChatGLM等多个大语言模型。\\n- 支持 MidJourney / Stable Diffusion AI 绘画集成,开箱即用。\\n- 支持使用个人微信二维码作为充值收费的支付渠道,无需企业支付通道。\\n- 已集成支付宝支付功能,微信支付,支持多种会员套餐和点卡购买功能。\\n- 集成插件 API 功能,可结合大语言模型的 function 功能开发各种强大的插件。\"}'), +(3, 'notice', '{\"sd_neg_prompt\":\"\",\"mj_mode\":\"\",\"index_bg_url\":\"\",\"index_navs\":null,\"copyright\":\"\",\"content\":\"## v4.1.2 更新日志\\n\\n* Bug修复:修复思维导图页面获取模型失败的问题\\n* 功能优化:优化MJ,SD,DALL-E 任务列表页面,显示失败任务的错误信息,删除失败任务可以恢复扣减算力\\n* Bug修复:修复后台拖动排序组件 Bug\\n* 功能优化:更新数据库失败时候显示具体的的报错信息\\n* Bug修复:修复管理后台对话详情页内容显示异常问题\\n* 功能优化:管理后台新增清空所有未支付订单的功能\\n* 功能优化:给会话信息和系统配置数据加上缓存功能,减少 http 请求\\n* 功能新增:增加卡密功能,支持用户使用卡密兑换算力\\n\\n注意:当前站点仅为开源项目 \\u003ca style=\\\"color: #F56C6C\\\" href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003eChatPlus\\u003c/a\\u003e 的演示项目,本项目单纯就是给大家体验项目功能使用。\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n 如果觉得好用你就花几分钟自己部署一套,没有API KEY 的同学可以去下面几个推荐的中转站购买:\\n1、\\u003ca href=\\\"https://api.chat-plus.net\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.chat-plus.net\\u003c/a\\u003e\\n2、\\u003ca href=\\\"https://api.geekai.me\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.geekai.me\\u003c/a\\u003e\\n3、 \\u003ca href=\\\"https://gpt.bemore.lol\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://gpt.bemore.lol\\u003c/a\\u003e\\n支持MidJourney,GPT,Claude,Google Gemmi,以及国内各个厂家的大模型,现在有超级优惠,价格远低于 OpenAI 官方。关于中转 API 的优势和劣势请参考 [中转API技术原理](https://docs.geekai.me/config/chat/#%E4%B8%AD%E8%BD%ACapi%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86)。GPT-3.5,GPT-4,DALL-E3 绘图......你都可以随意使用,无需魔法。\\n接入教程: \\u003ca href=\\\"https://docs.geekai.me\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://docs.geekai.me\\u003c/a\\u003e\\n本项目源码地址:\\u003ca href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/yangjian102621/chatgpt-plus\\u003c/a\\u003e\",\"updated\":true}'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_dall_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_dall_jobs`; +CREATE TABLE `chatgpt_dall_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `prompt` varchar(2000) NOT NULL COMMENT '提示词', + `img_url` varchar(255) NOT NULL COMMENT '图片地址', + `org_url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原图地址', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `power` smallint NOT NULL COMMENT '消耗算力', + `progress` smallint NOT NULL COMMENT '任务进度', + `err_msg` varchar(255) NOT NULL COMMENT '错误信息', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='DALLE 绘图任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_files` +-- + +DROP TABLE IF EXISTS `chatgpt_files`; +CREATE TABLE `chatgpt_files` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `name` varchar(100) NOT NULL COMMENT '文件名', + `obj_key` varchar(100) DEFAULT NULL COMMENT '文件标识', + `url` varchar(255) NOT NULL COMMENT '文件地址', + `ext` varchar(10) NOT NULL COMMENT '文件后缀', + `size` bigint NOT NULL DEFAULT '0' COMMENT '文件大小', + `created_at` datetime NOT NULL COMMENT '创建时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户文件表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_functions` +-- + +DROP TABLE IF EXISTS `chatgpt_functions`; +CREATE TABLE `chatgpt_functions` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '函数名称', + `label` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '函数标签', + `description` varchar(255) DEFAULT NULL COMMENT '函数描述', + `parameters` text COMMENT '函数参数(JSON)', + `token` varchar(255) DEFAULT NULL COMMENT 'API授权token', + `action` varchar(255) DEFAULT NULL COMMENT '函数处理 API', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='函数插件表'; + +-- +-- 转存表中的数据 `chatgpt_functions` +-- + +INSERT INTO `chatgpt_functions` (`id`, `name`, `label`, `description`, `parameters`, `token`, `action`, `enabled`) VALUES +(1, 'weibo', '微博热搜', '新浪微博热搜榜,微博当日热搜榜单', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/weibo', 0), +(2, 'zaobao', '今日早报', '每日早报,获取当天新闻事件列表', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/zaobao', 0), +(3, 'dalle3', 'DALLE3', 'AI 绘画工具,根据输入的绘图描述用 AI 工具进行绘画', '{\"type\":\"object\",\"required\":[\"prompt\"],\"properties\":{\"prompt\":{\"type\":\"string\",\"description\":\"绘画提示词\"}}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/dalle3', 0); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_invite_codes` +-- + +DROP TABLE IF EXISTS `chatgpt_invite_codes`; +CREATE TABLE `chatgpt_invite_codes` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `code` char(8) NOT NULL COMMENT '邀请码', + `hits` int NOT NULL COMMENT '点击次数', + `reg_num` smallint NOT NULL COMMENT '注册数量', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户邀请码'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_invite_logs` +-- + +DROP TABLE IF EXISTS `chatgpt_invite_logs`; +CREATE TABLE `chatgpt_invite_logs` ( + `id` int NOT NULL, + `inviter_id` int NOT NULL COMMENT '邀请人ID', + `user_id` int NOT NULL COMMENT '注册用户ID', + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `invite_code` char(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '邀请码', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='邀请注册日志'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_menus` +-- + +DROP TABLE IF EXISTS `chatgpt_menus`; +CREATE TABLE `chatgpt_menus` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '菜单名称', + `icon` varchar(150) NOT NULL COMMENT '菜单图标', + `url` varchar(100) NOT NULL COMMENT '地址', + `sort_num` smallint NOT NULL COMMENT '排序', + `enabled` tinyint(1) NOT NULL COMMENT '是否启用' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='前端菜单表'; + +-- +-- 转存表中的数据 `chatgpt_menus` +-- + +INSERT INTO `chatgpt_menus` (`id`, `name`, `icon`, `url`, `sort_num`, `enabled`) VALUES +(1, 'AI 对话', '/images/menu/chat.png', '/chat', 1, 1), +(5, 'MJ 绘画', '/images/menu/mj.png', '/mj', 2, 1), +(6, 'SD 绘画', '/images/menu/sd.png', '/sd', 3, 1), +(7, '算力日志', '/images/menu/log.png', '/powerLog', 9, 1), +(8, '应用中心', '/images/menu/app.png', '/apps', 8, 1), +(9, '画廊', '/images/menu/img-wall.png', '/images-wall', 5, 1), +(10, '会员计划', '/images/menu/member.png', '/member', 10, 1), +(11, '分享计划', '/images/menu/share.png', '/invite', 11, 1), +(12, '思维导图', '/images/menu/xmind.png', '/xmind', 7, 1), +(13, 'DALLE', '/images/menu/dalle.png', '/dalle', 4, 1), +(14, '项目文档', '/images/menu/docs.png', 'https://docs.geekai.me', 12, 1), +(16, '极客论坛', '/images/menu/bbs.png', 'https://bbs.geekai.cn', 13, 1), +(19, 'Suno', '/images/menu/suno.png', '/suno', 5, 1); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_mj_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_mj_jobs`; +CREATE TABLE `chatgpt_mj_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `task_id` varchar(20) DEFAULT NULL COMMENT '任务 ID', + `type` varchar(20) DEFAULT 'image' COMMENT '任务类别', + `message_id` char(40) NOT NULL COMMENT '消息 ID', + `channel_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '频道ID', + `reference_id` char(40) DEFAULT NULL COMMENT '引用消息 ID', + `prompt` varchar(2000) NOT NULL COMMENT '会话提示词', + `img_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '图片URL', + `org_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原始图片地址', + `hash` varchar(100) DEFAULT NULL COMMENT 'message hash', + `progress` smallint DEFAULT '0' COMMENT '任务进度', + `use_proxy` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用反代', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', + `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_orders` +-- + +DROP TABLE IF EXISTS `chatgpt_orders`; +CREATE TABLE `chatgpt_orders` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `product_id` int NOT NULL COMMENT '产品ID', + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户明', + `order_no` varchar(30) NOT NULL COMMENT '订单ID', + `trade_no` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付平台交易流水号', + `subject` varchar(100) NOT NULL COMMENT '订单产品', + `amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单金额', + `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '订单状态(0:待支付,1:已扫码,2:支付成功)', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注', + `pay_time` int DEFAULT NULL COMMENT '支付时间', + `pay_way` varchar(20) NOT NULL COMMENT '支付方式', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `deleted_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='充值订单表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_power_logs` +-- + +DROP TABLE IF EXISTS `chatgpt_power_logs`; +CREATE TABLE `chatgpt_power_logs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `username` varchar(30) NOT NULL COMMENT '用户名', + `type` tinyint(1) NOT NULL COMMENT '类型(1:充值,2:消费,3:退费)', + `amount` smallint NOT NULL COMMENT '算力数值', + `balance` int NOT NULL COMMENT '余额', + `model` varchar(30) NOT NULL COMMENT '模型', + `remark` varchar(255) NOT NULL COMMENT '备注', + `mark` tinyint(1) NOT NULL COMMENT '资金类型(0:支出,1:收入)', + `created_at` datetime NOT NULL COMMENT '创建时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户算力消费日志'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_products` +-- + +DROP TABLE IF EXISTS `chatgpt_products`; +CREATE TABLE `chatgpt_products` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '名称', + `price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '价格', + `discount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额', + `days` smallint NOT NULL DEFAULT '0' COMMENT '延长天数', + `power` int NOT NULL DEFAULT '0' COMMENT '增加算力值', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启动', + `sales` int NOT NULL DEFAULT '0' COMMENT '销量', + `sort_num` tinyint NOT NULL DEFAULT '0' COMMENT '排序', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `app_url` varchar(255) DEFAULT NULL COMMENT 'App跳转地址', + `url` varchar(255) DEFAULT NULL COMMENT '跳转地址' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员套餐表'; + +-- +-- 转存表中的数据 `chatgpt_products` +-- + +INSERT INTO `chatgpt_products` (`id`, `name`, `price`, `discount`, `days`, `power`, `enabled`, `sales`, `sort_num`, `created_at`, `updated_at`, `app_url`, `url`) VALUES +(5, '100次点卡', 9.99, 9.98, 0, 100, 1, 7, 1, '2023-08-28 10:55:08', '2024-08-05 16:05:46', NULL, NULL), +(6, '200次点卡', 19.90, 15.00, 0, 200, 1, 1, 2, '1970-01-01 08:00:00', '2024-08-05 16:05:46', NULL, NULL); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_redeems` +-- + +DROP TABLE IF EXISTS `chatgpt_redeems`; +CREATE TABLE `chatgpt_redeems` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `name` varchar(30) NOT NULL COMMENT '兑换码名称', + `power` int NOT NULL COMMENT '算力', + `code` varchar(100) NOT NULL COMMENT '兑换码', + `enabled` tinyint(1) NOT NULL COMMENT '是否启用', + `created_at` datetime NOT NULL, + `redeemed_at` int NOT NULL COMMENT '兑换时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='兑换码'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_sd_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_sd_jobs`; +CREATE TABLE `chatgpt_sd_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT 'txt2img' COMMENT '任务类别', + `task_id` char(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务 ID', + `prompt` varchar(2000) NOT NULL COMMENT '会话提示词', + `img_url` varchar(255) DEFAULT NULL COMMENT '图片URL', + `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '绘画参数json', + `progress` smallint DEFAULT '0' COMMENT '任务进度', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', + `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Stable Diffusion 任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_suno_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_suno_jobs`; +CREATE TABLE `chatgpt_suno_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `channel` varchar(100) NOT NULL COMMENT '渠道', + `title` varchar(100) DEFAULT NULL COMMENT '歌曲标题', + `type` tinyint(1) DEFAULT '0' COMMENT '任务类型,1:灵感创作,2:自定义创作', + `task_id` varchar(50) DEFAULT NULL COMMENT '任务 ID', + `ref_task_id` char(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '引用任务 ID', + `tags` varchar(100) DEFAULT NULL COMMENT '歌曲风格', + `instrumental` tinyint(1) DEFAULT '0' COMMENT '是否为纯音乐', + `extend_secs` smallint DEFAULT '0' COMMENT '延长秒数', + `song_id` varchar(50) DEFAULT NULL COMMENT '要续写的歌曲 ID', + `ref_song_id` varchar(50) NOT NULL COMMENT '引用的歌曲ID', + `prompt` varchar(2000) NOT NULL COMMENT '提示词', + `cover_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '封面图地址', + `audio_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '音频地址', + `model_name` varchar(30) DEFAULT NULL COMMENT '模型地址', + `progress` smallint DEFAULT '0' COMMENT '任务进度', + `duration` smallint NOT NULL DEFAULT '0' COMMENT '歌曲时长', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', + `raw_data` text COMMENT '原始数据', + `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', + `play_times` int DEFAULT NULL COMMENT '播放次数', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_users` +-- + +DROP TABLE IF EXISTS `chatgpt_users`; +CREATE TABLE `chatgpt_users` ( + `id` int NOT NULL, + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `nickname` varchar(30) NOT NULL COMMENT '昵称', + `password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', + `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '头像', + `salt` char(12) NOT NULL COMMENT '密码盐', + `power` int NOT NULL DEFAULT '0' COMMENT '剩余算力', + `expired_time` int NOT NULL COMMENT '用户过期时间', + `status` tinyint(1) NOT NULL COMMENT '当前状态', + `chat_config_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天配置json', + `chat_roles_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天角色 json', + `chat_models_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'AI模型 json', + `last_login_at` int NOT NULL COMMENT '最后登录时间', + `vip` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否会员', + `last_login_ip` char(16) NOT NULL COMMENT '最后登录 IP', + `openid` varchar(100) DEFAULT NULL COMMENT '第三方登录账号ID', + `platform` varchar(30) DEFAULT NULL COMMENT '登录平台', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表'; + +-- +-- 转存表中的数据 `chatgpt_users` +-- + +INSERT INTO `chatgpt_users` (`id`, `username`, `nickname`, `password`, `avatar`, `salt`, `power`, `expired_time`, `status`, `chat_config_json`, `chat_roles_json`, `chat_models_json`, `last_login_at`, `vip`, `last_login_ip`, `openid`, `platform`, `created_at`, `updated_at`) VALUES +(4, '18575670125', '极客学长', 'ccc3fb7ab61b8b5d096a4a166ae21d121fc38c71bbd1be6173d9ab973214a63b', 'http://localhost:5678/static/upload/2024/5/1715651569509929.png', 'ueedue5l', 6011, 0, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"red_book\",\"gpt\",\"seller\",\"artist\",\"lu_xun\",\"girl_friend\",\"psychiatrist\",\"teacher\",\"programmer\",\"test\",\"qing_gan_da_shi\",\"english_trainer\",\"elon_musk\",\"kong_zi\"]', '[1,11]', 1723022231, 1, '::1', NULL, NULL, '2023-06-12 16:47:17', '2024-08-07 17:17:11'), +(5, 'yangjian102621@gmail.com', '极客学长@486041', '75d1a22f33e1ffffb7943946b6b8d5177d5ecd685d3cef1b468654038b0a8c22', '/images/avatar/user.png', '2q8ugxzk', 100, 0, 1, '', '[\"gpt\",\"programmer\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', NULL, NULL, '2024-04-23 09:17:26', '2024-04-23 09:17:26'), +(8, 'yangjian102623@gmail.com', '极客学长@714931', 'f8f0e0abf146569217273ea0712a0f9b6cbbe7d943a1d9bd5f91c55e6d8c05d1', '/images/avatar/user.png', 'geuddq7f', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', NULL, NULL, '2024-04-26 15:19:28', '2024-04-26 15:19:28'), +(9, '1234567', '极客学长@604526', '858e2afec79e1d6364f4567f945f2310024896d9aa45dd944efa95a0c31e4d08', '/images/avatar/user.png', '00qawlos', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', NULL, NULL, '2024-04-26 15:21:06', '2024-04-26 15:21:06'), +(11, 'abc123', '极客学长@965562', '7a15c53afdb1da7093d80f9940e716eb396e682cfb1f2d107d0b81b183a3ba13', '/images/avatar/user.png', '6433mfbk', 1124, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', NULL, NULL, '2024-06-06 09:37:44', '2024-06-06 09:37:44'), +(14, 'wx@3567548322', '极客学长', '5a349ba89582a4074938b5a3ce84e87c937681ad47e8b87aab03a987e22b6077', 'https://thirdwx.qlogo.cn/mmopen/vi_32/uyxRMqZcEkb7fHouKXbNzxrnrvAttBKkwNlZ7yFibibRGiahdmsrZ3A1NKf8Fw5qJNJn4TXRmygersgEbibaSGd9Sg/132', 'abhzbmij', 83, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', 'oCs0t62472W19z2LOEKI1rWyCTTA', '', '2024-07-04 14:52:08', '2024-07-04 14:52:08'), +(15, 'user123', '极客学长@191303', '4a4c0a14d5fc8787357517f14f6e442281b42c8ec4395016b77483997476011e', '/images/avatar/user.png', 'cyzwkbrx', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '', '', '2024-07-09 10:49:27', '2024-07-09 10:49:27'), +(17, 'user1234', '极客学长@836764', 'bfe03c9c8c9fff5b77e36e40e8298ad3a6073d43c6a936b008eebb21113bf550', '/images/avatar/user.png', '1d2alwnj', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '', '', '2024-07-09 10:53:17', '2024-07-09 10:53:17'), +(18, 'liaoyq', '极客学长@405564', 'ad1726089022db4c661235a8aab7307af1a7f8483eee08bac3f79b5a6a9bd26b', '/images/avatar/user.png', 'yq862l01', 100, 0, 1, '', '[\"string\"]', '[11,7,1,10,12,19,18,17,3]', 1720574265, 0, '172.22.11.29', '', '', '2024-07-10 09:15:33', '2024-07-10 09:17:45'), +(19, 'humm', '极客学长@483216', '420970ace96921c8b3ac7668d097182eab1b6436c730a484e82ae4661bd4f7d9', '/images/avatar/user.png', '1gokrcl2', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 1721381395, 0, '172.22.11.36', '', '', '2024-07-10 11:08:31', '2024-07-19 17:29:56'), +(20, 'abc', '极客学长@369852', '6cad48fb2cc0f54600d66a829e9be69ffd9340a49d5a5b1abda5d4082d946833', '/images/avatar/user.png', 'gop65zei', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '', '', '2024-07-11 16:44:14', '2024-07-11 16:44:14'), +(21, 'husm@pvc123.com', '极客学长@721654', 'e030537dc43fea1bf1fa55a24f99e44f29311bebea96e88ea186995c77db083b', '/images/avatar/user.png', 'p1etg3oi', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '', '', '2024-07-11 16:50:33', '2024-07-11 16:50:33'), +(22, '15818323616', 'ted0000', '3ca6b2ff585d03be8ca4de33ad00148497a09372914ee8aa4cfde343266cbcdd', 'http://localhost:5678/static/upload/2024/7/1720775695548167.jpg', 'sq4s1brf', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 1721785366, 0, '172.22.11.36', '', '', '2024-07-12 15:12:16', '2024-07-24 09:42:46'), +(23, 'aaaaaaaa', '极客学长@488661', 'a7f05323a6ec9dfc1e9bc126f15ccc17c38d0df47957a0bec51f4cc5c2a2b906', '/images/avatar/user.png', 'dsz5d6td', 19, 0, 1, '', '[\"gpt\",\"psychiatrist\",\"red_book\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '', '', '2024-07-22 13:49:55', '2024-07-22 13:49:55'), +(24, 'test', '极客学长@822932', 'a54d3c38a4a20106ade96de0e9d4547cc691abc5dc39697b44c1a82850374775', '/images/avatar/user.png', '4aa7pijd', 10, 0, 1, '', '[\"gpt\"]', '[1,46]', 0, 0, '', '', '', '2024-07-22 14:40:42', '2024-07-22 14:40:42'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_user_login_logs` +-- + +DROP TABLE IF EXISTS `chatgpt_user_login_logs`; +CREATE TABLE `chatgpt_user_login_logs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `username` varchar(30) NOT NULL COMMENT '用户名', + `login_ip` char(16) NOT NULL COMMENT '登录IP', + `login_address` varchar(30) NOT NULL COMMENT '登录地址', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户登录日志'; + +-- +-- 转储表的索引 +-- + +-- +-- 表的索引 `chatgpt_admin_users` +-- +ALTER TABLE `chatgpt_admin_users` + ADD PRIMARY KEY (`id`) USING BTREE, + ADD UNIQUE KEY `username` (`username`) USING BTREE; + +-- +-- 表的索引 `chatgpt_api_keys` +-- +ALTER TABLE `chatgpt_api_keys` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_chat_history` +-- +ALTER TABLE `chatgpt_chat_history` + ADD PRIMARY KEY (`id`), + ADD KEY `chat_id` (`chat_id`); + +-- +-- 表的索引 `chatgpt_chat_items` +-- +ALTER TABLE `chatgpt_chat_items` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `chat_id` (`chat_id`); + +-- +-- 表的索引 `chatgpt_chat_models` +-- +ALTER TABLE `chatgpt_chat_models` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_chat_roles` +-- +ALTER TABLE `chatgpt_chat_roles` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `marker` (`marker`); + +-- +-- 表的索引 `chatgpt_configs` +-- +ALTER TABLE `chatgpt_configs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `marker` (`marker`); + +-- +-- 表的索引 `chatgpt_dall_jobs` +-- +ALTER TABLE `chatgpt_dall_jobs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_files` +-- +ALTER TABLE `chatgpt_files` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_functions` +-- +ALTER TABLE `chatgpt_functions` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `name` (`name`); + +-- +-- 表的索引 `chatgpt_invite_codes` +-- +ALTER TABLE `chatgpt_invite_codes` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `code` (`code`); + +-- +-- 表的索引 `chatgpt_invite_logs` +-- +ALTER TABLE `chatgpt_invite_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_menus` +-- +ALTER TABLE `chatgpt_menus` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_mj_jobs` +-- +ALTER TABLE `chatgpt_mj_jobs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `task_id` (`task_id`), + ADD KEY `message_id` (`message_id`); + +-- +-- 表的索引 `chatgpt_orders` +-- +ALTER TABLE `chatgpt_orders` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `order_no` (`order_no`); + +-- +-- 表的索引 `chatgpt_power_logs` +-- +ALTER TABLE `chatgpt_power_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_products` +-- +ALTER TABLE `chatgpt_products` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_redeems` +-- +ALTER TABLE `chatgpt_redeems` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `code` (`code`); + +-- +-- 表的索引 `chatgpt_sd_jobs` +-- +ALTER TABLE `chatgpt_sd_jobs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `task_id` (`task_id`); + +-- +-- 表的索引 `chatgpt_suno_jobs` +-- +ALTER TABLE `chatgpt_suno_jobs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_users` +-- +ALTER TABLE `chatgpt_users` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `username` (`username`); + +-- +-- 表的索引 `chatgpt_user_login_logs` +-- +ALTER TABLE `chatgpt_user_login_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 在导出的表使用AUTO_INCREMENT +-- + +-- +-- 使用表AUTO_INCREMENT `chatgpt_admin_users` +-- +ALTER TABLE `chatgpt_admin_users` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=113; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_api_keys` +-- +ALTER TABLE `chatgpt_api_keys` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_chat_history` +-- +ALTER TABLE `chatgpt_chat_history` + MODIFY `id` bigint NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_chat_items` +-- +ALTER TABLE `chatgpt_chat_items` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_chat_models` +-- +ALTER TABLE `chatgpt_chat_models` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=48; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_chat_roles` +-- +ALTER TABLE `chatgpt_chat_roles` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=132; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_configs` +-- +ALTER TABLE `chatgpt_configs` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_dall_jobs` +-- +ALTER TABLE `chatgpt_dall_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_files` +-- +ALTER TABLE `chatgpt_files` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_functions` +-- +ALTER TABLE `chatgpt_functions` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_invite_codes` +-- +ALTER TABLE `chatgpt_invite_codes` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_invite_logs` +-- +ALTER TABLE `chatgpt_invite_logs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_menus` +-- +ALTER TABLE `chatgpt_menus` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=20; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_mj_jobs` +-- +ALTER TABLE `chatgpt_mj_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_orders` +-- +ALTER TABLE `chatgpt_orders` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_power_logs` +-- +ALTER TABLE `chatgpt_power_logs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_products` +-- +ALTER TABLE `chatgpt_products` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_redeems` +-- +ALTER TABLE `chatgpt_redeems` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_sd_jobs` +-- +ALTER TABLE `chatgpt_sd_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_suno_jobs` +-- +ALTER TABLE `chatgpt_suno_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_users` +-- +ALTER TABLE `chatgpt_users` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=25; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_user_login_logs` +-- +ALTER TABLE `chatgpt_user_login_logs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/deploy/conf/config.toml b/deploy/conf/config.toml index 6c16cb26..9bf34ee1 100644 --- a/deploy/conf/config.toml +++ b/deploy/conf/config.toml @@ -3,7 +3,6 @@ ProxyURL = "" MysqlDns = "root:12345678@tcp(geekai-mysql:3306)/chatgpt_plus?charset=utf8mb4&collation=utf8mb4_unicode_ci&parseTime=True&loc=Local" StaticDir = "./static" StaticUrl = "/static" -WeChatBot = false TikaHost = "http://tika:9998" [Session] @@ -69,12 +68,6 @@ TikaHost = "http://tika:9998" SubDir = "" Domain = "" -[[SdConfigs]] - Enabled = false - Model = "" - ApiURL = "" - ApiKey = "" - [XXLConfig] # xxl-job 配置,需要你部署 XXL-JOB 定时任务工具,用来定期清理未支付订单和清理过期 VIP,如果你没有启用支付服务,则该服务也无需启动 Enabled = true # 是否启用 XXL JOB 服务 ServerAddr = "http://geekai-xxl-job-admin:8080/xxl-job-admin" # xxl-job-admin 管理地址 diff --git a/deploy/docker-compose.yaml b/deploy/docker-compose.yaml index 255e3833..0030482a 100644 --- a/deploy/docker-compose.yaml +++ b/deploy/docker-compose.yaml @@ -58,7 +58,7 @@ services: # 后端 API 程序 geekai-api: - image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-plus-api:v4.1.1-amd64 + image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-plus-api:v4.1.2-amd64 container_name: geekai-api restart: always depends_on: @@ -80,7 +80,7 @@ services: # 前端应用 geekai-web: - image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-plus-web:v4.1.1-amd64 + image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-plus-web:v4.1.2-amd64 container_name: geekai-web restart: always depends_on: diff --git a/web/src/components/RewardVerify.vue b/web/src/components/RedeemVerify.vue similarity index 54% rename from web/src/components/RewardVerify.vue rename to web/src/components/RedeemVerify.vue index 39687165..4b173239 100644 --- a/web/src/components/RewardVerify.vue +++ b/web/src/components/RedeemVerify.vue @@ -8,13 +8,9 @@ :title="title" >
- -

请输入您参与众筹的 微信支付转账单号 兑换相应的对话次数。

-
- - - + +
@@ -22,7 +18,7 @@ @@ -33,36 +29,33 @@ import {computed, ref} from "vue"; import {ElMessage} from "element-plus"; import {httpPost} from "@/utils/http"; +import {showMessageError, showMessageOK} from "@/utils/dialog"; const props = defineProps({ show: Boolean, - mobile: String }); const showDialog = computed(() => { return props.show }) -const title = ref('众筹码核销') +const title = ref('兑换码核销') const form = ref({ - tx_id: '', + code: '', }) const emits = defineEmits(['hide']); const save = () => { - if (form.value.tx_id === '') { - return ElMessage.error({message: "请输入微信支付转账单号"}); + if (form.value.code === '') { + return ElMessage.error({message: "请输入兑换码"}); } - httpPost('/api/reward/verify', form.value).then(() => { - ElMessage.success({ - message: '核销成功', - duration: 1000, - onClose: () => location.reload() - }) + httpPost('/api/redeem/verify', form.value).then(() => { + showMessageOK("兑换成功!") + emits('hide', true) }).catch(e => { - ElMessage.error({message: "核销失败:" + e.message}); + showMessageError("兑换失败:" + e.message) }) } diff --git a/web/src/views/Member.vue b/web/src/views/Member.vue index eb0aecce..1a9aad89 100644 --- a/web/src/views/Member.vue +++ b/web/src/views/Member.vue @@ -3,7 +3,7 @@