create project

This commit is contained in:
2026-01-16 17:30:40 +08:00
commit effac6b017
157 changed files with 45997 additions and 0 deletions

124
domain/models/ai_config.go Normal file
View 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
View 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"
}

View 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
View 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"
}

View 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"
)

View 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
View 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
View 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"
}

View 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"
}

View 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"
}