create project
This commit is contained in:
124
domain/models/ai_config.go
Normal file
124
domain/models/ai_config.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AIServiceConfig struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
ServiceType string `gorm:"type:varchar(50);not null" json:"service_type"` // text, image, video
|
||||
Provider string `gorm:"type:varchar(50)" json:"provider"` // openai, gemini, volcengine, etc.
|
||||
Name string `gorm:"type:varchar(100);not null" json:"name"`
|
||||
BaseURL string `gorm:"type:varchar(255);not null" json:"base_url"`
|
||||
APIKey string `gorm:"type:varchar(255);not null" json:"api_key"`
|
||||
Model ModelField `gorm:"type:text" json:"model"`
|
||||
Endpoint string `gorm:"type:varchar(255)" json:"endpoint"`
|
||||
QueryEndpoint string `gorm:"type:varchar(255)" json:"query_endpoint"`
|
||||
Priority int `gorm:"default:0" json:"priority"` // 优先级,数值越大优先级越高
|
||||
IsDefault bool `gorm:"default:false" json:"is_default"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
Settings string `gorm:"type:text" json:"settings"`
|
||||
CreatedAt time.Time `gorm:"not null;autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"not null;autoUpdateTime" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (c *AIServiceConfig) TableName() string {
|
||||
return "ai_service_configs"
|
||||
}
|
||||
|
||||
type AIServiceProvider struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
Name string `gorm:"type:varchar(100);not null;uniqueIndex" json:"name"`
|
||||
DisplayName string `gorm:"type:varchar(100);not null" json:"display_name"`
|
||||
ServiceType string `gorm:"type:varchar(50);not null" json:"service_type"`
|
||||
DefaultURL string `gorm:"type:varchar(255)" json:"default_url"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `gorm:"not null;autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"not null;autoUpdateTime" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (p *AIServiceProvider) TableName() string {
|
||||
return "ai_service_providers"
|
||||
}
|
||||
|
||||
// ModelField 自定义类型,支持字符串或字符串数组
|
||||
type ModelField []string
|
||||
|
||||
// Value 实现 driver.Valuer 接口,用于存储到数据库
|
||||
func (m ModelField) Value() (driver.Value, error) {
|
||||
if len(m) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
data, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
// Scan 实现 sql.Scanner 接口,用于从数据库读取
|
||||
func (m *ModelField) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
*m = []string{}
|
||||
return nil
|
||||
}
|
||||
|
||||
var data []byte
|
||||
switch v := value.(type) {
|
||||
case []byte:
|
||||
data = v
|
||||
case string:
|
||||
data = []byte(v)
|
||||
default:
|
||||
return errors.New("unsupported type for ModelField")
|
||||
}
|
||||
|
||||
// 尝试解析为数组
|
||||
var arr []string
|
||||
if err := json.Unmarshal(data, &arr); err == nil {
|
||||
*m = arr
|
||||
return nil
|
||||
}
|
||||
|
||||
// 如果解析失败,尝试作为单个字符串处理
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err == nil {
|
||||
*m = []string{str}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 兼容旧数据:直接作为字符串
|
||||
*m = []string{string(data)}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON 实现 json.Marshaler 接口
|
||||
func (m ModelField) MarshalJSON() ([]byte, error) {
|
||||
if len(m) == 0 {
|
||||
return json.Marshal([]string{})
|
||||
}
|
||||
return json.Marshal([]string(m))
|
||||
}
|
||||
|
||||
// UnmarshalJSON 实现 json.Unmarshaler 接口,支持字符串或数组
|
||||
func (m *ModelField) UnmarshalJSON(data []byte) error {
|
||||
// 尝试解析为数组
|
||||
var arr []string
|
||||
if err := json.Unmarshal(data, &arr); err == nil {
|
||||
*m = arr
|
||||
return nil
|
||||
}
|
||||
|
||||
// 尝试解析为单个字符串
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err == nil {
|
||||
*m = []string{str}
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("model field must be string or array of strings")
|
||||
}
|
||||
57
domain/models/asset.go
Normal file
57
domain/models/asset.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Asset struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
DramaID *uint `gorm:"index" json:"drama_id,omitempty"`
|
||||
Drama *Drama `gorm:"foreignKey:DramaID" json:"drama,omitempty"`
|
||||
|
||||
EpisodeID *uint `gorm:"index" json:"episode_id,omitempty"`
|
||||
StoryboardID *uint `gorm:"index" json:"storyboard_id,omitempty"`
|
||||
StoryboardNum *int `json:"storyboard_num,omitempty"`
|
||||
|
||||
Name string `gorm:"type:varchar(200);not null" json:"name"`
|
||||
Description *string `gorm:"type:text" json:"description,omitempty"`
|
||||
Type AssetType `gorm:"type:varchar(20);not null;index" json:"type"`
|
||||
Category *string `gorm:"type:varchar(50);index" json:"category,omitempty"`
|
||||
URL string `gorm:"type:varchar(1000);not null" json:"url"`
|
||||
ThumbnailURL *string `gorm:"type:varchar(1000)" json:"thumbnail_url,omitempty"`
|
||||
LocalPath *string `gorm:"type:varchar(500)" json:"local_path,omitempty"`
|
||||
|
||||
FileSize *int64 `json:"file_size,omitempty"`
|
||||
MimeType *string `gorm:"type:varchar(100)" json:"mime_type,omitempty"`
|
||||
Width *int `json:"width,omitempty"`
|
||||
Height *int `json:"height,omitempty"`
|
||||
Duration *int `json:"duration,omitempty"`
|
||||
Format *string `gorm:"type:varchar(50)" json:"format,omitempty"`
|
||||
|
||||
ImageGenID *uint `gorm:"index" json:"image_gen_id,omitempty"`
|
||||
ImageGen ImageGeneration `gorm:"foreignKey:ImageGenID" json:"image_gen,omitempty"`
|
||||
|
||||
VideoGenID *uint `gorm:"index" json:"video_gen_id,omitempty"`
|
||||
VideoGen VideoGeneration `gorm:"foreignKey:VideoGenID" json:"video_gen,omitempty"`
|
||||
|
||||
IsFavorite bool `gorm:"default:false" json:"is_favorite"`
|
||||
ViewCount int `gorm:"default:0" json:"view_count"`
|
||||
}
|
||||
|
||||
type AssetType string
|
||||
|
||||
const (
|
||||
AssetTypeImage AssetType = "image"
|
||||
AssetTypeVideo AssetType = "video"
|
||||
AssetTypeAudio AssetType = "audio"
|
||||
)
|
||||
|
||||
func (Asset) TableName() string {
|
||||
return "assets"
|
||||
}
|
||||
25
domain/models/character_library.go
Normal file
25
domain/models/character_library.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// CharacterLibrary 角色库模型
|
||||
type CharacterLibrary struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
Name string `gorm:"type:varchar(100);not null" json:"name"`
|
||||
Category *string `gorm:"type:varchar(50)" json:"category"`
|
||||
ImageURL string `gorm:"type:varchar(500);not null" json:"image_url"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
Tags *string `gorm:"type:varchar(500)" json:"tags"`
|
||||
SourceType string `gorm:"type:varchar(20);default:'generated'" json:"source_type"` // generated, uploaded
|
||||
CreatedAt time.Time `gorm:"not null;autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"not null;autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
func (c *CharacterLibrary) TableName() string {
|
||||
return "character_libraries"
|
||||
}
|
||||
148
domain/models/drama.go
Normal file
148
domain/models/drama.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Drama struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
Title string `gorm:"type:varchar(200);not null" json:"title"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
Genre *string `gorm:"type:varchar(50)" json:"genre"`
|
||||
Style string `gorm:"type:varchar(50);default:'realistic'" json:"style"`
|
||||
TotalEpisodes int `gorm:"default:1" json:"total_episodes"`
|
||||
TotalDuration int `gorm:"default:0" json:"total_duration"`
|
||||
Status string `gorm:"type:varchar(20);default:'draft';not null" json:"status"`
|
||||
Thumbnail *string `gorm:"type:varchar(500)" json:"thumbnail"`
|
||||
Tags datatypes.JSON `gorm:"type:json" json:"tags"`
|
||||
Metadata datatypes.JSON `gorm:"type:json" json:"metadata"`
|
||||
CreatedAt time.Time `gorm:"not null;autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"not null;autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
Episodes []Episode `gorm:"foreignKey:DramaID" json:"episodes,omitempty"`
|
||||
Characters []Character `gorm:"foreignKey:DramaID" json:"characters,omitempty"`
|
||||
Scenes []Scene `gorm:"foreignKey:DramaID" json:"scenes,omitempty"`
|
||||
}
|
||||
|
||||
func (d *Drama) TableName() string {
|
||||
return "dramas"
|
||||
}
|
||||
|
||||
type Character struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
DramaID uint `gorm:"not null;index" json:"drama_id"`
|
||||
Name string `gorm:"type:varchar(100);not null" json:"name"`
|
||||
Role *string `gorm:"type:varchar(50)" json:"role"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
Appearance *string `gorm:"type:text" json:"appearance"`
|
||||
Personality *string `gorm:"type:text" json:"personality"`
|
||||
VoiceStyle *string `gorm:"type:varchar(200)" json:"voice_style"`
|
||||
ImageURL *string `gorm:"type:varchar(500)" json:"image_url"`
|
||||
ReferenceImages datatypes.JSON `gorm:"type:json" json:"reference_images"`
|
||||
SeedValue *string `gorm:"type:varchar(100)" json:"seed_value"`
|
||||
SortOrder int `gorm:"default:0" json:"sort_order"`
|
||||
CreatedAt time.Time `gorm:"not null;autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"not null;autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
// 多对多关系:角色可以属于多个章节
|
||||
Episodes []Episode `gorm:"many2many:episode_characters;" json:"episodes,omitempty"`
|
||||
|
||||
// 运行时字段(不存储到数据库)
|
||||
ImageGenerationStatus *string `gorm:"-" json:"image_generation_status,omitempty"`
|
||||
ImageGenerationError *string `gorm:"-" json:"image_generation_error,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Character) TableName() string {
|
||||
return "characters"
|
||||
}
|
||||
|
||||
type Episode struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
DramaID uint `gorm:"not null;index" json:"drama_id"`
|
||||
EpisodeNum int `gorm:"column:episode_number;not null" json:"episode_number"`
|
||||
Title string `gorm:"type:varchar(200);not null" json:"title"`
|
||||
ScriptContent *string `gorm:"type:longtext" json:"script_content"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
Duration int `gorm:"default:0" json:"duration"` // 总时长(秒)
|
||||
Status string `gorm:"type:varchar(20);default:'draft'" json:"status"`
|
||||
VideoURL *string `gorm:"type:varchar(500)" json:"video_url"`
|
||||
Thumbnail *string `gorm:"type:varchar(500)" json:"thumbnail"`
|
||||
CreatedAt time.Time `gorm:"not null;autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"not null;autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
// 关联
|
||||
Drama Drama `gorm:"foreignKey:DramaID" json:"drama,omitempty"`
|
||||
Storyboards []Storyboard `gorm:"foreignKey:EpisodeID" json:"storyboards,omitempty"`
|
||||
Characters []Character `gorm:"many2many:episode_characters;" json:"characters,omitempty"`
|
||||
Scenes []Scene `gorm:"foreignKey:EpisodeID" json:"scenes,omitempty"`
|
||||
}
|
||||
|
||||
func (e *Episode) TableName() string {
|
||||
return "episodes"
|
||||
}
|
||||
|
||||
type Storyboard struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
EpisodeID uint `gorm:"not null;index:idx_storyboards_episode_id" json:"episode_id"`
|
||||
SceneID *uint `gorm:"index:idx_storyboards_scene_id;column:scene_id" json:"scene_id"`
|
||||
StoryboardNumber int `gorm:"not null;column:storyboard_number" json:"storyboard_number"`
|
||||
Title *string `gorm:"size:255" json:"title"`
|
||||
Location *string `gorm:"size:255" json:"location"`
|
||||
Time *string `gorm:"size:255" json:"time"`
|
||||
ShotType *string `gorm:"size:100" json:"shot_type"`
|
||||
Angle *string `gorm:"size:100" json:"angle"`
|
||||
Movement *string `gorm:"size:100" json:"movement"`
|
||||
Action *string `gorm:"type:text" json:"action"`
|
||||
Result *string `gorm:"type:text" json:"result"`
|
||||
Atmosphere *string `gorm:"type:text" json:"atmosphere"`
|
||||
ImagePrompt *string `gorm:"type:text" json:"image_prompt"`
|
||||
VideoPrompt *string `gorm:"type:text" json:"video_prompt"`
|
||||
BgmPrompt *string `gorm:"type:text" json:"bgm_prompt"`
|
||||
SoundEffect *string `gorm:"size:255" json:"sound_effect"`
|
||||
Dialogue *string `gorm:"type:text" json:"dialogue"`
|
||||
Description *string `gorm:"type:text" json:"description"`
|
||||
Duration int `gorm:"default:5" json:"duration"`
|
||||
ComposedImage *string `gorm:"type:text" json:"composed_image"`
|
||||
VideoURL *string `gorm:"type:text" json:"video_url"`
|
||||
Status string `gorm:"type:varchar(20);default:'pending'" json:"status"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
Episode Episode `gorm:"foreignKey:EpisodeID;constraint:OnDelete:CASCADE" json:"episode,omitempty"`
|
||||
Background *Scene `gorm:"foreignKey:SceneID" json:"background,omitempty"`
|
||||
Characters []Character `gorm:"many2many:storyboard_characters;" json:"characters,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Storyboard) TableName() string {
|
||||
return "storyboards"
|
||||
}
|
||||
|
||||
type Scene struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
DramaID uint `gorm:"not null;index:idx_scenes_drama_id" json:"drama_id"`
|
||||
EpisodeID *uint `gorm:"index:idx_scenes_episode_id" json:"episode_id"` // 场景所属章节
|
||||
Location string `gorm:"type:varchar(200);not null" json:"location"`
|
||||
Time string `gorm:"type:varchar(100);not null" json:"time"`
|
||||
Prompt string `gorm:"type:text;not null" json:"prompt"`
|
||||
StoryboardCount int `gorm:"default:1" json:"storyboard_count"`
|
||||
ImageURL *string `gorm:"type:varchar(500)" json:"image_url"`
|
||||
Status string `gorm:"type:varchar(20);default:'pending'" json:"status"` // pending, generated, failed
|
||||
CreatedAt time.Time `gorm:"not null;autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"not null;autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
// 运行时字段(不存储到数据库)
|
||||
ImageGenerationStatus *string `gorm:"-" json:"image_generation_status,omitempty"`
|
||||
ImageGenerationError *string `gorm:"-" json:"image_generation_error,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Scene) TableName() string {
|
||||
return "scenes"
|
||||
}
|
||||
28
domain/models/frame_prompt.go
Normal file
28
domain/models/frame_prompt.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// FramePrompt 帧提示词存储表
|
||||
type FramePrompt struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
StoryboardID uint `gorm:"not null;index:idx_frame_prompts_storyboard" json:"storyboard_id"`
|
||||
FrameType string `gorm:"size:20;not null;index:idx_frame_prompts_type" json:"frame_type"` // first, key, last, panel, action
|
||||
Prompt string `gorm:"type:text;not null" json:"prompt"`
|
||||
Description *string `gorm:"type:text" json:"description,omitempty"`
|
||||
Layout *string `gorm:"size:50" json:"layout,omitempty"` // 仅用于panel/action类型,如 horizontal_3
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
}
|
||||
|
||||
func (FramePrompt) TableName() string {
|
||||
return "frame_prompts"
|
||||
}
|
||||
|
||||
// FrameType 帧类型常量
|
||||
const (
|
||||
FrameTypeFirst = "first"
|
||||
FrameTypeKey = "key"
|
||||
FrameTypeLast = "last"
|
||||
FrameTypePanel = "panel"
|
||||
FrameTypeAction = "action"
|
||||
)
|
||||
75
domain/models/image_generation.go
Normal file
75
domain/models/image_generation.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
type ImageGeneration struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
StoryboardID *uint `gorm:"index" json:"storyboard_id,omitempty"`
|
||||
DramaID uint `gorm:"not null;index" json:"drama_id"`
|
||||
SceneID *uint `gorm:"index" json:"scene_id,omitempty"`
|
||||
CharacterID *uint `gorm:"index" json:"character_id,omitempty"`
|
||||
ImageType string `gorm:"size:20;index;default:'storyboard'" json:"image_type"`
|
||||
FrameType *string `gorm:"size:20" json:"frame_type,omitempty"`
|
||||
Provider string `gorm:"size:50;not null" json:"provider"`
|
||||
Prompt string `gorm:"type:text;not null" json:"prompt"`
|
||||
NegPrompt *string `gorm:"column:negative_prompt;type:text" json:"negative_prompt,omitempty"`
|
||||
Model string `gorm:"size:100" json:"model"`
|
||||
Size string `gorm:"size:20" json:"size"`
|
||||
Quality string `gorm:"size:20" json:"quality"`
|
||||
Style *string `gorm:"size:50" json:"style,omitempty"`
|
||||
Steps *int `json:"steps,omitempty"`
|
||||
CfgScale *float64 `json:"cfg_scale,omitempty"`
|
||||
Seed *int64 `json:"seed,omitempty"`
|
||||
ImageURL *string `gorm:"type:text" json:"image_url,omitempty"`
|
||||
MinioURL *string `gorm:"type:text" json:"minio_url,omitempty"`
|
||||
LocalPath *string `gorm:"type:text" json:"local_path,omitempty"`
|
||||
Status ImageGenerationStatus `gorm:"size:20;not null;default:'pending'" json:"status"`
|
||||
TaskID *string `gorm:"size:200" json:"task_id,omitempty"`
|
||||
ErrorMsg *string `gorm:"type:text" json:"error_msg,omitempty"`
|
||||
Width *int `json:"width,omitempty"`
|
||||
Height *int `json:"height,omitempty"`
|
||||
ReferenceImages datatypes.JSON `gorm:"type:json" json:"reference_images,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
||||
|
||||
Storyboard *Storyboard `gorm:"foreignKey:StoryboardID" json:"storyboard,omitempty"`
|
||||
Drama Drama `gorm:"foreignKey:DramaID" json:"drama,omitempty"`
|
||||
Scene *Scene `gorm:"foreignKey:SceneID" json:"scene,omitempty"`
|
||||
Character *Character `gorm:"foreignKey:CharacterID" json:"character,omitempty"`
|
||||
}
|
||||
|
||||
func (ImageGeneration) TableName() string {
|
||||
return "image_generations"
|
||||
}
|
||||
|
||||
type ImageGenerationStatus string
|
||||
|
||||
const (
|
||||
ImageStatusPending ImageGenerationStatus = "pending"
|
||||
ImageStatusProcessing ImageGenerationStatus = "processing"
|
||||
ImageStatusCompleted ImageGenerationStatus = "completed"
|
||||
ImageStatusFailed ImageGenerationStatus = "failed"
|
||||
)
|
||||
|
||||
type ImageProvider string
|
||||
|
||||
const (
|
||||
ProviderOpenAI ImageProvider = "openai"
|
||||
ProviderMidjourney ImageProvider = "midjourney"
|
||||
ProviderStableDiffusion ImageProvider = "stable_diffusion"
|
||||
ProviderDALLE ImageProvider = "dalle"
|
||||
)
|
||||
|
||||
// ImageType 图片类型
|
||||
type ImageType string
|
||||
|
||||
const (
|
||||
ImageTypeCharacter ImageType = "character" // 角色图片
|
||||
ImageTypeScene ImageType = "scene" // 场景图片
|
||||
ImageTypeStoryboard ImageType = "storyboard" // 分镜图片
|
||||
)
|
||||
23
domain/models/task.go
Normal file
23
domain/models/task.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// AsyncTask 异步任务模型
|
||||
type AsyncTask struct {
|
||||
ID string `gorm:"primaryKey;size:36" json:"id"`
|
||||
Type string `gorm:"size:50;not null;index" json:"type"` // 任务类型:storyboard_generation
|
||||
Status string `gorm:"size:20;not null;index" json:"status"` // pending, processing, completed, failed
|
||||
Progress int `gorm:"default:0" json:"progress"` // 0-100
|
||||
Message string `gorm:"size:500" json:"message,omitempty"` // 当前状态消息
|
||||
Error string `gorm:"type:text" json:"error,omitempty"` // 错误信息
|
||||
Result string `gorm:"type:text" json:"result,omitempty"` // JSON格式的结果数据
|
||||
ResourceID string `gorm:"size:36;index" json:"resource_id"` // 关联资源ID(如episode_id)
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
178
domain/models/timeline.go
Normal file
178
domain/models/timeline.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Timeline struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
DramaID uint `gorm:"not null;index" json:"drama_id"`
|
||||
Drama Drama `gorm:"foreignKey:DramaID" json:"drama,omitempty"`
|
||||
|
||||
EpisodeID *uint `gorm:"index" json:"episode_id,omitempty"`
|
||||
Episode *Episode `gorm:"foreignKey:EpisodeID" json:"episode,omitempty"`
|
||||
|
||||
Name string `gorm:"type:varchar(200);not null" json:"name"`
|
||||
Description *string `gorm:"type:text" json:"description,omitempty"`
|
||||
|
||||
Duration int `gorm:"default:0" json:"duration"`
|
||||
FPS int `gorm:"default:30" json:"fps"`
|
||||
Resolution *string `gorm:"type:varchar(50)" json:"resolution,omitempty"`
|
||||
|
||||
Status TimelineStatus `gorm:"type:varchar(20);not null;default:'draft';index" json:"status"`
|
||||
|
||||
Tracks []TimelineTrack `gorm:"foreignKey:TimelineID" json:"tracks,omitempty"`
|
||||
}
|
||||
|
||||
type TimelineStatus string
|
||||
|
||||
const (
|
||||
TimelineStatusDraft TimelineStatus = "draft"
|
||||
TimelineStatusEditing TimelineStatus = "editing"
|
||||
TimelineStatusCompleted TimelineStatus = "completed"
|
||||
TimelineStatusExporting TimelineStatus = "exporting"
|
||||
)
|
||||
|
||||
func (Timeline) TableName() string {
|
||||
return "timelines"
|
||||
}
|
||||
|
||||
type TimelineTrack struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
TimelineID uint `gorm:"not null;index" json:"timeline_id"`
|
||||
Timeline Timeline `gorm:"foreignKey:TimelineID" json:"-"`
|
||||
|
||||
Name string `gorm:"type:varchar(100);not null" json:"name"`
|
||||
Type TrackType `gorm:"type:varchar(20);not null" json:"type"`
|
||||
Order int `gorm:"not null;default:0" json:"order"`
|
||||
IsLocked bool `gorm:"default:false" json:"is_locked"`
|
||||
IsMuted bool `gorm:"default:false" json:"is_muted"`
|
||||
Volume *int `gorm:"default:100" json:"volume,omitempty"`
|
||||
|
||||
Clips []TimelineClip `gorm:"foreignKey:TrackID" json:"clips,omitempty"`
|
||||
}
|
||||
|
||||
type TrackType string
|
||||
|
||||
const (
|
||||
TrackTypeVideo TrackType = "video"
|
||||
TrackTypeAudio TrackType = "audio"
|
||||
TrackTypeText TrackType = "text"
|
||||
)
|
||||
|
||||
func (TimelineTrack) TableName() string {
|
||||
return "timeline_tracks"
|
||||
}
|
||||
|
||||
type TimelineClip struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
TrackID uint `gorm:"not null;index" json:"track_id"`
|
||||
Track TimelineTrack `gorm:"foreignKey:TrackID" json:"-"`
|
||||
|
||||
AssetID *uint `gorm:"index" json:"asset_id,omitempty"`
|
||||
Asset Asset `gorm:"foreignKey:AssetID" json:"asset,omitempty"`
|
||||
|
||||
StoryboardID *uint `gorm:"index" json:"storyboard_id,omitempty"`
|
||||
Storyboard *Storyboard `gorm:"foreignKey:StoryboardID" json:"storyboard,omitempty"`
|
||||
|
||||
Name string `gorm:"type:varchar(200)" json:"name"`
|
||||
|
||||
StartTime int `gorm:"not null" json:"start_time"`
|
||||
EndTime int `gorm:"not null" json:"end_time"`
|
||||
Duration int `gorm:"not null" json:"duration"`
|
||||
|
||||
TrimStart *int `json:"trim_start,omitempty"`
|
||||
TrimEnd *int `json:"trim_end,omitempty"`
|
||||
|
||||
Speed *float64 `gorm:"default:1.0" json:"speed,omitempty"`
|
||||
|
||||
Volume *int `json:"volume,omitempty"`
|
||||
IsMuted bool `gorm:"default:false" json:"is_muted"`
|
||||
FadeIn *int `json:"fade_in,omitempty"`
|
||||
FadeOut *int `json:"fade_out,omitempty"`
|
||||
|
||||
TransitionIn *uint `gorm:"index" json:"transition_in_id,omitempty"`
|
||||
TransitionOut *uint `gorm:"index" json:"transition_out_id,omitempty"`
|
||||
InTransition ClipTransition `gorm:"foreignKey:TransitionIn" json:"in_transition,omitempty"`
|
||||
OutTransition ClipTransition `gorm:"foreignKey:TransitionOut" json:"out_transition,omitempty"`
|
||||
|
||||
Effects []ClipEffect `gorm:"foreignKey:ClipID" json:"effects,omitempty"`
|
||||
}
|
||||
|
||||
func (TimelineClip) TableName() string {
|
||||
return "timeline_clips"
|
||||
}
|
||||
|
||||
type ClipTransition struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
Type TransitionType `gorm:"type:varchar(50);not null" json:"type"`
|
||||
Duration int `gorm:"not null;default:500" json:"duration"`
|
||||
Easing *string `gorm:"type:varchar(50)" json:"easing,omitempty"`
|
||||
|
||||
Config map[string]interface{} `gorm:"serializer:json" json:"config,omitempty"`
|
||||
}
|
||||
|
||||
type TransitionType string
|
||||
|
||||
const (
|
||||
TransitionTypeFade TransitionType = "fade"
|
||||
TransitionTypeCrossFade TransitionType = "crossfade"
|
||||
TransitionTypeSlide TransitionType = "slide"
|
||||
TransitionTypeWipe TransitionType = "wipe"
|
||||
TransitionTypeZoom TransitionType = "zoom"
|
||||
TransitionTypeDissolve TransitionType = "dissolve"
|
||||
)
|
||||
|
||||
func (ClipTransition) TableName() string {
|
||||
return "clip_transitions"
|
||||
}
|
||||
|
||||
type ClipEffect struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
ClipID uint `gorm:"not null;index" json:"clip_id"`
|
||||
Clip TimelineClip `gorm:"foreignKey:ClipID" json:"-"`
|
||||
|
||||
Type EffectType `gorm:"type:varchar(50);not null" json:"type"`
|
||||
Name string `gorm:"type:varchar(100)" json:"name"`
|
||||
IsEnabled bool `gorm:"default:true" json:"is_enabled"`
|
||||
Order int `gorm:"default:0" json:"order"`
|
||||
|
||||
Config map[string]interface{} `gorm:"serializer:json" json:"config,omitempty"`
|
||||
}
|
||||
|
||||
type EffectType string
|
||||
|
||||
const (
|
||||
EffectTypeFilter EffectType = "filter"
|
||||
EffectTypeColor EffectType = "color"
|
||||
EffectTypeBlur EffectType = "blur"
|
||||
EffectTypeBrightness EffectType = "brightness"
|
||||
EffectTypeContrast EffectType = "contrast"
|
||||
EffectTypeSaturation EffectType = "saturation"
|
||||
)
|
||||
|
||||
func (ClipEffect) TableName() string {
|
||||
return "clip_effects"
|
||||
}
|
||||
79
domain/models/video_generation.go
Normal file
79
domain/models/video_generation.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type VideoGeneration struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
StoryboardID *uint `gorm:"index" json:"storyboard_id,omitempty"`
|
||||
Storyboard *Storyboard `gorm:"foreignKey:StoryboardID" json:"storyboard,omitempty"`
|
||||
|
||||
DramaID uint `gorm:"not null;index" json:"drama_id"`
|
||||
Drama Drama `gorm:"foreignKey:DramaID" json:"drama,omitempty"`
|
||||
|
||||
Provider string `gorm:"type:varchar(50);not null;index" json:"provider"`
|
||||
Prompt string `gorm:"type:text;not null" json:"prompt"`
|
||||
Model string `gorm:"type:varchar(100)" json:"model,omitempty"`
|
||||
|
||||
ImageGenID *uint `gorm:"index" json:"image_gen_id,omitempty"`
|
||||
ImageGen ImageGeneration `gorm:"foreignKey:ImageGenID" json:"image_gen,omitempty"`
|
||||
|
||||
// 参考图模式:single(单图), first_last(首尾帧), multiple(多图), none(无)
|
||||
ReferenceMode *string `gorm:"type:varchar(20)" json:"reference_mode,omitempty"`
|
||||
|
||||
ImageURL *string `gorm:"type:varchar(1000)" json:"image_url,omitempty"`
|
||||
FirstFrameURL *string `gorm:"type:varchar(1000)" json:"first_frame_url,omitempty"`
|
||||
LastFrameURL *string `gorm:"type:varchar(1000)" json:"last_frame_url,omitempty"`
|
||||
ReferenceImageURLs *string `gorm:"type:text" json:"reference_image_urls,omitempty"` // JSON数组存储多张参考图
|
||||
|
||||
Duration *int `json:"duration,omitempty"`
|
||||
FPS *int `json:"fps,omitempty"`
|
||||
Resolution *string `gorm:"type:varchar(50)" json:"resolution,omitempty"`
|
||||
AspectRatio *string `gorm:"type:varchar(20)" json:"aspect_ratio,omitempty"`
|
||||
Style *string `gorm:"type:varchar(100)" json:"style,omitempty"`
|
||||
MotionLevel *int `json:"motion_level,omitempty"`
|
||||
CameraMotion *string `gorm:"type:varchar(100)" json:"camera_motion,omitempty"`
|
||||
Seed *int64 `json:"seed,omitempty"`
|
||||
|
||||
VideoURL *string `gorm:"type:varchar(1000)" json:"video_url,omitempty"`
|
||||
MinioURL *string `gorm:"type:varchar(1000)" json:"minio_url,omitempty"`
|
||||
LocalPath *string `gorm:"type:varchar(500)" json:"local_path,omitempty"`
|
||||
|
||||
Status VideoStatus `gorm:"type:varchar(20);not null;default:'pending';index" json:"status"`
|
||||
TaskID *string `gorm:"type:varchar(200);index" json:"task_id,omitempty"`
|
||||
|
||||
ErrorMsg *string `gorm:"type:text" json:"error_msg,omitempty"`
|
||||
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
||||
|
||||
Width *int `json:"width,omitempty"`
|
||||
Height *int `json:"height,omitempty"`
|
||||
}
|
||||
|
||||
type VideoStatus string
|
||||
|
||||
const (
|
||||
VideoStatusPending VideoStatus = "pending"
|
||||
VideoStatusProcessing VideoStatus = "processing"
|
||||
VideoStatusCompleted VideoStatus = "completed"
|
||||
VideoStatusFailed VideoStatus = "failed"
|
||||
)
|
||||
|
||||
type VideoProvider string
|
||||
|
||||
const (
|
||||
VideoProviderRunway VideoProvider = "runway"
|
||||
VideoProviderPika VideoProvider = "pika"
|
||||
VideoProviderDoubao VideoProvider = "doubao"
|
||||
VideoProviderOpenAI VideoProvider = "openai"
|
||||
)
|
||||
|
||||
func (VideoGeneration) TableName() string {
|
||||
return "video_generations"
|
||||
}
|
||||
52
domain/models/video_merge.go
Normal file
52
domain/models/video_merge.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type VideoMergeStatus string
|
||||
|
||||
const (
|
||||
VideoMergeStatusPending VideoMergeStatus = "pending"
|
||||
VideoMergeStatusProcessing VideoMergeStatus = "processing"
|
||||
VideoMergeStatusCompleted VideoMergeStatus = "completed"
|
||||
VideoMergeStatusFailed VideoMergeStatus = "failed"
|
||||
)
|
||||
|
||||
type VideoMerge struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
EpisodeID uint `gorm:"not null;index" json:"episode_id"`
|
||||
DramaID uint `gorm:"not null;index" json:"drama_id"`
|
||||
Title string `gorm:"type:varchar(200)" json:"title"`
|
||||
Provider string `gorm:"type:varchar(50);not null" json:"provider"`
|
||||
Model *string `gorm:"type:varchar(100)" json:"model,omitempty"`
|
||||
Status VideoMergeStatus `gorm:"type:varchar(20);not null;default:'pending'" json:"status"`
|
||||
Scenes datatypes.JSON `gorm:"type:json;not null" json:"scenes"`
|
||||
MergedURL *string `gorm:"type:varchar(500)" json:"merged_url,omitempty"`
|
||||
Duration *int `gorm:"type:int" json:"duration,omitempty"`
|
||||
TaskID *string `gorm:"type:varchar(100)" json:"task_id,omitempty"`
|
||||
ErrorMsg *string `gorm:"type:text" json:"error_msg,omitempty"`
|
||||
CreatedAt time.Time `gorm:"not null;autoCreateTime" json:"created_at"`
|
||||
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
Episode Episode `gorm:"foreignKey:EpisodeID" json:"episode,omitempty"`
|
||||
Drama Drama `gorm:"foreignKey:DramaID" json:"drama,omitempty"`
|
||||
}
|
||||
|
||||
type SceneClip struct {
|
||||
SceneID uint `json:"scene_id"`
|
||||
VideoURL string `json:"video_url"`
|
||||
StartTime float64 `json:"start_time"`
|
||||
EndTime float64 `json:"end_time"`
|
||||
Duration float64 `json:"duration"`
|
||||
Order int `json:"order"`
|
||||
Transition map[string]interface{} `json:"transition"`
|
||||
}
|
||||
|
||||
func (v *VideoMerge) TableName() string {
|
||||
return "video_merges"
|
||||
}
|
||||
Reference in New Issue
Block a user