Kaynağa Gözat

新增保存剧集分段剧本接口

lh 3 hafta önce
ebeveyn
işleme
b57acc109c

+ 15 - 0
app/Http/Controllers/DeepSeek/DeepSeekController.php

@@ -1222,6 +1222,21 @@ class DeepSeekController extends BaseController
     }
 
     /**
+     * 保存剧集片段(预览确认模式使用):删除旧数据并保存新数据
+     * @param Request $request
+     * @return mixed
+     */
+    public function saveEpisodeActs(Request $request) {
+        // 忽略所有超时限制
+        set_time_limit(0);
+        ini_set('max_execution_time', '0');
+
+        $data = $request->all();
+        $result = $this->deepseekService->saveEpisodeActs($data);
+        return $this->success($result);
+    }
+
+    /**
      * 批量生成多个分集
      * @param Request $request
      * @return mixed

+ 139 - 1
app/Services/DeepSeek/DeepSeekService.php

@@ -12365,7 +12365,8 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
 
             $episode_content = DB::table('mp_anime_episodes')->where('id', $episode_id)->value('content');
             if ($episode_content) {
-                $reference_content = "\n\n【本集原始内容】\n{$episode_content}\n\n【本集生成剧本内容】\n{$reference_content}";
+                // $reference_content = "\n\n【本集原始内容】\n{$episode_content}\n\n【本集生成剧本内容】\n{$reference_content}";
+                $reference_content = "\n\n【本集原始内容】\n{$episode_content}";
             }else {
                 $reference_content = "\n\n【原分段剧本内容】\n{$reference_content}";
             }
@@ -12871,6 +12872,34 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
                 }
                 
             } else {
+                // 预览确认模式(check_mode=1):不落库,返回展示参数供前端确认后调用 saveEpisodeActs 保存
+                if ($check_mode === 1) {
+                    // 预览生成即扣除积分并记录 token 明细(与 check_mode=0 保存时扣费一致)
+                    $this->chargeChatSuccess($uid, $this->pointsService->getTokensFromUsage($usage), [
+                        'anime_id'   => $target_anime_id,
+                        'episode_id' => $target_episode_id,
+                        'model'      => $model,
+                        'source'     => 'regenerateSegmentScript',
+                    ]);
+
+                    return [
+                        'check_mode'      => 1,
+                        'anime_id'        => $target_anime_id,
+                        'episode_id'      => $target_episode_id,
+                        'title'           => getProp($episode, 'title', ''),
+                        'episode_number'  => $target_episode_number,
+                        'is_generated'    => getProp($episode, 'is_generated', 0),
+                        'acts'            => array_map(function ($seg) {
+                            return [
+                                'act_number'             => $seg['act_number'],
+                                'act_duration'           => $seg['act_duration'],
+                                'act_content'            => $seg['act_content'],
+                                'act_show_content'       => $seg['act_show_content'],
+                            ];
+                        }, $parsed_segments),
+                    ];
+                }
+
                 // 整个剧集模式:删除原有记录并批量保存新记录
                 DB::beginTransaction();
                 
@@ -12962,6 +12991,115 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
     }
 
     /**
+     * 保存剧集片段(预览确认模式使用):删除旧数据并批量保存新数据到 mp_episode_segments
+     *
+     * 逻辑与 regenerateSegmentScript 的 episode_id + check_mode=0 保存保持一致。
+     *
+     * @param array $data 请求参数:episode_id 必填,acts 必填(预览返回的片段数组)
+     * @return array
+     */
+    public function saveEpisodeActs($data) {
+        $uid = Site::getUid();
+        $episode_id = (int)getProp($data, 'episode_id', 0);
+        $acts = getProp($data, 'acts', []);
+
+        if (!$episode_id) {
+            Utils::throwError('20003:请提供剧集ID');
+        }
+        if (!is_array($acts) || empty($acts)) {
+            Utils::throwError('20003:请提供片段数据');
+        }
+
+        $episode = DB::table('mp_anime_episodes')->where('id', $episode_id)->first();
+        if (!$episode) {
+            Utils::throwError('20003:剧集不存在');
+        }
+
+        // 用户校验:只能调整自己的剧集
+        $anime = DB::table('mp_animes')->where('id', $episode->anime_id)->first();
+        if (!$anime || (int)$anime->user_id !== (int)$uid) {
+            Utils::throwError('20003:没有权限操作该剧集');
+        }
+
+        $anime_id = (int)$episode->anime_id;
+        $episode_number = (int)$episode->episode_number;
+        $now = date('Y-m-d H:i:s');
+
+        try {
+            DB::beginTransaction();
+
+            // 删除原有的所有片段记录
+            DB::table('mp_episode_segments')
+                ->where('episode_id', $episode_id)
+                ->delete();
+
+            // 批量插入新的片段记录
+            $segments_to_insert = [];
+            $index = 0;
+            foreach ($acts as $act) {
+                if (!is_array($act)) {
+                    continue;
+                }
+                $index++;
+                $segments_to_insert[] = [
+                    'anime_id'         => $anime_id,
+                    'episode_id'       => $episode_id,
+                    'episode_number'   => $episode_number,
+                    'act_number'       => (int)getProp($act, 'act_number', $index),
+                    'act_title'        => (string)getProp($act, 'act_title', ''),
+                    'act_duration'     => (float)getProp($act, 'act_duration', 0),
+                    'act_content'      => (string)getProp($act, 'act_content', ''),
+                    // 'act_show_content' => (string)getProp($act, 'act_show_content', ''),
+                    'created_at'       => $now,
+                    'updated_at'       => $now,
+                ];
+            }
+
+            if (empty($segments_to_insert)) {
+                DB::rollBack();
+                Utils::throwError('20003:没有有效的片段数据');
+            }
+
+            DB::table('mp_episode_segments')->insert($segments_to_insert);
+
+            DB::commit();
+        } catch (\Exception $e) {
+            DB::rollBack();
+            dLog('deepseek')->error('保存剧集片段失败: ' . $e->getMessage(), [
+                'episode_id' => $episode_id,
+            ]);
+            Utils::throwError('20003:保存失败,请重试');
+        }
+
+        // 查询保存后的所有片段记录
+        $saved_segments = DB::table('mp_episode_segments')
+            ->where('episode_id', $episode_id)
+            ->orderBy('act_number')
+            ->get();
+
+        $saved_acts = [];
+        foreach ($saved_segments as $saved_segment) {
+            $saved_acts[] = [
+                'act_id'                => $saved_segment->id,
+                'act_number'            => $saved_segment->act_number,
+                'act_duration'          => $saved_segment->video_duration ? $saved_segment->video_duration : $saved_segment->act_duration,
+                'act_content'           => $saved_segment->act_content,
+                'act_show_content'      => $saved_segment->act_show_content,
+                'video_url'             => $saved_segment->video_url ?? '',
+                'video_duration'        => $saved_segment->video_duration ?? 0,
+                'video_time_point_start'=> $saved_segment->video_time_point_start ?? 0,
+                'video_time_point_end'  => $saved_segment->video_time_point_end ?? 0,
+            ];
+        }
+
+        return [
+            'anime_id'   => $anime_id,
+            'episode_id' => $episode_id,
+            'acts'       => $saved_acts,
+        ];
+    }
+
+    /**
      * 清理分镜内容:去除时长、旁白音色等非分镜行,只保留完整分镜内容(分镜标记统一为【分镜N】/【镜头N】)
      *
      * @param string $actContent

+ 1 - 0
routes/api.php

@@ -250,6 +250,7 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
             Route::post('reGenerateAnimeForAce', [DeepSeekController::class, 'reGenerateAnimeForAce']); // 调整动漫大纲
             Route::post('chatForAce', [DeepSeekController::class, 'chatForAce']);                       // 动漫对话(全能模式)
             Route::post('regenerateSegmentScript', [DeepSeekController::class, 'regenerateSegmentScript']); // 重新生成分段剧本
+            Route::post('saveEpisodeActs', [DeepSeekController::class, 'saveEpisodeActs']);         // 保存剧集片段
             Route::post('batchGenerateEpisodes', [DeepSeekController::class, 'batchGenerateEpisodes']); // 批量生成多个分集
             Route::get('getBatchGenerationTaskStatus', [DeepSeekController::class, 'getBatchGenerationTaskStatus']); // 获取批量生成任务状态
             Route::get('episodeInfoForAce', [AnimeController::class, 'episodeInfoForAce']);             // 动漫剧集(全能模式)