瀏覽代碼

新增片段处理相关接口

lh 1 月之前
父節點
當前提交
900c070eb7
共有 3 個文件被更改,包括 486 次插入0 次删除
  1. 53 0
      app/Http/Controllers/Anime/AnimeController.php
  2. 426 0
      app/Services/Anime/AnimeService.php
  3. 7 0
      routes/api.php

+ 53 - 0
app/Http/Controllers/Anime/AnimeController.php

@@ -377,6 +377,59 @@ class AnimeController extends BaseController
         return $this->success(['success'=>$result ? 1: 0]);
     }
 
+    // 添加片段
+    public function addAct(Request $request) {
+        // 忽略所有超时限制
+        set_time_limit(0);
+        ini_set('max_execution_time', '0');
+
+        $data = $request->all();
+        $result = $this->AnimeService->addAct($data);
+        return $this->success($result);
+    }
+
+    // 编辑片段
+    public function editAct(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->editAct($data);
+        return $this->success(['success'=>$result ? 1 : 0]);
+    }
+
+    // 复制片段
+    public function copyAct(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->copyAct($data);
+        return $this->success($result);
+    }
+
+    // 移动片段
+    public function moveAct(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->moveAct($data);
+        return $this->success(['success'=>$result ? 1: 0]);
+    }
+
+    // 删除片段
+    public function delAct(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->delAct($data);
+        return $this->success(['success'=>$result ? 1: 0]);
+    }
+
+    // 应用片段
+    public function applyAct(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->applyAct($data);
+        return $this->success(['success'=>$result ? 1: 0]);
+    }
+
+    // 片段对话历史记录
+    public function actChatHistory(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->actChatHistory($data);
+        return $this->success($result);
+    }
+
     // 分镜历史图片|视频
     public function segmentHistory(Request $request) {
         $data = $request->all();

+ 426 - 0
app/Services/Anime/AnimeService.php

@@ -2318,6 +2318,432 @@ class AnimeService
         return compact('pics', 'videos');
     }
 
+    public function addAct($data) {
+        $prev_act_id = getProp($data, 'prev_act_id');
+        $act_title = getProp($data, 'act_title', '');
+        $act_content = getProp($data, 'act_content', '');
+        $act_duration = getProp($data, 'act_duration', 0);
+        $video_url = getProp($data, 'video_url');
+        
+        // 根据prev_act_id获取记录
+        $prev_segment = DB::table('mp_episode_segments')->where('id', $prev_act_id)->first();
+        if (!$prev_segment) Utils::throwError('20003:该片段不存在');
+        
+        $anime_id = getProp($prev_segment, 'anime_id');
+        $episode_id = getProp($prev_segment, 'episode_id');
+        $episode_number = getProp($prev_segment, 'episode_number');
+        $prev_act_number = getProp($prev_segment, 'act_number');
+        
+        // 获取新的act_number
+        $new_act_number = $prev_act_number + 1;
+
+        try {
+            DB::beginTransaction();
+            
+            // 更新后续所有act的act_number(全能模式下每个act只有一条记录)
+            DB::table('mp_episode_segments')
+                ->where('anime_id', $anime_id)
+                ->where('episode_id', $episode_id)
+                ->where('act_number', '>', $prev_act_number)
+                ->increment('act_number');
+
+            // 插入新片段记录
+            $insert_data = [
+                'anime_id'      => $anime_id,
+                'episode_id'    => $episode_id,
+                'episode_number' => $episode_number,
+                'act_number'    => $new_act_number,
+                'created_at'    => date('Y-m-d H:i:s'),
+                'updated_at'    => date('Y-m-d H:i:s')
+            ];
+            if ($act_title) {
+                $insert_data['act_title'] = $act_title;
+            }
+
+            if ($act_content) {
+                $insert_data['act_content'] = $act_content;
+            }
+
+            if ($act_duration) {
+                $insert_data['act_duration'] = $act_duration;
+            }
+
+            if ($video_url) {
+                $insert_data['origin_video_url'] = $video_url;
+                $insert_data['current_type'] = 2;
+                $compressed_video_url = compressVideo($video_url);
+                $insert_data['video_url'] = $compressed_video_url ?: $video_url;
+            }
+
+            $id = DB::table('mp_episode_segments')->insertGetId($insert_data);
+            if (!$id) {
+                Utils::throwError('20003:新增片段失败!');
+            }
+            
+            DB::commit();
+        }catch (\Exception $e) {
+            DB::rollBack();
+            Utils::throwError('20003:'.$e->getMessage());
+        }
+        
+        $segment = DB::table('mp_episode_segments')->selectRaw("id as act_id,anime_id,episode_id,episode_number,act_number,act_title,act_duration,act_content,video_url,video_duration,video_time_point_start,video_time_point_end")->where('id', $id)->first();
+        $segment = $segment ? (array)$segment : [];
+        return $segment;
+    }
+
+    public function editAct($data) {
+        $act_id = getProp($data, 'act_id');
+        $act_content = getProp($data, 'act_content');
+        $act_duration = getProp($data, 'act_duration');
+        $act_title = getProp($data, 'act_title');
+        $image_url = getProp($data, 'image_url');
+        $video_url = getProp($data, 'video_url');
+
+        // 参数验证
+        if (!$act_id) Utils::throwError('20003:请提供片段ID');
+
+        // 验证片段是否存在(全能模式下每个act只有一条记录)
+        $segment = DB::table('mp_episode_segments')
+            ->where('id', $act_id)
+            ->first();
+        
+        if (!$segment) Utils::throwError('20003:该片段不存在');
+
+        try {
+            DB::beginTransaction();
+            
+            // 准备更新数据
+            $update_data = [
+                'updated_at' => date('Y-m-d H:i:s')
+            ];
+
+            // 更新act相关字段
+            if (!empty($act_content)) {
+                $update_data['act_content'] = $act_content;
+            }
+            
+            if (!empty($act_duration)) {
+                $update_data['act_duration'] = $act_duration;
+            }
+            
+            if (!empty($act_title)) {
+                $update_data['act_title'] = $act_title;
+            }
+
+            // 处理图片上传
+            if ($image_url) {
+                $update_data['img_url'] = $image_url;
+                $update_data['current_type'] = 1;
+
+                // 同时写入一个图片生成任务记录
+                if ($act_id) {
+                    $pic_task = [
+                        'alias_act_id'  => $act_id,
+                        'ref_img_url' => json_encode([]),
+                        'status' => 'success',
+                        'result_url' => json_encode([$image_url], 256),
+                        'model' => '',
+                        'created_at' => date('Y-m-d H:i:s'),
+                        'updated_at' => date('Y-m-d H:i:s'),
+                    ];
+
+                    DB::table('mp_generate_pic_tasks')->insert($pic_task);
+                }
+            }
+
+            // 处理视频上传
+            if ($video_url) {
+                $update_data['origin_video_url'] = $video_url;
+                $compressed_video_url = compressVideo($video_url);
+                $update_data['current_type'] = 2;
+                $update_data['video_url'] = $compressed_video_url ?: $video_url;
+
+                // 同时写入一个视频生成任务记录
+                if ($act_id) {
+                    $video_task = [
+                        'alias_act_id'  => $act_id,
+                        'status' => 'success',
+                        'result_url' => $update_data['origin_video_url'],
+                        'compressed_url' => $update_data['video_url'],
+                        'created_at' => date('Y-m-d H:i:s'),
+                        'updated_at' => date('Y-m-d H:i:s'),
+                    ];
+
+                    DB::table('mp_generate_video_tasks')->insert($video_task);
+                }
+            }
+
+            // 更新片段信息
+            $result = DB::table('mp_episode_segments')
+                ->where('id', $act_id)
+                ->update($update_data);
+
+            if ($result === false) {
+                Utils::throwError('20003:更新片段失败');
+            }
+
+            DB::commit();
+
+            return true;
+        } catch (\Exception $e) {
+            DB::rollBack();
+            dLog('anime')->error('更新片段失败', [
+                'act_id' => $act_id,
+                'error' => $e->getMessage()
+            ]);
+            Utils::throwError('20003:更新片段失败 ' . $e->getMessage());
+        }
+    }
+
+    public function copyAct($data) {
+        $act_id = getProp($data, 'act_id');
+        
+        // 根据act_id获取记录(全能模式下每个act只有一条记录)
+        $source_segment = DB::table('mp_episode_segments')->where('id', $act_id)->first();
+        if (!$source_segment) Utils::throwError('20003:请选择片段');
+        $video_url = getProp($source_segment, 'video_url');
+        if (!$video_url) Utils::throwError('20003:该片段没有视频无法复制');
+        
+        $anime_id = getProp($source_segment, 'anime_id');
+        $episode_id = getProp($source_segment, 'episode_id');
+        $episode_number = getProp($source_segment, 'episode_number');
+        $act_number = getProp($source_segment, 'act_number');
+
+        try {
+            DB::beginTransaction();
+
+            // 新act的编号
+            $new_act_number = $act_number + 1;
+            
+            // 更新后续所有act的act_number
+            DB::table('mp_episode_segments')
+                ->where('anime_id', $anime_id)
+                ->where('episode_id', $episode_id)
+                ->where('act_number', '>', $act_number)
+                ->increment('act_number');
+
+            // 复制该片段记录
+            $segment_data = (array)$source_segment;
+            unset($segment_data['id']);
+            $segment_data['act_number'] = $new_act_number;
+            $segment_data['created_at'] = $segment_data['updated_at'] = date('Y-m-d H:i:s');
+
+            $id = DB::table('mp_episode_segments')->insertGetId($segment_data);
+            if (!$id) {
+                Utils::throwError('20003:复制片段失败');
+            }
+            
+            DB::commit();
+        }catch (\Exception $e) {
+            DB::rollBack();
+            Utils::throwError('20003:'.$e->getMessage());
+        }
+
+        // 返回新复制的记录
+        $new_segment = DB::table('mp_episode_segments')->selectRaw("id as act_id,anime_id,episode_id,episode_number,act_number,act_title,act_duration,act_content,video_url,video_duration,video_time_point_start,video_time_point_end")->where('id', $id)->first();
+        $new_segment = $new_segment ? (array)$new_segment : [];
+        $new_segment['act_id'] = $id;
+        return $new_segment;
+    }
+
+    public function moveAct($data) {
+        $act_id = getProp($data, 'act_id');
+        $target_act_id = getProp($data, 'target_act_id');
+        
+        // 获取源片段信息
+        $source_segment = DB::table('mp_episode_segments')->where('id', $act_id)->first();
+        if (!$source_segment) Utils::throwError('20003:请选择片段');
+        
+        // 获取目标片段信息
+        $target_segment = DB::table('mp_episode_segments')->where('id', $target_act_id)->first();
+        if (!$target_segment) Utils::throwError('20003:目标片段不存在');
+        
+        $anime_id = getProp($source_segment, 'anime_id');
+        $episode_id = getProp($source_segment, 'episode_id');
+        $source_act_number = getProp($source_segment, 'act_number');
+        $target_act_number = getProp($target_segment, 'act_number');
+        
+        // 验证源片段和目标片段必须属于同一个动漫的同一集
+        $target_anime_id = getProp($target_segment, 'anime_id');
+        $target_episode_id = getProp($target_segment, 'episode_id');
+        
+        if ($anime_id != $target_anime_id || $episode_id != $target_episode_id) {
+            Utils::throwError('20003:只能在同一动漫的同一集内移动片段');
+        }
+        
+        // 如果源片段和目标片段相同,无需移动
+        if ($source_act_number == $target_act_number) {
+            return true;
+        }
+
+        try {
+            DB::beginTransaction();
+
+            if ($source_act_number < $target_act_number) {
+                // 向后移动:源片段移动到目标片段之后
+                // 1. 将源片段和目标片段之间的所有片段编号减1
+                DB::table('mp_episode_segments')
+                    ->where('anime_id', $anime_id)
+                    ->where('episode_id', $episode_id)
+                    ->where('act_number', '>', $source_act_number)
+                    ->where('act_number', '<=', $target_act_number)
+                    ->decrement('act_number');
+                
+                // 2. 将源片段移动到目标片段之后
+                $new_act_number = $target_act_number;
+                
+            } else {
+                // 向前移动:源片段移动到目标片段之后
+                // 1. 将目标片段之后到源片段之前的所有片段编号加1
+                DB::table('mp_episode_segments')
+                    ->where('anime_id', $anime_id)
+                    ->where('episode_id', $episode_id)
+                    ->where('act_number', '>', $target_act_number)
+                    ->where('act_number', '<', $source_act_number)
+                    ->increment('act_number');
+                
+                // 2. 将源片段移动到目标片段之后
+                $new_act_number = $target_act_number + 1;
+            }
+            
+            // 3. 更新源片段的编号
+            $update_result = DB::table('mp_episode_segments')
+                ->where('id', $act_id)
+                ->update([
+                    'act_number' => $new_act_number,
+                    'updated_at' => date('Y-m-d H:i:s')
+                ]);
+                
+            if (!$update_result) {
+                Utils::throwError('20003:更新片段编号失败');
+            }
+
+            DB::commit();
+            return true;
+            
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Utils::throwError('20003:' . $e->getMessage());
+        }
+    }
+
+    public function delAct($data) {
+        $act_id = getProp($data, 'act_id');
+        
+        // 根据act_id获取记录(全能模式下每个act只有一条记录)
+        $segment = DB::table('mp_episode_segments')->where('id', $act_id)->first();
+        if (!$segment) Utils::throwError('20003:请选择片段');
+        
+        $anime_id = getProp($segment, 'anime_id');
+        $episode_id = getProp($segment, 'episode_id');
+        $act_number = getProp($segment, 'act_number');
+
+        try {
+            DB::beginTransaction();
+
+            // 删除该片段记录
+            $deleted = DB::table('mp_episode_segments')->where('id', $act_id)->delete();
+            if (!$deleted) {
+                Utils::throwError('20003:删除片段失败');
+            }
+
+            // 更新后续act的编号
+            DB::table('mp_episode_segments')
+                ->where('anime_id', $anime_id)
+                ->where('episode_id', $episode_id)
+                ->where('act_number', '>', $act_number)
+                ->decrement('act_number');
+                
+            DB::commit();
+        }catch (\Exception $e) {
+            DB::rollBack();
+            Utils::throwError('20003:'.$e->getMessage());
+        }
+
+        return true;
+    }
+
+    public function applyAct($data) {
+        $act_id = getProp($data, 'act_id');
+        $url = getProp($data, 'url');
+        
+        if (!$act_id) Utils::throwError('20003:请选择片段');
+        if (!$url) Utils::throwError('20003:URL不能为空');
+        
+        // 获取URL的文件扩展名
+        $urlPath = parse_url($url, PHP_URL_PATH);
+        $extension = strtolower(pathinfo($urlPath, PATHINFO_EXTENSION));
+        
+        // 定义图片和视频的扩展名
+        $imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
+        $videoExtensions = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm', 'm4v'];
+        
+        // 判断是图片还是视频
+        $updateData = ['updated_at' => date('Y-m-d H:i:s')];
+        
+        if (in_array($extension, $imageExtensions)) {
+            // 图片类型
+            $updateData['img_url'] = $url;
+            $updateData['current_type'] = 1;
+        } elseif (in_array($extension, $videoExtensions)) {
+            // 视频类型
+            $updateData['video_url'] = $url;
+            $updateData['current_type'] = 2;
+        } else {
+            Utils::throwError('20003:不支持的文件类型');
+        }
+        
+        // 更新片段记录(全能模式下每个act只有一条记录)
+        $result = DB::table('mp_episode_segments')
+            ->where('id', $act_id)
+            ->update($updateData);
+        
+        if (!$result) {
+            Utils::throwError('20003:更新片段失败');
+        }
+        
+        return true;
+    }
+
+    public function actChatHistory($data) {
+        $act_id = getProp($data, 'act_id');
+
+        if (!$act_id) Utils::throwError('20003:请选择片段!');
+
+        $query = DB::table('mp_anime_records')->where('act_id', $act_id)->select('role', 'content', 'act_id', 'image_url', 'video_url', 'created_at');
+        
+        $chat = $query->orderBy('id')->get()->map(function ($value) {
+            $value = (array)$value;
+            $value['created_at'] = transDate($value['created_at']);
+            return $value;
+        })->toArray();
+
+        // 获取历史图片
+        $url = [];
+        $pic_history = DB::table('mp_generate_pic_tasks')->where('alias_act_id', $act_id)->where('status', 'success')->orderBy('created_at', 'desc')->get();
+        foreach($pic_history as $task) {
+            $result_url = getProp($task, 'result_url');
+            if (is_json($result_url)) {
+                $url = array_merge($url, json_decode($result_url, true));
+            }else {
+                $url[] = $result_url;
+            }
+        }
+        
+        // 获取历史视频
+        $video_history = DB::table('mp_generate_video_tasks')->where('alias_act_id', $act_id)->where('status', 'success')->orderBy('created_at', 'desc')->get();
+        foreach($video_history as $task) {
+            $result_url = getProp($task, 'compressed_url');
+            if (is_json($result_url)) {
+                $url = array_merge($url, json_decode($result_url, true));
+            }else {
+                $url[] = $result_url;
+            }
+        }
+
+        return compact('chat', 'url');
+    }
+
     public function applyAudioData($data) {
         $segment_id = getProp($data, 'segment_id');
         $global_data = getProp($data, 'global_data');

+ 7 - 0
routes/api.php

@@ -178,6 +178,12 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
             Route::post('moveSegment', [AnimeController::class, 'moveSegment']);                    // 移动分镜
             Route::post('delSegment', [AnimeController::class, 'delSegment']);                      // 删除分镜
             Route::get('applySegment', [AnimeController::class, 'applySegment']);                  // 应用分镜
+            Route::post('addAct', [AnimeController::class, 'addAct']);                              // 新增片段
+            Route::post('editAct', [AnimeController::class, 'editAct']);                            // 编辑片段
+            Route::post('copyAct', [AnimeController::class, 'copyAct']);                            // 复制片段
+            Route::post('moveAct', [AnimeController::class, 'moveAct']);                            // 移动片段
+            Route::post('delAct', [AnimeController::class, 'delAct']);                              // 删除片段
+            Route::get('applyAct', [AnimeController::class, 'applyAct']);                           // 应用片段
             Route::post('segmentHistory', [AnimeController::class, 'segmentHistory']);              // 分镜历史图片/视频
             Route::get('segmentChatHistory', [AnimeController::class, 'segmentChatHistory']);           // 分镜对话历史记录
             Route::post('createSegmentVideoTask', [AnimeController::class, 'createSegmentVideoTask']);  // 分镜图片转视频
@@ -186,6 +192,7 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
             Route::post('previewAudio', [AnimeController::class, 'previewAudio']);                      // 音频试听
             Route::get('episodePicsInfo', [AnimeController::class, 'episodePicsInfo']);                 // 获取主体和场景图片生成信息
             Route::get('clipSegmentVideo', [AnimeController::class, 'clipSegmentVideo']);                       // 裁剪视频
+            Route::get('actChatHistory', [AnimeController::class, 'actChatHistory']);                   // 片段对话历史记录
             
             // 完整视频合成任务
             Route::get('createCompleteVideoTask', [AnimeController::class, 'createCompleteVideoTask']);