init
This commit is contained in:
136
api/handlers/ai_config.go
Normal file
136
api/handlers/ai_config.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/pkg/config"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type AIConfigHandler struct {
|
||||
aiService *services.AIService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewAIConfigHandler(db *gorm.DB, cfg *config.Config, log *logger.Logger) *AIConfigHandler {
|
||||
return &AIConfigHandler{
|
||||
aiService: services.NewAIService(db, log),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *AIConfigHandler) CreateConfig(c *gin.Context) {
|
||||
var req services.CreateAIConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.aiService.CreateConfig(&req)
|
||||
if err != nil {
|
||||
response.InternalError(c, "创建失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Created(c, config)
|
||||
}
|
||||
|
||||
func (h *AIConfigHandler) GetConfig(c *gin.Context) {
|
||||
|
||||
configID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的配置ID")
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.aiService.GetConfig(uint(configID))
|
||||
if err != nil {
|
||||
if err.Error() == "config not found" {
|
||||
response.NotFound(c, "配置不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "获取失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, config)
|
||||
}
|
||||
|
||||
func (h *AIConfigHandler) ListConfigs(c *gin.Context) {
|
||||
|
||||
serviceType := c.Query("service_type")
|
||||
|
||||
configs, err := h.aiService.ListConfigs(serviceType)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, configs)
|
||||
}
|
||||
|
||||
func (h *AIConfigHandler) UpdateConfig(c *gin.Context) {
|
||||
|
||||
configID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的配置ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req services.UpdateAIConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.aiService.UpdateConfig(uint(configID), &req)
|
||||
if err != nil {
|
||||
if err.Error() == "config not found" {
|
||||
response.NotFound(c, "配置不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "更新失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, config)
|
||||
}
|
||||
|
||||
func (h *AIConfigHandler) DeleteConfig(c *gin.Context) {
|
||||
|
||||
configID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的配置ID")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.aiService.DeleteConfig(uint(configID)); err != nil {
|
||||
if err.Error() == "config not found" {
|
||||
response.NotFound(c, "配置不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "删除失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "删除成功"})
|
||||
}
|
||||
|
||||
func (h *AIConfigHandler) TestConnection(c *gin.Context) {
|
||||
var req services.TestConnectionRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.aiService.TestConnection(&req); err != nil {
|
||||
response.BadRequest(c, "连接测试失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "连接测试成功"})
|
||||
}
|
||||
220
api/handlers/asset.go
Normal file
220
api/handlers/asset.go
Normal file
@@ -0,0 +1,220 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/domain/models"
|
||||
"github.com/drama-generator/backend/pkg/config"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type AssetHandler struct {
|
||||
assetService *services.AssetService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewAssetHandler(db *gorm.DB, cfg *config.Config, log *logger.Logger) *AssetHandler {
|
||||
return &AssetHandler{
|
||||
assetService: services.NewAssetService(db, log),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *AssetHandler) CreateAsset(c *gin.Context) {
|
||||
|
||||
var req services.CreateAssetRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
asset, err := h.assetService.CreateAsset(&req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to create asset", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, asset)
|
||||
}
|
||||
|
||||
func (h *AssetHandler) UpdateAsset(c *gin.Context) {
|
||||
|
||||
assetID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req services.UpdateAssetRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
asset, err := h.assetService.UpdateAsset(uint(assetID), &req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to update asset", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, asset)
|
||||
}
|
||||
|
||||
func (h *AssetHandler) GetAsset(c *gin.Context) {
|
||||
|
||||
assetID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
asset, err := h.assetService.GetAsset(uint(assetID))
|
||||
if err != nil {
|
||||
response.NotFound(c, "素材不存在")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, asset)
|
||||
}
|
||||
|
||||
func (h *AssetHandler) ListAssets(c *gin.Context) {
|
||||
|
||||
var dramaID *string
|
||||
if dramaIDStr := c.Query("drama_id"); dramaIDStr != "" {
|
||||
dramaID = &dramaIDStr
|
||||
}
|
||||
|
||||
var episodeID *uint
|
||||
if episodeIDStr := c.Query("episode_id"); episodeIDStr != "" {
|
||||
if id, err := strconv.ParseUint(episodeIDStr, 10, 32); err == nil {
|
||||
uid := uint(id)
|
||||
episodeID = &uid
|
||||
}
|
||||
}
|
||||
|
||||
var storyboardID *uint
|
||||
if storyboardIDStr := c.Query("storyboard_id"); storyboardIDStr != "" {
|
||||
if id, err := strconv.ParseUint(storyboardIDStr, 10, 32); err == nil {
|
||||
uid := uint(id)
|
||||
storyboardID = &uid
|
||||
}
|
||||
}
|
||||
|
||||
var assetType *models.AssetType
|
||||
if typeStr := c.Query("type"); typeStr != "" {
|
||||
t := models.AssetType(typeStr)
|
||||
assetType = &t
|
||||
}
|
||||
|
||||
var isFavorite *bool
|
||||
if favoriteStr := c.Query("is_favorite"); favoriteStr != "" {
|
||||
if favoriteStr == "true" {
|
||||
fav := true
|
||||
isFavorite = &fav
|
||||
} else if favoriteStr == "false" {
|
||||
fav := false
|
||||
isFavorite = &fav
|
||||
}
|
||||
}
|
||||
|
||||
var tagIDs []uint
|
||||
if tagIDsStr := c.Query("tag_ids"); tagIDsStr != "" {
|
||||
for _, idStr := range strings.Split(tagIDsStr, ",") {
|
||||
if id, err := strconv.ParseUint(strings.TrimSpace(idStr), 10, 32); err == nil {
|
||||
tagIDs = append(tagIDs, uint(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
req := &services.ListAssetsRequest{
|
||||
DramaID: dramaID,
|
||||
EpisodeID: episodeID,
|
||||
StoryboardID: storyboardID,
|
||||
Type: assetType,
|
||||
Category: c.Query("category"),
|
||||
TagIDs: tagIDs,
|
||||
IsFavorite: isFavorite,
|
||||
Search: c.Query("search"),
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
}
|
||||
|
||||
assets, total, err := h.assetService.ListAssets(req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to list assets", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.SuccessWithPagination(c, assets, total, page, pageSize)
|
||||
}
|
||||
|
||||
func (h *AssetHandler) DeleteAsset(c *gin.Context) {
|
||||
|
||||
assetID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.assetService.DeleteAsset(uint(assetID)); err != nil {
|
||||
h.log.Errorw("Failed to delete asset", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, nil)
|
||||
}
|
||||
|
||||
func (h *AssetHandler) ImportFromImageGen(c *gin.Context) {
|
||||
|
||||
imageGenID, err := strconv.ParseUint(c.Param("image_gen_id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
asset, err := h.assetService.ImportFromImageGen(uint(imageGenID))
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to import from image gen", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, asset)
|
||||
}
|
||||
|
||||
func (h *AssetHandler) ImportFromVideoGen(c *gin.Context) {
|
||||
|
||||
videoGenID, err := strconv.ParseUint(c.Param("video_gen_id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
asset, err := h.assetService.ImportFromVideoGen(uint(videoGenID))
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to import from video gen", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, asset)
|
||||
}
|
||||
34
api/handlers/character_batch.go
Normal file
34
api/handlers/character_batch.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// BatchGenerateCharacterImages 批量生成角色图片
|
||||
func (h *CharacterLibraryHandler) BatchGenerateCharacterImages(c *gin.Context) {
|
||||
|
||||
var req struct {
|
||||
CharacterIDs []string `json:"character_ids" binding:"required,min=1"`
|
||||
Model string `json:"model"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 限制批量生成数量
|
||||
if len(req.CharacterIDs) > 10 {
|
||||
response.BadRequest(c, "单次最多生成10个角色")
|
||||
return
|
||||
}
|
||||
|
||||
// 异步批量生成
|
||||
go h.libraryService.BatchGenerateCharacterImages(req.CharacterIDs, h.imageService, req.Model)
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"message": "批量生成任务已提交",
|
||||
"count": len(req.CharacterIDs),
|
||||
})
|
||||
}
|
||||
274
api/handlers/character_library.go
Normal file
274
api/handlers/character_library.go
Normal file
@@ -0,0 +1,274 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
services2 "github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/pkg/config"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CharacterLibraryHandler struct {
|
||||
libraryService *services2.CharacterLibraryService
|
||||
imageService *services2.ImageGenerationService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewCharacterLibraryHandler(db *gorm.DB, cfg *config.Config, log *logger.Logger, transferService *services2.ResourceTransferService) *CharacterLibraryHandler {
|
||||
return &CharacterLibraryHandler{
|
||||
libraryService: services2.NewCharacterLibraryService(db, log),
|
||||
imageService: services2.NewImageGenerationService(db, transferService, log),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// ListLibraryItems 获取角色库列表
|
||||
func (h *CharacterLibraryHandler) ListLibraryItems(c *gin.Context) {
|
||||
|
||||
var query services2.CharacterLibraryQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if query.Page < 1 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.PageSize < 1 || query.PageSize > 100 {
|
||||
query.PageSize = 20
|
||||
}
|
||||
|
||||
items, total, err := h.libraryService.ListLibraryItems(&query)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to list library items", "error", err)
|
||||
response.InternalError(c, "获取角色库失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.SuccessWithPagination(c, items, total, query.Page, query.PageSize)
|
||||
}
|
||||
|
||||
// CreateLibraryItem 添加到角色库
|
||||
func (h *CharacterLibraryHandler) CreateLibraryItem(c *gin.Context) {
|
||||
|
||||
var req services2.CreateLibraryItemRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
item, err := h.libraryService.CreateLibraryItem(&req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to create library item", "error", err)
|
||||
response.InternalError(c, "添加到角色库失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Created(c, item)
|
||||
}
|
||||
|
||||
// GetLibraryItem 获取角色库项详情
|
||||
func (h *CharacterLibraryHandler) GetLibraryItem(c *gin.Context) {
|
||||
|
||||
itemID := c.Param("id")
|
||||
|
||||
item, err := h.libraryService.GetLibraryItem(itemID)
|
||||
if err != nil {
|
||||
if err.Error() == "library item not found" {
|
||||
response.NotFound(c, "角色库项不存在")
|
||||
return
|
||||
}
|
||||
h.log.Errorw("Failed to get library item", "error", err)
|
||||
response.InternalError(c, "获取失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, item)
|
||||
}
|
||||
|
||||
// DeleteLibraryItem 删除角色库项
|
||||
func (h *CharacterLibraryHandler) DeleteLibraryItem(c *gin.Context) {
|
||||
|
||||
itemID := c.Param("id")
|
||||
|
||||
if err := h.libraryService.DeleteLibraryItem(itemID); err != nil {
|
||||
if err.Error() == "library item not found" {
|
||||
response.NotFound(c, "角色库项不存在")
|
||||
return
|
||||
}
|
||||
h.log.Errorw("Failed to delete library item", "error", err)
|
||||
response.InternalError(c, "删除失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "删除成功"})
|
||||
}
|
||||
|
||||
// UploadCharacterImage 上传角色图片
|
||||
func (h *CharacterLibraryHandler) UploadCharacterImage(c *gin.Context) {
|
||||
|
||||
characterID := c.Param("id")
|
||||
|
||||
// TODO: 处理文件上传
|
||||
// 这里需要实现文件上传逻辑,保存到OSS或本地
|
||||
// 暂时使用简单的实现
|
||||
var req struct {
|
||||
ImageURL string `json:"image_url" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.libraryService.UploadCharacterImage(characterID, req.ImageURL); err != nil {
|
||||
if err.Error() == "character not found" {
|
||||
response.NotFound(c, "角色不存在")
|
||||
return
|
||||
}
|
||||
if err.Error() == "unauthorized" {
|
||||
response.Forbidden(c, "无权限")
|
||||
return
|
||||
}
|
||||
h.log.Errorw("Failed to upload character image", "error", err)
|
||||
response.InternalError(c, "上传失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "上传成功"})
|
||||
}
|
||||
|
||||
// ApplyLibraryItemToCharacter 从角色库应用形象
|
||||
func (h *CharacterLibraryHandler) ApplyLibraryItemToCharacter(c *gin.Context) {
|
||||
|
||||
characterID := c.Param("id")
|
||||
|
||||
var req struct {
|
||||
LibraryItemID string `json:"library_item_id" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.libraryService.ApplyLibraryItemToCharacter(characterID, req.LibraryItemID); err != nil {
|
||||
if err.Error() == "library item not found" {
|
||||
response.NotFound(c, "角色库项不存在")
|
||||
return
|
||||
}
|
||||
if err.Error() == "character not found" {
|
||||
response.NotFound(c, "角色不存在")
|
||||
return
|
||||
}
|
||||
if err.Error() == "unauthorized" {
|
||||
response.Forbidden(c, "无权限")
|
||||
return
|
||||
}
|
||||
h.log.Errorw("Failed to apply library item", "error", err)
|
||||
response.InternalError(c, "应用失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "应用成功"})
|
||||
}
|
||||
|
||||
// AddCharacterToLibrary 将角色添加到角色库
|
||||
func (h *CharacterLibraryHandler) AddCharacterToLibrary(c *gin.Context) {
|
||||
|
||||
characterID := c.Param("id")
|
||||
|
||||
var req struct {
|
||||
Category *string `json:"category"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
// 允许空body
|
||||
req.Category = nil
|
||||
}
|
||||
|
||||
item, err := h.libraryService.AddCharacterToLibrary(characterID, req.Category)
|
||||
if err != nil {
|
||||
if err.Error() == "character not found" {
|
||||
response.NotFound(c, "角色不存在")
|
||||
return
|
||||
}
|
||||
if err.Error() == "unauthorized" {
|
||||
response.Forbidden(c, "无权限")
|
||||
return
|
||||
}
|
||||
if err.Error() == "character has no image" {
|
||||
response.BadRequest(c, "角色还没有形象图片")
|
||||
return
|
||||
}
|
||||
h.log.Errorw("Failed to add character to library", "error", err)
|
||||
response.InternalError(c, "添加失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Created(c, item)
|
||||
}
|
||||
|
||||
// UpdateCharacter 更新角色信息
|
||||
func (h *CharacterLibraryHandler) UpdateCharacter(c *gin.Context) {
|
||||
|
||||
characterID := c.Param("id")
|
||||
|
||||
var req struct {
|
||||
Name *string `json:"name"`
|
||||
Appearance *string `json:"appearance"`
|
||||
Personality *string `json:"personality"`
|
||||
Description *string `json:"description"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.libraryService.UpdateCharacter(characterID, &req); err != nil {
|
||||
if err.Error() == "character not found" {
|
||||
response.NotFound(c, "角色不存在")
|
||||
return
|
||||
}
|
||||
if err.Error() == "unauthorized" {
|
||||
response.Forbidden(c, "无权限")
|
||||
return
|
||||
}
|
||||
h.log.Errorw("Failed to update character", "error", err)
|
||||
response.InternalError(c, "更新失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "更新成功"})
|
||||
}
|
||||
|
||||
// DeleteCharacter 删除单个角色
|
||||
func (h *CharacterLibraryHandler) DeleteCharacter(c *gin.Context) {
|
||||
|
||||
characterIDStr := c.Param("id")
|
||||
characterID, err := strconv.ParseUint(characterIDStr, 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的角色ID")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.libraryService.DeleteCharacter(uint(characterID)); err != nil {
|
||||
h.log.Errorw("Failed to delete character", "error", err, "id", characterID)
|
||||
if err.Error() == "character not found" {
|
||||
response.NotFound(c, "角色不存在")
|
||||
return
|
||||
}
|
||||
if err.Error() == "unauthorized" {
|
||||
response.Forbidden(c, "无权删除此角色")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "删除失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "角色已删除"})
|
||||
}
|
||||
38
api/handlers/character_library_gen.go
Normal file
38
api/handlers/character_library_gen.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// GenerateCharacterImage AI生成角色形象
|
||||
func (h *CharacterLibraryHandler) GenerateCharacterImage(c *gin.Context) {
|
||||
|
||||
characterID := c.Param("id")
|
||||
|
||||
// 获取请求体中的model参数
|
||||
var req struct {
|
||||
Model string `json:"model"`
|
||||
}
|
||||
c.ShouldBindJSON(&req)
|
||||
|
||||
imageGen, err := h.libraryService.GenerateCharacterImage(characterID, h.imageService, req.Model)
|
||||
if err != nil {
|
||||
if err.Error() == "character not found" {
|
||||
response.NotFound(c, "角色不存在")
|
||||
return
|
||||
}
|
||||
if err.Error() == "unauthorized" {
|
||||
response.Forbidden(c, "无权限")
|
||||
return
|
||||
}
|
||||
h.log.Errorw("Failed to generate character image", "error", err)
|
||||
response.InternalError(c, "生成失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"message": "角色图片生成已启动",
|
||||
"image_generation": imageGen,
|
||||
})
|
||||
}
|
||||
310
api/handlers/drama.go
Normal file
310
api/handlers/drama.go
Normal file
@@ -0,0 +1,310 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/domain/models"
|
||||
"github.com/drama-generator/backend/pkg/config"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DramaHandler struct {
|
||||
db *gorm.DB
|
||||
dramaService *services.DramaService
|
||||
videoMergeService *services.VideoMergeService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewDramaHandler(db *gorm.DB, cfg *config.Config, log *logger.Logger, transferService *services.ResourceTransferService) *DramaHandler {
|
||||
return &DramaHandler{
|
||||
db: db,
|
||||
dramaService: services.NewDramaService(db, log),
|
||||
videoMergeService: services.NewVideoMergeService(db, transferService, cfg.Storage.LocalPath, cfg.Storage.BaseURL, log),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *DramaHandler) CreateDrama(c *gin.Context) {
|
||||
|
||||
var req services.CreateDramaRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
drama, err := h.dramaService.CreateDrama(&req)
|
||||
if err != nil {
|
||||
response.InternalError(c, "创建失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Created(c, drama)
|
||||
}
|
||||
|
||||
func (h *DramaHandler) GetDrama(c *gin.Context) {
|
||||
|
||||
dramaID := c.Param("id")
|
||||
|
||||
drama, err := h.dramaService.GetDrama(dramaID)
|
||||
if err != nil {
|
||||
if err.Error() == "drama not found" {
|
||||
response.NotFound(c, "剧本不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "获取失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, drama)
|
||||
}
|
||||
|
||||
func (h *DramaHandler) ListDramas(c *gin.Context) {
|
||||
|
||||
var query services.DramaListQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if query.Page < 1 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.PageSize < 1 || query.PageSize > 100 {
|
||||
query.PageSize = 20
|
||||
}
|
||||
|
||||
dramas, total, err := h.dramaService.ListDramas(&query)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.SuccessWithPagination(c, dramas, total, query.Page, query.PageSize)
|
||||
}
|
||||
|
||||
func (h *DramaHandler) UpdateDrama(c *gin.Context) {
|
||||
|
||||
dramaID := c.Param("id")
|
||||
|
||||
var req services.UpdateDramaRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
drama, err := h.dramaService.UpdateDrama(dramaID, &req)
|
||||
if err != nil {
|
||||
if err.Error() == "drama not found" {
|
||||
response.NotFound(c, "剧本不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "更新失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, drama)
|
||||
}
|
||||
|
||||
func (h *DramaHandler) DeleteDrama(c *gin.Context) {
|
||||
|
||||
dramaID := c.Param("id")
|
||||
|
||||
if err := h.dramaService.DeleteDrama(dramaID); err != nil {
|
||||
if err.Error() == "drama not found" {
|
||||
response.NotFound(c, "剧本不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "删除失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "删除成功"})
|
||||
}
|
||||
|
||||
func (h *DramaHandler) GetDramaStats(c *gin.Context) {
|
||||
|
||||
stats, err := h.dramaService.GetDramaStats()
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取统计失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, stats)
|
||||
}
|
||||
|
||||
func (h *DramaHandler) SaveOutline(c *gin.Context) {
|
||||
|
||||
dramaID := c.Param("id")
|
||||
|
||||
var req services.SaveOutlineRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.dramaService.SaveOutline(dramaID, &req); err != nil {
|
||||
if err.Error() == "drama not found" {
|
||||
response.NotFound(c, "剧本不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "保存失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "保存成功"})
|
||||
}
|
||||
|
||||
func (h *DramaHandler) GetCharacters(c *gin.Context) {
|
||||
|
||||
dramaID := c.Param("id")
|
||||
episodeID := c.Query("episode_id") // 可选:如果提供则只返回该章节的角色
|
||||
|
||||
var episodeIDPtr *string
|
||||
if episodeID != "" {
|
||||
episodeIDPtr = &episodeID
|
||||
}
|
||||
|
||||
characters, err := h.dramaService.GetCharacters(dramaID, episodeIDPtr)
|
||||
if err != nil {
|
||||
if err.Error() == "drama not found" {
|
||||
response.NotFound(c, "剧本不存在")
|
||||
return
|
||||
}
|
||||
if err.Error() == "episode not found" {
|
||||
response.NotFound(c, "章节不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "获取角色失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, characters)
|
||||
}
|
||||
|
||||
func (h *DramaHandler) SaveCharacters(c *gin.Context) {
|
||||
|
||||
dramaID := c.Param("id")
|
||||
|
||||
var req services.SaveCharactersRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.dramaService.SaveCharacters(dramaID, &req); err != nil {
|
||||
if err.Error() == "drama not found" {
|
||||
response.NotFound(c, "剧本不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "保存失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "保存成功"})
|
||||
}
|
||||
|
||||
func (h *DramaHandler) SaveEpisodes(c *gin.Context) {
|
||||
|
||||
dramaID := c.Param("id")
|
||||
|
||||
var req services.SaveEpisodesRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.dramaService.SaveEpisodes(dramaID, &req); err != nil {
|
||||
if err.Error() == "drama not found" {
|
||||
response.NotFound(c, "剧本不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "保存失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "保存成功"})
|
||||
}
|
||||
|
||||
func (h *DramaHandler) SaveProgress(c *gin.Context) {
|
||||
|
||||
dramaID := c.Param("id")
|
||||
|
||||
var req services.SaveProgressRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.dramaService.SaveProgress(dramaID, &req); err != nil {
|
||||
if err.Error() == "drama not found" {
|
||||
response.NotFound(c, "剧本不存在")
|
||||
return
|
||||
}
|
||||
response.InternalError(c, "保存失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "保存成功"})
|
||||
}
|
||||
|
||||
// FinalizeEpisode 完成集数制作(触发视频合成)
|
||||
func (h *DramaHandler) FinalizeEpisode(c *gin.Context) {
|
||||
|
||||
episodeID := c.Param("episode_id")
|
||||
if episodeID == "" {
|
||||
response.BadRequest(c, "episode_id不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 尝试读取时间线数据(可选)
|
||||
var timelineData *services.FinalizeEpisodeRequest
|
||||
if err := c.ShouldBindJSON(&timelineData); err != nil {
|
||||
// 如果没有请求体或解析失败,使用nil(将使用默认场景顺序)
|
||||
h.log.Warnw("No timeline data provided, will use default scene order", "error", err)
|
||||
timelineData = nil
|
||||
} else if timelineData != nil {
|
||||
h.log.Infow("Received timeline data", "clips_count", len(timelineData.Clips), "episode_id", episodeID)
|
||||
}
|
||||
|
||||
// 触发视频合成任务
|
||||
result, err := h.videoMergeService.FinalizeEpisode(episodeID, timelineData)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to finalize episode", "error", err, "episode_id", episodeID)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, result)
|
||||
}
|
||||
|
||||
// DownloadEpisodeVideo 下载剧集视频
|
||||
func (h *DramaHandler) DownloadEpisodeVideo(c *gin.Context) {
|
||||
|
||||
episodeID := c.Param("episode_id")
|
||||
if episodeID == "" {
|
||||
response.BadRequest(c, "episode_id不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 查询episode
|
||||
var episode models.Episode
|
||||
if err := h.db.Preload("Drama").Where("id = ?", episodeID).First(&episode).Error; err != nil {
|
||||
response.NotFound(c, "剧集不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否有视频
|
||||
if episode.VideoURL == nil || *episode.VideoURL == "" {
|
||||
response.BadRequest(c, "该剧集还没有生成视频")
|
||||
return
|
||||
}
|
||||
|
||||
// 返回视频URL,让前端重定向下载
|
||||
c.JSON(200, gin.H{
|
||||
"video_url": *episode.VideoURL,
|
||||
"title": episode.Title,
|
||||
"episode_number": episode.EpisodeNum,
|
||||
})
|
||||
}
|
||||
55
api/handlers/frame_prompt.go
Normal file
55
api/handlers/frame_prompt.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// FramePromptHandler 处理帧提示词生成请求
|
||||
type FramePromptHandler struct {
|
||||
framePromptService *services.FramePromptService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
// NewFramePromptHandler 创建帧提示词处理器
|
||||
func NewFramePromptHandler(framePromptService *services.FramePromptService, log *logger.Logger) *FramePromptHandler {
|
||||
return &FramePromptHandler{
|
||||
framePromptService: framePromptService,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateFramePrompt 生成指定类型的帧提示词
|
||||
// POST /api/v1/storyboards/:id/frame-prompt
|
||||
func (h *FramePromptHandler) GenerateFramePrompt(c *gin.Context) {
|
||||
storyboardID := c.Param("id")
|
||||
|
||||
var req struct {
|
||||
FrameType string `json:"frame_type" binding:"required"` // first, key, last, panel, action
|
||||
PanelCount int `json:"panel_count"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
// 构建请求
|
||||
serviceReq := services.GenerateFramePromptRequest{
|
||||
StoryboardID: storyboardID,
|
||||
FrameType: services.FrameType(req.FrameType),
|
||||
PanelCount: req.PanelCount,
|
||||
}
|
||||
|
||||
// 生成提示词
|
||||
result, err := h.framePromptService.GenerateFramePrompt(serviceReq)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to generate frame prompt", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, result)
|
||||
}
|
||||
30
api/handlers/frame_prompt_query.go
Normal file
30
api/handlers/frame_prompt_query.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/drama-generator/backend/domain/models"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// GetStoryboardFramePrompts 查询镜头的所有帧提示词
|
||||
// GET /api/v1/storyboards/:id/frame-prompts
|
||||
func GetStoryboardFramePrompts(db *gorm.DB, log *logger.Logger) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
storyboardID := c.Param("id")
|
||||
|
||||
var framePrompts []models.FramePrompt
|
||||
if err := db.Where("storyboard_id = ?", storyboardID).
|
||||
Order("created_at DESC").
|
||||
Find(&framePrompts).Error; err != nil {
|
||||
log.Errorw("Failed to query frame prompts", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"frame_prompts": framePrompts,
|
||||
})
|
||||
}
|
||||
}
|
||||
182
api/handlers/image_generation.go
Normal file
182
api/handlers/image_generation.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/pkg/config"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ImageGenerationHandler struct {
|
||||
imageService *services.ImageGenerationService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewImageGenerationHandler(db *gorm.DB, cfg *config.Config, log *logger.Logger, transferService *services.ResourceTransferService) *ImageGenerationHandler {
|
||||
return &ImageGenerationHandler{
|
||||
imageService: services.NewImageGenerationService(db, transferService, log),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ImageGenerationHandler) GenerateImage(c *gin.Context) {
|
||||
|
||||
var req services.GenerateImageRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
imageGen, err := h.imageService.GenerateImage(&req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to generate image", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, imageGen)
|
||||
}
|
||||
|
||||
func (h *ImageGenerationHandler) GenerateImagesForScene(c *gin.Context) {
|
||||
|
||||
sceneID := c.Param("scene_id")
|
||||
|
||||
images, err := h.imageService.GenerateImagesForScene(sceneID)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to generate images for scene", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, images)
|
||||
}
|
||||
|
||||
func (h *ImageGenerationHandler) GetBackgroundsForEpisode(c *gin.Context) {
|
||||
|
||||
episodeID := c.Param("episode_id")
|
||||
|
||||
backgrounds, err := h.imageService.GetScencesForEpisode(episodeID)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to get backgrounds", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, backgrounds)
|
||||
}
|
||||
|
||||
func (h *ImageGenerationHandler) ExtractBackgroundsForEpisode(c *gin.Context) {
|
||||
|
||||
episodeID := c.Param("episode_id")
|
||||
|
||||
// 同步执行场景提取
|
||||
backgrounds, err := h.imageService.ExtractBackgroundsForEpisode(episodeID)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to extract backgrounds", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, backgrounds)
|
||||
}
|
||||
|
||||
func (h *ImageGenerationHandler) BatchGenerateForEpisode(c *gin.Context) {
|
||||
|
||||
episodeID := c.Param("episode_id")
|
||||
|
||||
images, err := h.imageService.BatchGenerateImagesForEpisode(episodeID)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to batch generate images", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, images)
|
||||
}
|
||||
|
||||
func (h *ImageGenerationHandler) GetImageGeneration(c *gin.Context) {
|
||||
|
||||
imageGenID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
imageGen, err := h.imageService.GetImageGeneration(uint(imageGenID))
|
||||
if err != nil {
|
||||
response.NotFound(c, "图片生成记录不存在")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, imageGen)
|
||||
}
|
||||
|
||||
func (h *ImageGenerationHandler) ListImageGenerations(c *gin.Context) {
|
||||
var sceneID *uint
|
||||
if sceneIDStr := c.Query("scene_id"); sceneIDStr != "" {
|
||||
id, err := strconv.ParseUint(sceneIDStr, 10, 32)
|
||||
if err == nil {
|
||||
uid := uint(id)
|
||||
sceneID = &uid
|
||||
}
|
||||
}
|
||||
|
||||
var storyboardID *uint
|
||||
if storyboardIDStr := c.Query("storyboard_id"); storyboardIDStr != "" {
|
||||
id, err := strconv.ParseUint(storyboardIDStr, 10, 32)
|
||||
if err == nil {
|
||||
uid := uint(id)
|
||||
storyboardID = &uid
|
||||
}
|
||||
}
|
||||
|
||||
frameType := c.Query("frame_type")
|
||||
status := c.Query("status")
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
var dramaIDUint *uint
|
||||
if dramaIDStr := c.Query("drama_id"); dramaIDStr != "" {
|
||||
did, _ := strconv.ParseUint(dramaIDStr, 10, 32)
|
||||
didUint := uint(did)
|
||||
dramaIDUint = &didUint
|
||||
}
|
||||
|
||||
images, total, err := h.imageService.ListImageGenerations(dramaIDUint, sceneID, storyboardID, frameType, status, page, pageSize)
|
||||
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to list images", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.SuccessWithPagination(c, images, total, page, pageSize)
|
||||
}
|
||||
|
||||
func (h *ImageGenerationHandler) DeleteImageGeneration(c *gin.Context) {
|
||||
|
||||
imageGenID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.imageService.DeleteImageGeneration(uint(imageGenID)); err != nil {
|
||||
h.log.Errorw("Failed to delete image", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, nil)
|
||||
}
|
||||
75
api/handlers/scene.go
Normal file
75
api/handlers/scene.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
services2 "github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type SceneHandler struct {
|
||||
sceneService *services2.StoryboardCompositionService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewSceneHandler(db *gorm.DB, log *logger.Logger, imageGenService *services2.ImageGenerationService) *SceneHandler {
|
||||
return &SceneHandler{
|
||||
sceneService: services2.NewStoryboardCompositionService(db, log, imageGenService),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *SceneHandler) GetStoryboardsForEpisode(c *gin.Context) {
|
||||
episodeID := c.Param("episode_id")
|
||||
|
||||
storyboards, err := h.sceneService.GetScenesForEpisode(episodeID)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to get storyboards for episode", "error", err, "episode_id", episodeID)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"storyboards": storyboards,
|
||||
"total": len(storyboards),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *SceneHandler) UpdateScene(c *gin.Context) {
|
||||
sceneID := c.Param("scene_id")
|
||||
|
||||
var req services2.UpdateSceneRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.sceneService.UpdateScene(sceneID, &req); err != nil {
|
||||
h.log.Errorw("Failed to update scene", "error", err, "scene_id", sceneID)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "Scene updated successfully"})
|
||||
}
|
||||
|
||||
func (h *SceneHandler) GenerateSceneImage(c *gin.Context) {
|
||||
var req services2.GenerateSceneImageRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request")
|
||||
return
|
||||
}
|
||||
|
||||
imageGen, err := h.sceneService.GenerateSceneImage(&req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to generate scene image", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"message": "Scene image generation started",
|
||||
"image_generation": imageGen,
|
||||
})
|
||||
}
|
||||
76
api/handlers/script_generation.go
Normal file
76
api/handlers/script_generation.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/pkg/config"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ScriptGenerationHandler struct {
|
||||
scriptService *services.ScriptGenerationService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewScriptGenerationHandler(db *gorm.DB, cfg *config.Config, log *logger.Logger) *ScriptGenerationHandler {
|
||||
return &ScriptGenerationHandler{
|
||||
scriptService: services.NewScriptGenerationService(db, log),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ScriptGenerationHandler) GenerateOutline(c *gin.Context) {
|
||||
|
||||
var req services.GenerateOutlineRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.scriptService.GenerateOutline(&req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to generate outline", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, result)
|
||||
}
|
||||
|
||||
func (h *ScriptGenerationHandler) GenerateCharacters(c *gin.Context) {
|
||||
var req services.GenerateCharactersRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 同步执行角色生成
|
||||
characters, err := h.scriptService.GenerateCharacters(&req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to generate characters", "error", err)
|
||||
response.InternalError(c, "生成角色失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, characters)
|
||||
}
|
||||
|
||||
func (h *ScriptGenerationHandler) GenerateEpisodes(c *gin.Context) {
|
||||
|
||||
var req services.GenerateEpisodesRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
episodes, err := h.scriptService.GenerateEpisodes(&req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to generate episodes", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, episodes)
|
||||
}
|
||||
96
api/handlers/storyboard.go
Normal file
96
api/handlers/storyboard.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/pkg/config"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type StoryboardHandler struct {
|
||||
storyboardService *services.StoryboardService
|
||||
taskService *services.TaskService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewStoryboardHandler(db *gorm.DB, cfg *config.Config, log *logger.Logger) *StoryboardHandler {
|
||||
return &StoryboardHandler{
|
||||
storyboardService: services.NewStoryboardService(db, log),
|
||||
taskService: services.NewTaskService(db, log),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateStoryboard 生成分镜头(异步)
|
||||
func (h *StoryboardHandler) GenerateStoryboard(c *gin.Context) {
|
||||
episodeID := c.Param("episode_id")
|
||||
|
||||
// 创建异步任务
|
||||
task, err := h.taskService.CreateTask("storyboard_generation", episodeID)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to create task", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 启动后台goroutine处理
|
||||
go h.processStoryboardGeneration(task.ID, episodeID)
|
||||
|
||||
// 立即返回任务ID
|
||||
response.Success(c, gin.H{
|
||||
"task_id": task.ID,
|
||||
"status": "pending",
|
||||
"message": "分镜生成任务已创建,正在后台处理...",
|
||||
})
|
||||
}
|
||||
|
||||
// processStoryboardGeneration 后台处理分镜生成
|
||||
func (h *StoryboardHandler) processStoryboardGeneration(taskID, episodeID string) {
|
||||
h.log.Infow("Starting storyboard generation", "task_id", taskID, "episode_id", episodeID)
|
||||
|
||||
// 更新任务状态为处理中
|
||||
if err := h.taskService.UpdateTaskStatus(taskID, "processing", 10, "开始生成分镜..."); err != nil {
|
||||
h.log.Errorw("Failed to update task status", "error", err)
|
||||
}
|
||||
|
||||
// 调用实际的生成逻辑
|
||||
result, err := h.storyboardService.GenerateStoryboard(episodeID)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to generate storyboard", "error", err, "task_id", taskID)
|
||||
if updateErr := h.taskService.UpdateTaskError(taskID, err); updateErr != nil {
|
||||
h.log.Errorw("Failed to update task error", "error", updateErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 更新任务结果
|
||||
if err := h.taskService.UpdateTaskResult(taskID, result); err != nil {
|
||||
h.log.Errorw("Failed to update task result", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
h.log.Infow("Storyboard generation completed", "task_id", taskID, "total", result.Total)
|
||||
}
|
||||
|
||||
// UpdateStoryboard 更新分镜
|
||||
func (h *StoryboardHandler) UpdateStoryboard(c *gin.Context) {
|
||||
storyboardID := c.Param("id")
|
||||
|
||||
var req map[string]interface{}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
err := h.storyboardService.UpdateStoryboard(storyboardID, req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to update storyboard", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "Storyboard updated successfully"})
|
||||
}
|
||||
57
api/handlers/task.go
Normal file
57
api/handlers/task.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type TaskHandler struct {
|
||||
taskService *services.TaskService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewTaskHandler(db *gorm.DB, log *logger.Logger) *TaskHandler {
|
||||
return &TaskHandler{
|
||||
taskService: services.NewTaskService(db, log),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// GetTaskStatus 获取任务状态
|
||||
func (h *TaskHandler) GetTaskStatus(c *gin.Context) {
|
||||
taskID := c.Param("task_id")
|
||||
|
||||
task, err := h.taskService.GetTask(taskID)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
response.NotFound(c, "任务不存在")
|
||||
return
|
||||
}
|
||||
h.log.Errorw("Failed to get task", "error", err, "task_id", taskID)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, task)
|
||||
}
|
||||
|
||||
// GetResourceTasks 获取资源相关的所有任务
|
||||
func (h *TaskHandler) GetResourceTasks(c *gin.Context) {
|
||||
resourceID := c.Query("resource_id")
|
||||
if resourceID == "" {
|
||||
response.BadRequest(c, "缺少resource_id参数")
|
||||
return
|
||||
}
|
||||
|
||||
tasks, err := h.taskService.GetTasksByResource(resourceID)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to get resource tasks", "error", err, "resource_id", resourceID)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, tasks)
|
||||
}
|
||||
142
api/handlers/upload.go
Normal file
142
api/handlers/upload.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
services2 "github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/pkg/config"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type UploadHandler struct {
|
||||
uploadService *services2.UploadService
|
||||
characterLibraryService *services2.CharacterLibraryService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewUploadHandler(cfg *config.Config, log *logger.Logger, characterLibraryService *services2.CharacterLibraryService) (*UploadHandler, error) {
|
||||
uploadService, err := services2.NewUploadService(cfg, log)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &UploadHandler{
|
||||
uploadService: uploadService,
|
||||
characterLibraryService: characterLibraryService,
|
||||
log: log,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UploadImage 上传图片
|
||||
func (h *UploadHandler) UploadImage(c *gin.Context) {
|
||||
// 获取上传的文件
|
||||
file, header, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
response.BadRequest(c, "请选择文件")
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// 检查文件类型
|
||||
contentType := header.Header.Get("Content-Type")
|
||||
if contentType == "" {
|
||||
contentType = "application/octet-stream"
|
||||
}
|
||||
|
||||
// 验证是图片类型
|
||||
allowedTypes := map[string]bool{
|
||||
"image/jpeg": true,
|
||||
"image/jpg": true,
|
||||
"image/png": true,
|
||||
"image/gif": true,
|
||||
"image/webp": true,
|
||||
}
|
||||
|
||||
if !allowedTypes[contentType] {
|
||||
response.BadRequest(c, "只支持图片格式 (jpg, png, gif, webp)")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查文件大小 (10MB)
|
||||
if header.Size > 10*1024*1024 {
|
||||
response.BadRequest(c, "文件大小不能超过10MB")
|
||||
return
|
||||
}
|
||||
|
||||
// 上传到MinIO
|
||||
fileURL, err := h.uploadService.UploadCharacterImage(file, header.Filename, contentType)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to upload image", "error", err)
|
||||
response.InternalError(c, "上传失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"url": fileURL,
|
||||
"filename": header.Filename,
|
||||
"size": header.Size,
|
||||
})
|
||||
}
|
||||
|
||||
// UploadCharacterImage 上传角色图片(带角色ID)
|
||||
func (h *UploadHandler) UploadCharacterImage(c *gin.Context) {
|
||||
characterID := c.Param("id")
|
||||
|
||||
// 获取上传的文件
|
||||
file, header, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
response.BadRequest(c, "请选择文件")
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// 检查文件类型
|
||||
contentType := header.Header.Get("Content-Type")
|
||||
if contentType == "" {
|
||||
contentType = "application/octet-stream"
|
||||
}
|
||||
|
||||
// 验证是图片类型
|
||||
allowedTypes := map[string]bool{
|
||||
"image/jpeg": true,
|
||||
"image/jpg": true,
|
||||
"image/png": true,
|
||||
"image/gif": true,
|
||||
"image/webp": true,
|
||||
}
|
||||
|
||||
if !allowedTypes[contentType] {
|
||||
response.BadRequest(c, "只支持图片格式 (jpg, png, gif, webp)")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查文件大小 (10MB)
|
||||
if header.Size > 10*1024*1024 {
|
||||
response.BadRequest(c, "文件大小不能超过10MB")
|
||||
return
|
||||
}
|
||||
|
||||
// 上传到MinIO
|
||||
fileURL, err := h.uploadService.UploadCharacterImage(file, header.Filename, contentType)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to upload character image", "error", err)
|
||||
response.InternalError(c, "上传失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 更新角色的image_url字段到数据库
|
||||
err = h.characterLibraryService.UploadCharacterImage(characterID, fileURL)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to update character image_url", "error", err, "character_id", characterID)
|
||||
response.InternalError(c, "更新角色图片失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.log.Infow("Character image uploaded and saved", "character_id", characterID, "url", fileURL)
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"url": fileURL,
|
||||
"filename": header.Filename,
|
||||
"size": header.Size,
|
||||
})
|
||||
}
|
||||
149
api/handlers/video_generation.go
Normal file
149
api/handlers/video_generation.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/infrastructure/storage"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type VideoGenerationHandler struct {
|
||||
videoService *services.VideoGenerationService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewVideoGenerationHandler(db *gorm.DB, transferService *services.ResourceTransferService, localStorage *storage.LocalStorage, aiService *services.AIService, log *logger.Logger) *VideoGenerationHandler {
|
||||
return &VideoGenerationHandler{
|
||||
videoService: services.NewVideoGenerationService(db, transferService, localStorage, aiService, log),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *VideoGenerationHandler) GenerateVideo(c *gin.Context) {
|
||||
|
||||
var req services.GenerateVideoRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
videoGen, err := h.videoService.GenerateVideo(&req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to generate video", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, videoGen)
|
||||
}
|
||||
|
||||
func (h *VideoGenerationHandler) GenerateVideoFromImage(c *gin.Context) {
|
||||
|
||||
imageGenID, err := strconv.ParseUint(c.Param("image_gen_id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的图片ID")
|
||||
return
|
||||
}
|
||||
|
||||
videoGen, err := h.videoService.GenerateVideoFromImage(uint(imageGenID))
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to generate video from image", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, videoGen)
|
||||
}
|
||||
|
||||
func (h *VideoGenerationHandler) BatchGenerateForEpisode(c *gin.Context) {
|
||||
|
||||
episodeID := c.Param("episode_id")
|
||||
|
||||
videos, err := h.videoService.BatchGenerateVideosForEpisode(episodeID)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to batch generate videos", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, videos)
|
||||
}
|
||||
|
||||
func (h *VideoGenerationHandler) GetVideoGeneration(c *gin.Context) {
|
||||
|
||||
videoGenID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
videoGen, err := h.videoService.GetVideoGeneration(uint(videoGenID))
|
||||
if err != nil {
|
||||
response.NotFound(c, "视频生成记录不存在")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, videoGen)
|
||||
}
|
||||
|
||||
func (h *VideoGenerationHandler) ListVideoGenerations(c *gin.Context) {
|
||||
var storyboardID *uint
|
||||
// 优先使用storyboard_id参数
|
||||
if storyboardIDStr := c.Query("storyboard_id"); storyboardIDStr != "" {
|
||||
id, err := strconv.ParseUint(storyboardIDStr, 10, 32)
|
||||
if err == nil {
|
||||
uid := uint(id)
|
||||
storyboardID = &uid
|
||||
}
|
||||
}
|
||||
status := c.Query("status")
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
var dramaIDUint *uint
|
||||
if dramaIDStr := c.Query("drama_id"); dramaIDStr != "" {
|
||||
did, _ := strconv.ParseUint(dramaIDStr, 10, 32)
|
||||
didUint := uint(did)
|
||||
dramaIDUint = &didUint
|
||||
}
|
||||
|
||||
// 计算offset:(page - 1) * pageSize
|
||||
offset := (page - 1) * pageSize
|
||||
videos, total, err := h.videoService.ListVideoGenerations(dramaIDUint, storyboardID, status, pageSize, offset)
|
||||
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to list videos", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.SuccessWithPagination(c, videos, total, page, pageSize)
|
||||
}
|
||||
|
||||
func (h *VideoGenerationHandler) DeleteVideoGeneration(c *gin.Context) {
|
||||
|
||||
videoGenID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.videoService.DeleteVideoGeneration(uint(videoGenID)); err != nil {
|
||||
h.log.Errorw("Failed to delete video", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, nil)
|
||||
}
|
||||
104
api/handlers/video_merge.go
Normal file
104
api/handlers/video_merge.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
services2 "github.com/drama-generator/backend/application/services"
|
||||
"github.com/drama-generator/backend/pkg/logger"
|
||||
"github.com/drama-generator/backend/pkg/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type VideoMergeHandler struct {
|
||||
mergeService *services2.VideoMergeService
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewVideoMergeHandler(db *gorm.DB, transferService *services2.ResourceTransferService, storagePath, baseURL string, log *logger.Logger) *VideoMergeHandler {
|
||||
return &VideoMergeHandler{
|
||||
mergeService: services2.NewVideoMergeService(db, transferService, storagePath, baseURL, log),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *VideoMergeHandler) MergeVideos(c *gin.Context) {
|
||||
var req services2.MergeVideoRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request")
|
||||
return
|
||||
}
|
||||
|
||||
merge, err := h.mergeService.MergeVideos(&req)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to merge videos", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"message": "Video merge task created",
|
||||
"merge": merge,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *VideoMergeHandler) GetMerge(c *gin.Context) {
|
||||
mergeIDStr := c.Param("merge_id")
|
||||
mergeID, err := strconv.ParseUint(mergeIDStr, 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid merge ID")
|
||||
return
|
||||
}
|
||||
|
||||
merge, err := h.mergeService.GetMerge(uint(mergeID))
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to get merge", "error", err)
|
||||
response.NotFound(c, "Merge not found")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"merge": merge})
|
||||
}
|
||||
|
||||
func (h *VideoMergeHandler) ListMerges(c *gin.Context) {
|
||||
episodeID := c.Query("episode_id")
|
||||
status := c.Query("status")
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
|
||||
var episodeIDPtr *string
|
||||
if episodeID != "" {
|
||||
episodeIDPtr = &episodeID
|
||||
}
|
||||
|
||||
merges, total, err := h.mergeService.ListMerges(episodeIDPtr, status, page, pageSize)
|
||||
if err != nil {
|
||||
h.log.Errorw("Failed to list merges", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"merges": merges,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": pageSize,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *VideoMergeHandler) DeleteMerge(c *gin.Context) {
|
||||
mergeIDStr := c.Param("merge_id")
|
||||
mergeID, err := strconv.ParseUint(mergeIDStr, 10, 32)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid merge ID")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.mergeService.DeleteMerge(uint(mergeID)); err != nil {
|
||||
h.log.Errorw("Failed to delete merge", "error", err)
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{"message": "Merge deleted successfully"})
|
||||
}
|
||||
Reference in New Issue
Block a user