feat(release): migrate GeekAI v4.3.0 to open source

- Sync backend and frontend from GeekAI Plus v4.3.0

- Remove commercial License flows and update open-source deployment defaults

- Preserve Docker Compose deployment and bump image tags to v4.3.0

BREAKING CHANGE: commercial License configuration and related endpoints are removed
This commit is contained in:
RockYang
2026-08-11 14:51:20 +08:00
parent 37e024acea
commit 9ccff4efbc
219 changed files with 29212 additions and 10802 deletions
+12 -12
View File
@@ -5,18 +5,18 @@ import (
)
type ChatApp struct {
Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
Name string `gorm:"column:name;type:varchar(30);not null;comment:角色名称" json:"name"`
Tid uint `gorm:"column:tid;type:int(11);not null;comment:分类ID" json:"tid"`
Key string `gorm:"column:marker;type:varchar(30);uniqueIndex;not null;comment:角色标识" json:"marker"`
Context string `gorm:"column:context_json;type:text;not null;comment:角色语料 json" json:"context_json"`
HelloMsg string `gorm:"column:hello_msg;type:varchar(255);not null;comment:打招呼信息" json:"hello_msg"`
Icon string `gorm:"column:icon;type:varchar(255);not null;comment:角色图标" json:"icon"`
Enable bool `gorm:"column:enable;type:tinyint(1);not null;comment:是否被启用" json:"enable"`
SortNum int `gorm:"column:sort_num;type:smallint;not null;default:0;comment:角色排序" json:"sort_num"`
ModelId uint `gorm:"column:model_id;type:int(11);not null;default:0;comment:绑定模型ID" json:"model_id"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;not null" json:"updated_at"`
Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
Name string `gorm:"column:name;type:varchar(30);not null;comment:角色名称" json:"name"`
Tid uint `gorm:"column:tid;type:int(11);not null;comment:分类ID" json:"tid"`
UserId uint `gorm:"column:user_id;type:int(11);not null;default:0;comment:所属用户ID,为 0 表示系统内置" json:"user_id"`
SystemPrompt string `gorm:"column:system_prompt;type:text;not null;comment:系统提示词" json:"system_prompt"`
HelloMsg string `gorm:"column:hello_msg;type:varchar(255);not null;comment:打招呼信息" json:"hello_msg"`
Icon string `gorm:"column:icon;type:varchar(255);not null;comment:角色图标" json:"icon"`
Enable bool `gorm:"column:enable;type:tinyint(1);not null;comment:是否被启用" json:"enable"`
SortNum int `gorm:"column:sort_num;type:smallint;not null;default:0;comment:角色排序" json:"sort_num"`
ModelId uint `gorm:"column:model_id;type:int(11);not null;default:0;comment:绑定模型ID" json:"model_id"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;not null" json:"updated_at"`
}
func (m *ChatApp) TableName() string {
-21
View File
@@ -1,21 +0,0 @@
package model
import "time"
type DallJob struct {
Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
UserId uint `gorm:"column:user_id;type:int(11);not null;comment:用户ID" json:"user_id"`
Prompt string `gorm:"column:prompt;type:text;not null;comment:提示词" json:"prompt"`
TaskInfo string `gorm:"column:task_info;type:text;not null;comment:任务详情" json:"task_info"`
ImgURL string `gorm:"column:img_url;type:varchar(255);not null;comment:图片地址" json:"img_url"`
OrgURL string `gorm:"column:org_url;type:varchar(1024);comment:原图地址" json:"org_url"`
Publish int `gorm:"column:publish;type:tinyint(1);not null;comment:是否发布" json:"publish"`
Power int `gorm:"column:power;type:smallint;not null;comment:消耗算力" json:"power"`
Progress int `gorm:"column:progress;type:smallint;not null;comment:任务进度" json:"progress"`
ErrMsg string `gorm:"column:err_msg;type:varchar(1024);not null;comment:错误信息" json:"err_msg"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
}
func (m *DallJob) TableName() string {
return "geekai_dall_jobs"
}
+22
View File
@@ -0,0 +1,22 @@
package model
import "time"
type ImageJob struct {
Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
UserId uint `gorm:"column:user_id;type:int(11);not null;comment:用户ID" json:"user_id"`
Prompt string `gorm:"column:prompt;type:text;not null;comment:提示词" json:"prompt"`
Params string `gorm:"column:params;type:text;not null;comment:任务参数" json:"params"`
TaskId string `gorm:"column:task_id;type:varchar(64);comment:Kapon 异步任务 ID" json:"task_id"`
ImgURL string `gorm:"column:img_url;type:varchar(255);not null;comment:图片地址" json:"img_url"`
OrgURL string `gorm:"column:org_url;type:varchar(1024);comment:原图地址" json:"org_url"`
Publish int `gorm:"column:publish;type:tinyint(1);not null;comment:是否发布" json:"publish"`
Power int `gorm:"column:power;type:smallint;not null;comment:消耗算力" json:"power"`
Progress int `gorm:"column:progress;type:smallint;not null;comment:任务进度" json:"progress"`
ErrMsg string `gorm:"column:err_msg;type:varchar(1024);not null;comment:错误信息" json:"err_msg"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
}
func (m *ImageJob) TableName() string {
return "geekai_image_jobs"
}
+29
View File
@@ -0,0 +1,29 @@
package model
import (
"geekai/store/vo"
"time"
)
// PPTJob PPT 生成任务(持久化到数据库)
type PPTJob struct {
Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
TaskId string `gorm:"column:task_id;type:varchar(64);uniqueIndex;not null;comment:任务 ID" json:"task_id"`
UserId uint `gorm:"column:user_id;type:int(11);not null;index;comment:用户 ID" json:"user_id"`
Status string `gorm:"column:status;type:varchar(32);not null;default:pending;comment:任务状态 pending,processing,completed,failed" json:"status"`
ErrMsg string `gorm:"column:err_msg;type:varchar(1024);comment:错误信息" json:"err_msg"`
Prompt string `gorm:"column:prompt;type:text;comment:用户补充提示" json:"prompt"`
Title string `gorm:"column:title;type:varchar(256);default:'';comment:列表展示标题(LLM)" json:"title"`
Thumb string `gorm:"column:thumb;type:varchar(1024);default:'';comment:列表缩略图 URL" json:"thumb"`
Content string `gorm:"column:content;type:text;not null;comment:PPT 内容大纲" json:"content"`
Params vo.PPTParams `gorm:"column:params;type:text;comment:生成参数 JSON(语言,生成模式,页数)" json:"params"`
Slides vo.PPTSlides `gorm:"column:slides;type:text;comment:生成的幻灯片列表 JSON" json:"slides"`
TotalSlides int `gorm:"column:total_slides;type:int(11);default:0;comment:总页数" json:"total_slides"`
CompletedSlides int `gorm:"column:completed_slides;type:int(11);default:0;comment:已完成页数" json:"completed_slides"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;not null" json:"updated_at"`
}
func (m *PPTJob) TableName() string {
return "geekai_ppt_jobs"
}
-23
View File
@@ -1,23 +0,0 @@
package model
import "time"
type SdJob struct {
Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
UserId uint `gorm:"column:user_id;type:int(11);not null;comment:用户 ID" json:"user_id"`
Type string `gorm:"column:type;type:varchar(20);default:txt2img;comment:任务类别" json:"type"`
TaskId string `gorm:"column:task_id;type:char(30);uniqueIndex;not null;comment:任务 ID" json:"task_id"`
TaskInfo string `gorm:"column:task_info;type:text;not null;comment:任务详情" json:"task_info"`
Prompt string `gorm:"column:prompt;type:text;not null;comment:会话提示词" json:"prompt"`
ImgURL string `gorm:"column:img_url;type:varchar(255);comment:图片URL" json:"img_url"`
Params string `gorm:"column:params;type:text;comment:绘画参数json" json:"params"`
Progress int `gorm:"column:progress;type:smallint;default:0;comment:任务进度" json:"progress"`
Publish int `gorm:"column:publish;type:tinyint(1);not null;comment:是否发布" json:"publish"`
ErrMsg string `gorm:"column:err_msg;type:varchar(1024);comment:错误信息" json:"err_msg"`
Power int `gorm:"column:power;type:smallint;not null;default:0;comment:消耗算力" json:"power"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
}
func (m *SdJob) TableName() string {
return "geekai_sd_jobs"
}
+25 -26
View File
@@ -1,33 +1,32 @@
package model
import "time"
import (
"geekai/store/vo"
"time"
)
type SunoJob struct {
Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
UserId uint `gorm:"column:user_id;type:int;not null;comment:用户 ID" json:"user_id"`
Channel string `gorm:"column:channel;type:varchar(100);not null;comment:渠道" json:"channel"`
Title string `gorm:"column:title;type:varchar(100);comment:歌曲标题" json:"title"`
Type int `gorm:"column:type;type:tinyint(1);default:0;comment:任务类型,1:灵感创作,2:自定义创作" json:"type"`
TaskId string `gorm:"column:task_id;type:varchar(50);comment:任务 ID" json:"task_id"`
TaskInfo string `gorm:"column:task_info;type:text;not null;comment:任务详情" json:"task_info"`
RefTaskId string `gorm:"column:ref_task_id;type:char(50);comment:引用任务 ID" json:"ref_task_id"`
Tags string `gorm:"column:tags;type:varchar(255);comment:歌曲风格" json:"tags"`
Instrumental bool `gorm:"column:instrumental;type:tinyint(1);default:0;comment:是否为纯音乐" json:"instrumental"`
ExtendSecs int `gorm:"column:extend_secs;type:smallint;default:0;comment:延长秒数" json:"extend_secs"`
SongId string `gorm:"column:song_id;type:varchar(50);comment:要续写的歌曲 ID" json:"song_id"`
RefSongId string `gorm:"column:ref_song_id;type:varchar(50);not null;comment:引用的歌曲ID" json:"ref_song_id"`
Prompt string `gorm:"column:prompt;type:varchar(2000);not null;comment:提示词" json:"prompt"`
CoverURL string `gorm:"column:cover_url;type:varchar(512);comment:封面图地址" json:"cover_url"`
AudioURL string `gorm:"column:audio_url;type:varchar(512);comment:音频地址" json:"audio_url"`
ModelName string `gorm:"column:model_name;type:varchar(30);comment:模型地址" json:"model_name"`
Progress int `gorm:"column:progress;type:smallint;default:0;comment:任务进度" json:"progress"`
Duration int `gorm:"column:duration;type:smallint;not null;default:0;comment:歌曲时长" json:"duration"`
Publish int `gorm:"column:publish;type:tinyint(1);not null;comment:是否发布" json:"publish"`
ErrMsg string `gorm:"column:err_msg;type:varchar(1024);comment:错误信息" json:"err_msg"`
RawData string `gorm:"column:raw_data;type:text;comment:原始数据" json:"raw_data"`
Power int `gorm:"column:power;type:smallint;not null;default:0;comment:消耗算力" json:"power"`
PlayTimes int `gorm:"column:play_times;type:int;comment:播放次数" json:"play_times"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
UserId uint `gorm:"column:user_id;type:int;not null;comment:用户 ID" json:"user_id"`
Channel string `gorm:"column:channel;type:varchar(100);not null;comment:渠道" json:"channel"`
Title string `gorm:"column:title;type:varchar(100);comment:歌曲标题" json:"title"`
Type int `gorm:"column:type;type:tinyint(1);default:0;comment:任务类型,1:灵感创作,2:自定义创作" json:"type"`
TaskId string `gorm:"column:task_id;type:varchar(50);comment:任务 ID" json:"task_id"`
Params vo.SunoParam `gorm:"column:params;type:text;comment:任务参数" json:"params"`
RefTaskId string `gorm:"column:ref_task_id;type:char(50);comment:引用任务 ID" json:"ref_task_id"`
SongId string `gorm:"column:song_id;type:varchar(50);comment:要续写的歌曲 ID" json:"song_id"`
RefSongId string `gorm:"column:ref_song_id;type:varchar(50);not null;comment:引用的歌曲ID" json:"ref_song_id"`
Prompt string `gorm:"column:prompt;type:varchar(2000);not null;comment:提示词" json:"prompt"`
CoverURL string `gorm:"column:cover_url;type:varchar(512);comment:封面图地址" json:"cover_url"`
AudioURL string `gorm:"column:audio_url;type:varchar(512);comment:音频地址" json:"audio_url"`
Progress int `gorm:"column:progress;type:smallint;default:0;comment:任务进度" json:"progress"`
Duration int `gorm:"column:duration;type:smallint;not null;default:0;comment:歌曲时长" json:"duration"`
Publish int `gorm:"column:publish;type:tinyint(1);not null;comment:是否发布" json:"publish"`
ErrMsg string `gorm:"column:err_msg;type:varchar(1024);comment:错误信息" json:"err_msg"`
Output string `gorm:"column:output;type:text;comment:原始输出数据" json:"output"`
Power int `gorm:"column:power;type:smallint;not null;default:0;comment:消耗算力" json:"power"`
PlayTimes int `gorm:"column:play_times;type:int;comment:播放次数" json:"play_times"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
}
func (m *SunoJob) TableName() string {
+2 -1
View File
@@ -17,13 +17,14 @@ type User struct {
ExpiredTime int64 `gorm:"column:expired_time;type:int;not null;comment:用户过期时间" json:"expired_time"`
Status bool `gorm:"column:status;type:tinyint(1);not null;comment:当前状态" json:"status"`
ChatConfig string `gorm:"column:chat_config_json;type:text;default:null;comment:聊天配置json" json:"chat_config"`
ChatRoles string `gorm:"column:chat_roles_json;type:text;default:null;comment:聊天角色 json" json:"chat_roles"`
ChatRoles string `gorm:"column:chat_roles_json;type:text;default:null;comment:聊天角色 json" json:"-"`
ChatModels string `gorm:"column:chat_models_json;type:text;default:null;comment:AI模型 json" json:"chat_models"`
LastLoginAt int64 `gorm:"column:last_login_at;type:int;not null;comment:最后登录时间" json:"last_login_at"`
Vip bool `gorm:"column:vip;type:tinyint(1);not null;default:0;comment:是否会员" json:"vip"`
LastLoginIp string `gorm:"column:last_login_ip;type:char(32);not null;comment:最后登录 IP" json:"last_login_ip"`
OpenId string `gorm:"column:openid;type:varchar(100);comment:第三方登录账号ID" json:"openid"`
Platform string `gorm:"column:platform;type:varchar(30);comment:登录平台" json:"platform"`
GemIds string `gorm:"column:gem_ids_json;type:text;default:null;comment:用户固定的智能体ID列表(JSON数组)" json:"gem_ids"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;not null" json:"updated_at"`
}
+5 -7
View File
@@ -7,17 +7,15 @@ type VideoJob struct {
UserId uint `gorm:"column:user_id;type:int(11);not null;comment:用户 ID" json:"user_id"`
Channel string `gorm:"column:channel;type:varchar(100);not null;comment:渠道" json:"channel"`
TaskId string `gorm:"column:task_id;type:varchar(100);not null;comment:任务 ID" json:"task_id"`
TaskInfo string `gorm:"column:task_info;type:text;comment:原始任务信息" json:"task_info"`
Params string `gorm:"column:params;type:text;comment:视频任务参数 JSON" json:"params"`
Type string `gorm:"column:type;type:varchar(20);comment:任务类型,luma,runway,cogvideo" json:"type"`
Prompt string `gorm:"column:prompt;type:text;not null;comment:提示词" json:"prompt"`
PromptExt string `gorm:"column:prompt_ext;type:text;comment:优化后提示词" json:"prompt_ext"`
CoverURL string `gorm:"column:cover_url;type:varchar(512);comment:封面图地址" json:"cover_url"`
VideoURL string `gorm:"column:video_url;type:varchar(512);comment:视频地址" json:"video_url"`
WaterURL string `gorm:"column:water_url;type:varchar(512);comment:带水印的视频地址" json:"water_url"`
Progress int `gorm:"column:progress;type:smallint;default:0;comment:任务进度" json:"progress"`
VideoURL string `gorm:"column:video_url;type:varchar(2000);not null;comment:视频地址" json:"video_url"`
Status string `gorm:"column:status;type:varchar(20);default:pending;comment:任务状态:pending,in_progress,downloading,success,failed" json:"status"`
Progress int `gorm:"column:progress;type:smallint;default:0;comment:任务进度(0-100)" json:"progress"`
Publish int `gorm:"column:publish;type:tinyint(1);not null;comment:是否发布" json:"publish"`
ErrMsg string `gorm:"column:err_msg;type:varchar(1024);comment:错误信息" json:"err_msg"`
RawData string `gorm:"column:raw_data;type:text;comment:原始数据" json:"raw_data"`
Output string `gorm:"column:output;type:text;comment:任务输出的原始信息" json:"output"`
Power int `gorm:"column:power;type:smallint;not null;default:0;comment:消耗算力" json:"power"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"`
}
+8 -8
View File
@@ -10,20 +10,20 @@ package store
import (
"fmt"
"geekai/core/types"
logger2 "geekai/logger"
"geekai/log"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
logger2 "gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var log = logger2.GetLogger()
var logger = log.GetLogger()
func NewGormConfig() *gorm.Config {
return &gorm.Config{
Logger: logger.Default.LogMode(logger.Warn),
Logger: logger2.Default.LogMode(logger2.Warn),
NamingStrategy: schema.NamingStrategy{
TablePrefix: "geekai_", // 设置表前缀
SingularTable: false, // 使用单数表名形式
@@ -46,7 +46,7 @@ func NewMysql(config *gorm.Config, appConfig *types.AppConfig) (*gorm.DB, error)
sqlDB.SetMaxOpenConns(512)
sqlDB.SetConnMaxLifetime(time.Hour)
log.Info("开始重命名数据表...")
logger.Info("开始重命名数据表...")
// 重命名数据表
tableRenames := map[string]string{
@@ -61,12 +61,12 @@ func NewMysql(config *gorm.Config, appConfig *types.AppConfig) (*gorm.DB, error)
"chatgpt_orders": "geekai_orders",
"chatgpt_products": "geekai_products",
"chatgpt_configs": "geekai_configs",
"chatgpt_sd_jobs": "geekai_sd_jobs",
"chatgpt_mj_jobs": "geekai_mj_jobs",
"chatgpt_suno_jobs": "geekai_suno_jobs",
"chatgpt_dall_jobs": "geekai_dall_jobs",
"chatgpt_video_jobs": "geekai_video_jobs",
"chatgpt_jimeng_jobs": "geekai_jimeng_jobs",
"chatgpt_ppt_jobs": "geekai_ppt_jobs",
"chatgpt_files": "geekai_files",
"chatgpt_menus": "geekai_menus",
"chatgpt_functions": "geekai_functions",
@@ -83,9 +83,9 @@ func NewMysql(config *gorm.Config, appConfig *types.AppConfig) (*gorm.DB, error)
if !db.Migrator().HasTable(newTableName) {
err := db.Exec(fmt.Sprintf("ALTER TABLE %s RENAME TO %s", oldTableName, newTableName)).Error
if err != nil {
log.Errorf("重命名数据表 %s 到 %s 失败: %v", oldTableName, newTableName, err)
logger.Errorf("重命名数据表 %s 到 %s 失败: %v", oldTableName, newTableName, err)
} else {
log.Infof("成功重命名数据表: %s -> %s", oldTableName, newTableName)
logger.Infof("成功重命名数据表: %s -> %s", oldTableName, newTableName)
}
}
}
+11 -13
View File
@@ -1,18 +1,16 @@
package vo
import "geekai/core/types"
type ChatApp struct {
BaseVo
Key string `json:"key"` // 角色唯一标识
Tid uint `json:"tid"`
Name string `json:"name"` // 角色名称
Context []types.Message `json:"context"` // 角色语料信息
HelloMsg string `json:"hello_msg"` // 打招呼的消息
Icon string `json:"icon"` // 角色聊天图标
Enable bool `json:"enable"` // 是否启用被启用
SortNum int `json:"sort"` // 排序
ModelId uint `json:"model_id"` // 绑定模型 ID
ModelName string `json:"model_name"` // 模型名称
TypeName string `json:"type_name"` // 分类名称
Tid uint `json:"tid"`
Name string `json:"name"` // 角色名称
UserId uint `json:"user_id"` // 所属用户 ID0 表示系统内置
SystemPrompt string `json:"system_prompt,omitempty"` // 系统提示词(列表接口对内置智能体不下发)
HelloMsg string `json:"hello_msg"` // 打招呼的消息
Icon string `json:"icon"` // 角色聊天图标
Enable bool `json:"enable"` // 是否启用
SortNum int `json:"sort"` // 排序
ModelId uint `json:"model_id"` // 绑定模型 ID
ModelName string `json:"model_name"` // 模型名称
TypeName string `json:"type_name"` // 分类名称
}
-14
View File
@@ -1,14 +0,0 @@
package vo
type DallJob struct {
Id uint `json:"id"`
UserId int `json:"user_id"`
Prompt string `json:"prompt"`
ImgURL string `json:"img_url"`
OrgURL string `json:"org_url"`
Publish bool `json:"publish"`
Power int `json:"power"`
Progress int `json:"progress"`
ErrMsg string `json:"err_msg"`
CreatedAt int64 `json:"created_at"`
}
+15
View File
@@ -0,0 +1,15 @@
package vo
type ImageJob struct {
Id uint `json:"id"`
UserId int `json:"user_id"`
Prompt string `json:"prompt"`
Params string `json:"params"`
ImgURL string `json:"img_url"`
OrgURL string `json:"org_url"`
Publish bool `json:"publish"`
Power int `json:"power"`
Progress int `json:"progress"`
ErrMsg string `json:"err_msg"`
CreatedAt int64 `json:"created_at"`
}
+110
View File
@@ -0,0 +1,110 @@
package vo
import (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
)
// PPTSlideImageVersion 单页配图历史中的一条(图片地址 + 文生图/图生图提示)
type PPTSlideImageVersion struct {
ImageURL string `json:"image_url"`
Prompt string `json:"prompt"`
}
// PPTSlideImageVersions 存库 JSON 数组;UnmarshalJSON 兼容旧版仅字符串数组
type PPTSlideImageVersions []PPTSlideImageVersion
// UnmarshalJSON 兼容 ["url1","url2"] 与 [{"image_url":"...","prompt":"..."}]
func (v *PPTSlideImageVersions) UnmarshalJSON(data []byte) error {
if len(data) == 0 || string(data) == "null" {
*v = nil
return nil
}
var raw []json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
out := make([]PPTSlideImageVersion, 0, len(raw))
for _, item := range raw {
item = bytes.TrimSpace(item)
if len(item) == 0 || string(item) == "null" {
continue
}
if item[0] == '"' {
var s string
if err := json.Unmarshal(item, &s); err != nil {
return err
}
out = append(out, PPTSlideImageVersion{ImageURL: s, Prompt: ""})
continue
}
var o PPTSlideImageVersion
if err := json.Unmarshal(item, &o); err != nil {
return err
}
out = append(out, o)
}
*v = out
return nil
}
// PPTParams 生成参数(语言、生成模式、页数)
type PPTParams struct {
Language string `json:"language"` // 输出语言,如 zh-CN, en
Mode string `json:"mode"` // 生成模式:detailed | slides
Pages int `json:"pages"` // 目标页数
}
// Value 实现 driver.Valuer,序列化为 JSON 存储
func (p PPTParams) Value() (driver.Value, error) {
return json.Marshal(p)
}
// Scan 实现 sql.Scanner,从数据库读取 JSON
func (p *PPTParams) Scan(value any) error {
if value == nil {
return nil
}
bytes, ok := value.([]byte)
if !ok {
return fmt.Errorf("failed to unmarshal PPTParams value: %v", value)
}
return json.Unmarshal(bytes, p)
}
// PPTSlideData 单页幻灯片数据(与 service/ppt SlideData 一致)
type PPTSlideData struct {
SlideIndex int `json:"slide_index"`
Theme string `json:"theme"`
Title string `json:"title"`
Points []string `json:"points"`
ImagePrompt string `json:"image_prompt"`
ImageURL string `json:"image_url"`
ImageHistory PPTSlideImageVersions `json:"image_history,omitempty"`
}
// PPTSlides 幻灯片列表(JSON 数组)
type PPTSlides []PPTSlideData
// Value 实现 driver.Valuer
func (s PPTSlides) Value() (driver.Value, error) {
if len(s) == 0 {
return "[]", nil
}
return json.Marshal(s)
}
// Scan 实现 sql.Scanner
func (s *PPTSlides) Scan(value any) error {
if value == nil {
*s = nil
return nil
}
bytes, ok := value.([]byte)
if !ok {
return fmt.Errorf("failed to unmarshal PPTSlides value: %v", value)
}
return json.Unmarshal(bytes, s)
}
-20
View File
@@ -1,20 +0,0 @@
package vo
import (
"geekai/core/types"
)
type SdJob struct {
Id uint `json:"id"`
Type string `json:"type"`
UserId uint `json:"user_id"`
TaskId string `json:"task_id"`
ImgURL string `json:"img_url"`
Params types.SdTaskParams `json:"params"`
Progress int `json:"progress"`
Prompt string `json:"prompt"`
Publish bool `json:"publish"`
ErrMsg string `json:"err_msg"`
Power int `json:"power"`
CreatedAt int64 `json:"created_at"`
}
+38 -1
View File
@@ -1,5 +1,41 @@
package vo
import (
"database/sql/driver"
"encoding/json"
"fmt"
)
// SunoParam Suno 任务参数
type SunoParam struct {
Prompt string `json:"prompt"` // 提示词
Instrumental bool `json:"instrumental"` // 是否为纯音乐
Tags string `json:"tags"` // 歌曲风格和标签
ExtendSecs int `json:"extend_secs"` // 续写秒数
Lyrics string `json:"lyrics,omitempty"` // 歌词(可选)
Model string `json:"model"` // 模型名称
}
// Value 实现 driver.Valuer 接口,用于将 SunoParam 序列化为 JSON 字符串存储到数据库
func (p SunoParam) Value() (driver.Value, error) {
if p.Prompt == "" && !p.Instrumental && p.Tags == "" && p.ExtendSecs == 0 && p.Lyrics == "" && p.Model == "" {
return nil, nil
}
return json.Marshal(p)
}
// Scan 实现 sql.Scanner 接口,用于从数据库读取 JSON 字符串并反序列化为 SunoParam
func (p *SunoParam) Scan(value any) error {
if value == nil {
return nil
}
bytes, ok := value.([]byte)
if !ok {
return fmt.Errorf("failed to unmarshal SunoParam value: %v", value)
}
return json.Unmarshal(bytes, p)
}
type SunoJob struct {
Id uint `json:"id"`
UserId uint `json:"user_id"`
@@ -21,7 +57,8 @@ type SunoJob struct {
Duration int `json:"duration"` // 银屏时长,秒
Publish bool `json:"publish"` // 是否发布
ErrMsg string `json:"err_msg"` // 错误信息
RawData map[string]interface{} `json:"raw_data"` // 原始数据 json
Output map[string]interface{} `json:"output"` // 原始输出数据 json
Params SunoParam `json:"params"` // 任务参数
Power int `json:"power"` // 消耗算力
RefSong map[string]interface{} `json:"ref_song,omitempty"`
User map[string]interface{} `json:"user,omitempty"` //关联用户信息
+16 -16
View File
@@ -2,20 +2,20 @@ package vo
type User struct {
BaseVo
Username string `json:"username"`
Nickname string `json:"nickname"`
Mobile string `json:"mobile"`
Email string `json:"email"`
Avatar string `json:"avatar"`
Salt string `json:"salt"` // 密码盐
Power int `json:"power"` // 剩余算力
ChatRoles []string `json:"chat_roles"` // 聊天角色集合
ChatModels []int `json:"chat_models"` // AI模型集合
ExpiredTime int64 `json:"expired_time"` // 账户到期时间
Status bool `json:"status"` // 当前状态
LastLoginAt int64 `json:"last_login_at"` // 最后登录时间
LastLoginIp string `json:"last_login_ip"` // 最后登录 IP
Vip bool `json:"vip"`
OpenId string `json:"openid"` // 第三方登录 OpenID
Platform string `json:"platform"` // 第三方登录平台
Username string `json:"username"`
Nickname string `json:"nickname"`
Mobile string `json:"mobile"`
Email string `json:"email"`
Avatar string `json:"avatar"`
Salt string `json:"salt"` // 密码盐
Power int `json:"power"` // 剩余算力
ChatModels []int `json:"chat_models"` // AI模型集合
ChatRoles []uint `json:"chat_roles"` // 工作区应用 ID 列表
ExpiredTime int64 `json:"expired_time"` // 账户到期时间
Status bool `json:"status"` // 当前状态
LastLoginAt int64 `json:"last_login_at"`
LastLoginIp string `json:"last_login_ip"`
Vip bool `json:"vip"`
OpenId string `json:"openid"` // 第三方登录 OpenID
Platform string `json:"platform"` // 第三方登录平台
}
+15 -16
View File
@@ -1,20 +1,19 @@
package vo
type VideoJob struct {
Id uint `json:"id"`
UserId uint `json:"user_id"`
Channel string `json:"channel"`
Type string `json:"type"`
TaskId string `json:"task_id"`
Prompt string `json:"prompt"` // 提示词
PromptExt string `json:"prompt_ext"` // 提示词
CoverURL string `json:"cover_url"` // 封面图 URL
VideoURL string `json:"video_url"` // 无水印视频 URL
WaterURL string `json:"water_url"` // 有水印视频 URL
Progress int `json:"progress"` // 任务进度
Publish bool `json:"publish"` // 是否发布
ErrMsg string `json:"err_msg"` // 错误信息
RawData map[string]interface{} `json:"raw_data"` // 原始数据 json
Power int `json:"power"` // 消耗算力
CreatedAt int64 `json:"created_at"`
Id uint `json:"id"`
UserId uint `json:"user_id"`
Channel string `json:"channel"`
Type string `json:"type"`
TaskId string `json:"task_id"`
Prompt string `json:"prompt"` // 提示词
VideoURL string `json:"video_url"` // 视频 URL
Status string `json:"status"` // 任务状态
Progress int `json:"progress"` // 任务进度(0-100)
Publish bool `json:"publish"` // 是否发布
ErrMsg string `json:"err_msg"` // 错误信息
Params map[string]any `json:"params"` // 任务参数 json(用于前端显示)
Output map[string]any `json:"output"` // 任务输出信息 json(管理后台使用)
Power int `json:"power"` // 消耗算力
CreatedAt int64 `json:"created_at"`
}