package handler import ( "errors" "io" "net/http" "strings" "juhe-factory/api/internal/service" "github.com/gin-gonic/gin" "github.com/google/uuid" ) func (h *Creative) PreviewDramaImport(c *gin.Context) { projectID, ok := h.projectID(c) if !ok { return } c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 4<<20) if err := c.Request.ParseMultipartForm(4 << 20); err != nil { h.bad(c, errors.New("导入内容无效")) return } if c.Request.MultipartForm != nil { defer c.Request.MultipartForm.RemoveAll() } rawText := strings.TrimSpace(c.PostForm("raw_text")) var filename string var content []byte file, header, err := c.Request.FormFile("file") if err == nil { defer file.Close() filename = header.Filename content, err = io.ReadAll(io.LimitReader(file, 3*1024*1024+1)) if err != nil { h.bad(c, errors.New("读取小说文件失败")) return } } else if rawText == "" { h.bad(c, errors.New("请选择小说文件或粘贴文本")) return } preview, err := h.service.PreviewDramaImport(currentWebUser(c).ID, projectID, filename, content, rawText) if err != nil { h.respondError(c, err) return } c.JSON(http.StatusOK, gin.H{"data": preview}) } func (h *Creative) ConfirmDramaImport(c *gin.Context) { projectID, ok := h.projectID(c) if !ok { return } var body struct { ImportToken uuid.UUID `json:"import_token"` ChaptersPerEpisode int `json:"chapters_per_episode"` StartEpisodeNo int `json:"start_episode_no"` TreatAsSingleEpisode bool `json:"treat_as_single_episode"` } if err := c.ShouldBindJSON(&body); err != nil || body.ImportToken == uuid.Nil { h.bad(c, errors.New("导入确认参数无效")) return } items, err := h.service.ConfirmDramaImport(currentWebUser(c).ID, projectID, body.ImportToken, body.ChaptersPerEpisode, body.StartEpisodeNo, body.TreatAsSingleEpisode) if err != nil { h.respondError(c, err) return } c.JSON(http.StatusCreated, gin.H{"data": items}) } func (h *Creative) GetDramaEpisodeSource(c *gin.Context) { projectID, episodeID, ok := h.dramaEpisodeIDs(c) if !ok { return } source, err := h.service.EpisodeSource(currentWebUser(c).ID, projectID, episodeID) if err != nil { h.respondError(c, err) return } c.JSON(http.StatusOK, gin.H{"data": source}) } func (h *Creative) SaveDramaEpisodeSource(c *gin.Context) { projectID, episodeID, ok := h.dramaEpisodeIDs(c) if !ok { return } var body struct { Title string `json:"title"` RawContent string `json:"raw_content"` } if err := c.ShouldBindJSON(&body); err != nil { h.bad(c, err) return } source, err := h.service.SaveEpisodeSource(currentWebUser(c).ID, projectID, episodeID, body.RawContent, body.Title) if err != nil { h.respondError(c, err) return } c.JSON(http.StatusOK, gin.H{"data": source}) } func (h *Creative) QueueDramaParse(c *gin.Context) { projectID, episodeID, ok := h.dramaEpisodeIDs(c) if !ok { return } task, err := h.service.QueueDramaParse(currentWebUser(c).ID, projectID, episodeID) if err != nil { h.respondError(c, err) return } c.JSON(http.StatusAccepted, gin.H{"data": task}) } func (h *Creative) ReparseDrama(c *gin.Context) { if !h.objectStorageAvailable(c) { return } projectID, episodeID, ok := h.dramaEpisodeIDs(c) if !ok { return } userID := currentWebUser(c).ID objectKeys, err := h.service.ResetEpisodeAnalysis(userID, projectID, episodeID) if err != nil { h.respondError(c, err) return } if !h.deleteStoredObjects(c, objectKeys) { return } task, err := h.service.QueueDramaParse(userID, projectID, episodeID) if err != nil { h.respondError(c, err) return } c.JSON(http.StatusAccepted, gin.H{"data": task}) } func (h *Creative) ListDramaParseTasks(c *gin.Context) { projectID, ok := h.projectID(c) if !ok { return } var episodeID *uuid.UUID if raw := strings.TrimSpace(c.Query("episode_id")); raw != "" { parsed, err := service.ParseUUID(raw, "剧集") if err != nil { h.bad(c, err) return } episodeID = &parsed } items, err := h.service.ListDramaParseTasks(currentWebUser(c).ID, projectID, episodeID) if err != nil { h.respondError(c, err) return } c.JSON(http.StatusOK, gin.H{"data": items}) } func (h *Creative) CancelDramaParse(c *gin.Context) { projectID, ok := h.projectID(c) if !ok { return } taskID, err := service.ParseUUID(c.Param("task_id"), "解析任务") if err != nil { h.bad(c, err) return } if err = h.service.CancelDramaParse(currentWebUser(c).ID, projectID, taskID); err != nil { h.respondError(c, err) return } c.Status(http.StatusNoContent) } func (h *Creative) CreateDramaStoryboard(c *gin.Context) { projectID, episodeID, ok := h.dramaEpisodeIDs(c) if !ok { return } storyboard, err := h.service.CreateStoryboard(currentWebUser(c).ID, projectID, episodeID) if err != nil { h.respondError(c, err) return } c.JSON(http.StatusCreated, gin.H{"data": storyboard}) } func (h *Creative) dramaEpisodeIDs(c *gin.Context) (uuid.UUID, uuid.UUID, bool) { projectID, ok := h.projectID(c) if !ok { return uuid.Nil, uuid.Nil, false } episodeID, err := service.ParseUUID(c.Param("episode_id"), "剧集") if err != nil { h.bad(c, err) return uuid.Nil, uuid.Nil, false } return projectID, episodeID, true }