lh 3 ay önce
ebeveyn
işleme
8bd85505f3

+ 1 - 1
app/Console/Test/TestCommand.php

@@ -51,7 +51,7 @@ class TestCommand extends Command
     public function handle()
     public function handle()
     {
     {
         // dd(testStoryboardParsing(''));
         // dd(testStoryboardParsing(''));
-        // dd(handleEpisodeContent(''));
+        dd(handleEpisodeContent(''));
         
         
         exit();
         exit();
         $url = 'https://zw-audiobook.tos-cn-beijing.volces.com/video/ai_generation_1772704798_69a9541e94bef';
         $url = 'https://zw-audiobook.tos-cn-beijing.volces.com/video/ai_generation_1772704798_69a9541e94bef';

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

@@ -79,6 +79,27 @@ class AnimeController extends BaseController
         return $this->success(['success'=>$result ? 1 : 0]);
         return $this->success(['success'=>$result ? 1 : 0]);
     }
     }
 
 
+    // 修改分集主体列表
+    public function changeEpisodeRoles(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->changeEpisodeRoles($data);
+        return $this->success(['success'=>$result ? 1 : 0]);
+    }
+
+    // 修改分集场景列表
+    public function changeEpisodeScenes(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->changeEpisodeScenes($data);
+        return $this->success(['success'=>$result ? 1 : 0]);
+    }
+
+    // 编辑分镜剧本
+    public function editSegment(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->editSegment($data);
+        return $this->success(['success'=>$result ? 1 : 0]);
+    }
+
     // 动漫对话列表
     // 动漫对话列表
     public function chatList(Request $request) {
     public function chatList(Request $request) {
         $data = $request->all();
         $data = $request->all();
@@ -205,6 +226,10 @@ class AnimeController extends BaseController
     }
     }
 
 
     public function createSegmentVideoTask(Request $request) {
     public function createSegmentVideoTask(Request $request) {
+        // 忽略所有超时限制
+        set_time_limit(0);
+        ini_set('max_execution_time', '0');
+
         $data = $request->all();
         $data = $request->all();
         
         
         // 验证参数
         // 验证参数
@@ -380,6 +405,10 @@ class AnimeController extends BaseController
      * 批量生成分镜视频
      * 批量生成分镜视频
      */
      */
     public function batchSetSegmentVideos(Request $request) {
     public function batchSetSegmentVideos(Request $request) {
+        // 忽略所有超时限制
+        set_time_limit(0);
+        ini_set('max_execution_time', '0');
+
         $data = $request->all();
         $data = $request->all();
         
         
         // 验证参数
         // 验证参数

Dosya farkı çok büyük olduğundan ihmal edildi
+ 100 - 78
app/Libs/Helpers.php


+ 135 - 5
app/Services/Anime/AnimeService.php

@@ -195,14 +195,14 @@ class AnimeService
             if (!empty($anime_id)) {
             if (!empty($anime_id)) {
                 $boolen = DB::table('mp_animes')->where('id', $anime_id)->update($table_data);
                 $boolen = DB::table('mp_animes')->where('id', $anime_id)->update($table_data);
                 if (!$boolen) {
                 if (!$boolen) {
-                    dLog('deepseek')->info('对话保存失败', $table_data);
+                    dLog('anime')->info('对话保存失败', $table_data);
                     Utils::throwError('20003:对话保存失败');
                     Utils::throwError('20003:对话保存失败');
                 }
                 }
             }else {
             }else {
                 $table['created_at'] = $table_data['updated_at'];
                 $table['created_at'] = $table_data['updated_at'];
                 $anime_id = DB::table('mp_animes')->insertGetId($table_data);
                 $anime_id = DB::table('mp_animes')->insertGetId($table_data);
                 if (!$anime_id) {
                 if (!$anime_id) {
-                    dLog('deepseek')->info('对话保存失败', $table_data);
+                    dLog('anime')->info('对话保存失败', $table_data);
                     Utils::throwError('20003:对话保存失败');
                     Utils::throwError('20003:对话保存失败');
                 }
                 }
             }
             }
@@ -462,6 +462,136 @@ class AnimeService
         return $img_url;
         return $img_url;
     }
     }
 
 
+    public function changeEpisodeRoles($data) {
+        $anime_id = getProp($data, 'anime_id');
+        $episode_id = getProp($data, 'episode_id');
+        $roles = getProp($data, 'roles');
+
+        // 参数验证
+        if (!$anime_id) Utils::throwError('20003:请提供动漫ID');
+        if (!$episode_id) Utils::throwError('20003:请提供剧集ID');
+        if (!is_array($roles)) Utils::throwError('20003:角色列表必须是数组格式');
+
+        // 验证剧集是否存在
+        $episode = DB::table('mp_anime_episodes')
+            ->where('anime_id', $anime_id)
+            ->where('id', $episode_id)
+            ->first();
+        
+        if (!$episode) Utils::throwError('20003:该剧集不存在');
+
+        try {
+            // 更新角色列表
+            $result = DB::table('mp_anime_episodes')
+                ->where('anime_id', $anime_id)
+                ->where('id', $episode_id)
+                ->update([
+                    'roles' => json_encode($roles, 256),
+                    'updated_at' => date('Y-m-d H:i:s')
+                ]);
+
+            if ($result === false) {
+                Utils::throwError('20003:更新角色列表失败');
+            }
+
+            return ['success' => true, 'message' => '角色列表更新成功'];
+        } catch (\Exception $e) {
+            dLog('anime')->error('更新剧集角色失败', [
+                'anime_id' => $anime_id,
+                'episode_id' => $episode_id,
+                'error' => $e->getMessage()
+            ]);
+            Utils::throwError('20003:更新角色列表失败: ' . $e->getMessage());
+        }
+    }
+
+    public function changeEpisodeScenes($data) {
+        $anime_id = getProp($data, 'anime_id');
+        $episode_id = getProp($data, 'episode_id');
+        $scenes = getProp($data, 'scenes');
+
+        // 参数验证
+        if (!$anime_id) Utils::throwError('20003:请提供动漫ID');
+        if (!$episode_id) Utils::throwError('20003:请提供剧集ID');
+        if (!is_array($scenes)) Utils::throwError('20003:场景列表必须是数组格式');
+
+        // 验证剧集是否存在
+        $episode = DB::table('mp_anime_episodes')
+            ->where('anime_id', $anime_id)
+            ->where('id', $episode_id)
+            ->first();
+        
+        if (!$episode) Utils::throwError('20003:该剧集不存在');
+
+        try {
+            // 更新场景列表
+            $result = DB::table('mp_anime_episodes')
+                ->where('anime_id', $anime_id)
+                ->where('id', $episode_id)
+                ->update([
+                    'scenes' => json_encode($scenes, 256),
+                    'updated_at' => date('Y-m-d H:i:s')
+                ]);
+
+            if ($result === false) {
+                Utils::throwError('20003:更新场景列表失败');
+            }
+
+            return ['success' => true, 'message' => '场景列表更新成功'];
+        } catch (\Exception $e) {
+            dLog('anime')->error('更新剧集场景失败', [
+                'anime_id' => $anime_id,
+                'episode_id' => $episode_id,
+                'error' => $e->getMessage()
+            ]);
+            Utils::throwError('20003:更新场景列表失败: ' . $e->getMessage());
+        }
+    }
+
+    public function editSegment($data) {
+        $segment_id = getProp($data, 'segment_id');
+        $segment_content = getProp($data, 'segment_content');
+
+        // 参数验证
+        if (!$segment_id) Utils::throwError('20003:请提供分镜ID');
+        if (!$segment_content) Utils::throwError('20003:请提供分镜内容');
+
+        // 验证分镜是否存在
+        $segment = DB::table('mp_episode_segments')
+            ->where('segment_id', $segment_id)
+            ->first();
+        
+        if (!$segment) Utils::throwError('20003:该分镜不存在');
+
+        try {
+            // 准备更新数据
+            $update_data = [
+                'segment_content' => $segment_content,
+                'updated_at' => date('Y-m-d H:i:s')
+            ];
+
+            // 使用现有方法分析segment_content,提取各个字段
+            $this->handleSegmentContent($update_data);
+
+            // 更新分镜信息
+            $result = DB::table('mp_episode_segments')
+                ->where('segment_id', $segment_id)
+                ->update($update_data);
+
+            if ($result === false) {
+                Utils::throwError('20003:更新分镜剧本失败');
+            }
+
+            return true;
+        } catch (\Exception $e) {
+            dLog('anime')->error('更新分镜剧本失败', [
+                'segment_id' => $segment_id,
+                'error' => $e->getMessage()
+            ]);
+            Utils::throwError('20003:更新分镜剧本失败: ' . $e->getMessage());
+        }
+    }
+
     public function batchSetSegmentPics($data) {
     public function batchSetSegmentPics($data) {
         $anime_id = getProp($data, 'anime_id');
         $anime_id = getProp($data, 'anime_id');
         $episode_id = getProp($data, 'episode_id');
         $episode_id = getProp($data, 'episode_id');
@@ -861,7 +991,7 @@ class AnimeService
             
             
 
 
             // 更新分镜剧本信息
             // 更新分镜剧本信息
-            $this->handleEpisodeContent($update_data);
+            $this->handleSegmentContent($update_data);
             $boolen = DB::table('mp_episode_segments')
             $boolen = DB::table('mp_episode_segments')
                 ->where('segment_id', $segment_id)
                 ->where('segment_id', $segment_id)
                 ->update($update_data);
                 ->update($update_data);
@@ -996,7 +1126,7 @@ class AnimeService
             ];
             ];
 
 
             // 更新分镜剧本信息
             // 更新分镜剧本信息
-            $this->handleEpisodeContent($insert_data);
+            $this->handleSegmentContent($insert_data);
 
 
             // 如果没有上传图片则使用当前描述进行生成
             // 如果没有上传图片则使用当前描述进行生成
             if (!$img_url) {
             if (!$img_url) {
@@ -1343,7 +1473,7 @@ class AnimeService
     }
     }
 
 
     // 从分镜剧本中提取关键字段
     // 从分镜剧本中提取关键字段
-    private function handleEpisodeContent(&$data) {
+    private function handleSegmentContent(&$data) {
         $segmentContent = getProp($data, 'segment_content');
         $segmentContent = getProp($data, 'segment_content');
         // 解析分镜详细信息
         // 解析分镜详细信息
         $segmentData = [
         $segmentData = [

+ 33 - 23
app/Services/DeepSeek/DeepSeekService.php

@@ -1182,7 +1182,7 @@ class DeepSeekService
                             yield [
                             yield [
                                 'type' => 'content',
                                 'type' => 'content',
                                 'content' => $delta['content'],
                                 'content' => $delta['content'],
-                                'full_content' => $fullContent
+                                // 'full_content' => $fullContent
                             ];
                             ];
                         }
                         }
                     }
                     }
@@ -1961,7 +1961,7 @@ class DeepSeekService
                             yield [
                             yield [
                                 'type' => 'content',
                                 'type' => 'content',
                                 'content' => $delta['content'],
                                 'content' => $delta['content'],
-                                'full_content' => $fullContent
+                                // 'full_content' => $fullContent
                             ];
                             ];
                         }
                         }
                     }
                     }
@@ -2386,7 +2386,7 @@ class DeepSeekService
                             yield [
                             yield [
                                 'type' => 'content',
                                 'type' => 'content',
                                 'content' => $delta['content'],
                                 'content' => $delta['content'],
-                                'full_content' => $fullContent
+                                // 'full_content' => $fullContent
                             ];
                             ];
                         }
                         }
                     }
                     }
@@ -2530,10 +2530,19 @@ class DeepSeekService
         $scenes = $base_episode ? json_decode((string)getProp($base_episode, 'scenes'), true) : json_decode((string)getProp($anime, 'scenes'), true);
         $scenes = $base_episode ? json_decode((string)getProp($base_episode, 'scenes'), true) : json_decode((string)getProp($anime, 'scenes'), true);
         $roles = is_array($roles) ? $roles : [];
         $roles = is_array($roles) ? $roles : [];
         $scenes = is_array($scenes) ? $scenes : [];
         $scenes = is_array($scenes) ? $scenes : [];
+
         // 转换主体列表和场景列表的格式
         // 转换主体列表和场景列表的格式
         $roles_content = $this->buildEpisodeItemContent($roles, 'role');
         $roles_content = $this->buildEpisodeItemContent($roles, 'role');
         $scenes_content = $this->buildEpisodeItemContent($scenes, 'scene');
         $scenes_content = $this->buildEpisodeItemContent($scenes, 'scene');
 
 
+        // 获取音色列表
+        $timbres = DB::table('mp_timbres')->select('timbre_name')->where('is_enabled', 1)->where('id', '<=', 15)->get()->map(function ($value) {
+            $value = (array)$value;
+            $value['timbre_name'] = str_replace('(多情感)', '', $value['timbre_name']);
+            return $value;
+        })->pluck('timbre_name')->toArray();
+        $timbres_content = implode('、', $timbres);
+
         $existing_roles = $base_episode ? json_decode((string)getProp($base_episode, 'roles'), true) : [];
         $existing_roles = $base_episode ? json_decode((string)getProp($base_episode, 'roles'), true) : [];
         $existing_scenes = $base_episode ? json_decode((string)getProp($base_episode, 'scenes'), true) : [];
         $existing_scenes = $base_episode ? json_decode((string)getProp($base_episode, 'scenes'), true) : [];
         $existing_roles = is_array($existing_roles) ? $existing_roles : [];
         $existing_roles = is_array($existing_roles) ? $existing_roles : [];
@@ -2560,22 +2569,23 @@ class DeepSeekService
         $demo = "你是一个专业的文档分析助手及资深编剧,请根据用户提供的文档内容完成示例格式的内容输出(需包含以下几个板块: <剧集标题><故事梗概><美术风格><主体列表><场景列表><分镜剧本>,每个板块之间用###分隔;同时板块之间需满足以下要求:\n
         $demo = "你是一个专业的文档分析助手及资深编剧,请根据用户提供的文档内容完成示例格式的内容输出(需包含以下几个板块: <剧集标题><故事梗概><美术风格><主体列表><场景列表><分镜剧本>,每个板块之间用###分隔;同时板块之间需满足以下要求:\n
                     强制要求:
                     强制要求:
                     1.你只负责与剧本相关的内容,如果用户输入与剧本无关的内容,请告知用户并拒绝继续回答,此为第一优先原则,不满足此原则就忽略其他要求并停止继续输出
                     1.你只负责与剧本相关的内容,如果用户输入与剧本无关的内容,请告知用户并拒绝继续回答,此为第一优先原则,不满足此原则就忽略其他要求并停止继续输出
-                    2.如果用户输入修改美术风格、修改画风这类内容,请告知用户不可修改美术风格,并拒绝继续回答\n
+                    2.如果用户输入修改美术风格、修改画风这类内容,请告知用户不可修改美术风格,并拒绝继续回答
                     3.以上两条要求对修改主体角色或场景不生效,允许用户调整主体角色说明和场景描述等\n
                     3.以上两条要求对修改主体角色或场景不生效,允许用户调整主体角色说明和场景描述等\n
                     普通要求:
                     普通要求:
                     1.剧集标题必须与文档内容高度相关,剧集序号是{$episode_number}
                     1.剧集标题必须与文档内容高度相关,剧集序号是{$episode_number}
-                    2.<主体列表>必须在以下主体中选择多个(根据拆分出的分镜剧本来确认具体几个),不得自定义(需带上冒号后的具体描述):{$roles_content}\n
+                    2.<主体列表>必须在以下主体中选择多个(根据拆分出的分镜剧本来确认具体几个),不得自定义(需带上冒号后的具体描述):\n{$roles_content}
                     2.1如果分集内容中出现了<主体列表>中不存在的新主体,则不用在上述主体中选择,而是按照相同的格式新增一个主体显示在主题列表中
                     2.1如果分集内容中出现了<主体列表>中不存在的新主体,则不用在上述主体中选择,而是按照相同的格式新增一个主体显示在主题列表中
-                    3.<场景列表>必须在以下场景中选择多个(根据拆分出的分镜剧本来确认具体几个),不得自定义(需带上冒号后的具体描述):{$scenes_content}\n
-                    4.<分镜剧本>要求包含“分幕标题”以及“分镜信息”: \n
-                    4.1“分幕标题”是根据章节中的场景进行拆分,类似于“第1幕 场景、时间及室内或室外”的信息,其中场景只能在所给出的场景列表中选(不带场景详细描述)。\n
-                    4.2“分镜信息”需同一场景内的对话内容完成分镜(每一幕分镜尽量不得低于5个),需包含“画面描述”、“构图设计”、“运镜调度”、“配音音色”、“台词内容”和“画面类型”这几个部分,其中“画面描述”如果出现主体,只能选择上述主体列表中的一个,主体的名称也需要保持一致(不带主体具体描述)。\n
-                    4.3分镜序号用1、2、3显示,如分镜1、分镜2,并且分镜序号需连续(跨分幕中的分镜序号需连续,但跨剧集中的不需要连续,如第2集的第1幕分镜序号从1开始)。\n
-                    4.4“分镜信息”中的“台词内容”需与原文中的台词完全一致,不得修改或添加任何内容。\n
-                    4.5“分镜信息”中的“配音角色”需对应本集中的<主体列表>中的一个(非对话内容则统一固定为“旁白”角色),不得自己生成。\n
-                    4.6“分镜信息”中的“场景”需对应本集中的<场景列表>中的一个(不带详细表述)\n
-                    4.7“分镜信息”中的“出镜角色”需对应本集中的<主体列表>中的一个或多个(不带详细描述),如果没有出镜角色则填无\n
-                    4.8“分镜信息”中的“尾帧描述”需根据本镜和下一镜的剧本信息进行过渡生成,用于后续转视频进行衔接上下镜头的画面\n\n
+                    2.2主体列表的音色必须在以下音色中($timbres_content)选择,选择的音色放在描述的最后用{{}}框起来
+                    3.<场景列表>必须在以下场景中选择多个(根据拆分出的分镜剧本来确认具体几个),不得自定义(需带上冒号后的具体描述):\n{$scenes_content}
+                    4.<分镜剧本>要求包含“分幕标题”以及“分镜信息”: 
+                    4.1“分幕标题”是根据章节中的场景进行拆分,类似于“第1幕 场景、时间及室内或室外”的信息,其中场景只能在所给出的场景列表中选(不带场景详细描述)。
+                    4.2“分镜信息”需同一场景内的对话内容完成分镜(每一幕分镜尽量不得低于5个),需包含“画面描述”、“构图设计”、“运镜调度”、“配音音色”、“台词内容”和“画面类型”这几个部分,其中“画面描述”如果出现主体,只能选择上述主体列表中的一个,主体的名称也需要保持一致(不带主体具体描述)。
+                    4.3分镜序号用1、2、3显示,如分镜1、分镜2,并且分镜序号需连续(跨分幕中的分镜序号需连续,但跨剧集中的不需要连续,如第2集的第1幕分镜序号从1开始)。
+                    4.4“分镜信息”中的“台词内容”需与原文中的台词完全一致,不得修改或添加任何内容。
+                    4.5“分镜信息”中的“配音角色”需对应本集中的<主体列表>中的一个(非对话内容则统一固定为“旁白”角色),不得自己生成。
+                    4.6“分镜信息”中的“场景”需对应本集中的<场景列表>中的一个(不带详细表述)
+                    4.7“分镜信息”中的“出镜角色”需对应本集中的<主体列表>中的一个或多个(不带详细描述),如果没有出镜角色则填无
+                    4.8“分镜信息”中的“尾帧描述”需根据本镜和下一镜的剧本信息进行过渡生成,用于后续转视频进行衔接上下镜头的画面\n
                 示例格式:\n
                 示例格式:\n
                 第1集:隐形的守护者
                 第1集:隐形的守护者
 
 
@@ -2587,11 +2597,11 @@ class DeepSeekService
                 视觉风格描述:整体采用精致的韩漫厚涂风格,以浅灰冷调为基调,营造出重生复仇的清冷与压抑感。画面强调高对比度的光影处理,网吧场景通过低饱和度的杂乱色调表现颓废感,而清晨车祸瞬间则利用强烈的动态模糊与局部高光,突显“透明守护者”存在的神秘感与宿命感。人物形象细腻,眼神充满坚毅与破碎交织的故事感,完美契合偏执救赎的主题。
                 视觉风格描述:整体采用精致的韩漫厚涂风格,以浅灰冷调为基调,营造出重生复仇的清冷与压抑感。画面强调高对比度的光影处理,网吧场景通过低饱和度的杂乱色调表现颓废感,而清晨车祸瞬间则利用强烈的动态模糊与局部高光,突显“透明守护者”存在的神秘感与宿命感。人物形象细腻,眼神充满坚毅与破碎交织的故事感,完美契合偏执救赎的主题。
                 
                 
                 ###主体列表
                 ###主体列表
-                许芸-校服装:重生后的“假千金”,清醒果敢,不再任人唯亲。她是一名高中生,身材纤细,留着乌黑齐肩短发,眼神坚定。
-                许芸-卫衣装:半个月后居家或外出时的装扮,在清冷的环境中透着一丝坚毅与破碎感。
-                程景:偏执深情的学霸,为救许芸变得“不可见”,是始终默默守护的隐形爱人。他身材高大挺拔,面容英俊。
-                卞大伟:许芸名义上的表哥,阴险暴戾的无业游民。他身材肥胖,面部肉感重,一双小眼睛透着阴冷。
-                徐母:许芸亲生母亲,重男轻女且极度刻薄,面容严厉。
+                许芸-校服装:重生后的“假千金”,清醒果敢,不再任人唯亲。她是一名高中生,身材纤细,留着乌黑齐肩短发,眼神坚定。{{甜心小美}}
+                许芸-卫衣装:半个月后居家或外出时的装扮,在清冷的环境中透着一丝坚毅与破碎感。{{爽快思思}}
+                程景:偏执深情的学霸,为救许芸变得“不可见”,是始终默默守护的隐形爱人。他身材高大挺拔,面容英俊。{{阳光青年}}
+                卞大伟:许芸名义上的表哥,阴险暴戾的无业游民。他身材肥胖,面部肉感重,一双小眼睛透着阴冷。{{广州德哥}}
+                徐母:许芸亲生母亲,重男轻女且极度刻薄,面容严厉。{{邻居阿姨}}
                 
                 
                 ###场景列表
                 ###场景列表
                 徐家老旧厨房:这是徐母劳作和惩罚许芸的地方。空间狭窄阴暗,充满了生活琐碎的压抑感。室内有一个旧式锅炉,案板上散落着面粉和包好的馄饨,光影对比强烈,凸显出家庭环境的冷酷。
                 徐家老旧厨房:这是徐母劳作和惩罚许芸的地方。空间狭窄阴暗,充满了生活琐碎的压抑感。室内有一个旧式锅炉,案板上散落着面粉和包好的馄饨,光影对比强烈,凸显出家庭环境的冷酷。
@@ -2801,7 +2811,7 @@ class DeepSeekService
                             yield [
                             yield [
                                 'type' => 'content',
                                 'type' => 'content',
                                 'content' => $delta['content'],
                                 'content' => $delta['content'],
-                                'full_content' => $fullContent
+                                // 'full_content' => $fullContent
                             ];
                             ];
                         }
                         }
                     }
                     }
@@ -2847,8 +2857,8 @@ class DeepSeekService
         $generated_scenes = isset($episode_arr['scenes']) && is_array($episode_arr['scenes']) ? $episode_arr['scenes'] : [];
         $generated_scenes = isset($episode_arr['scenes']) && is_array($episode_arr['scenes']) ? $episode_arr['scenes'] : [];
         $merged_roles = $this->mergeEpisodeResourceItems($existing_roles, $generated_roles, 'role');
         $merged_roles = $this->mergeEpisodeResourceItems($existing_roles, $generated_roles, 'role');
         $merged_scenes = $this->mergeEpisodeResourceItems($existing_scenes, $generated_scenes, 'scene');
         $merged_scenes = $this->mergeEpisodeResourceItems($existing_scenes, $generated_scenes, 'scene');
-        // dLog('deepseek')->info('修改后的数据: ', [$merged_roles, $merged_scenes]);
-        // exit();
+        dLog('deepseek')->info('修改后的数据: ', [$merged_roles, $merged_scenes]);
+        exit();
         $now = date('Y-m-d H:i:s');
         $now = date('Y-m-d H:i:s');
 
 
         try {
         try {

+ 3 - 0
routes/api.php

@@ -139,6 +139,9 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
         Route::get('episodeVersions', [AnimeController::class, 'episodeVersions']);
         Route::get('episodeVersions', [AnimeController::class, 'episodeVersions']);
         Route::get('bindEpisodeVersion', [AnimeController::class, 'bindEpisodeVersion']);
         Route::get('bindEpisodeVersion', [AnimeController::class, 'bindEpisodeVersion']);
         Route::post('edit', [AnimeController::class, 'editAnime']);
         Route::post('edit', [AnimeController::class, 'editAnime']);
+        Route::post('changeEpisodeRoles', [AnimeController::class, 'changeEpisodeRoles']);
+        Route::post('changeEpisodeScenes', [AnimeController::class, 'changeEpisodeScenes']);
+        Route::post('editSegment', [AnimeController::class, 'editSegment']);
         Route::post('batchUploadImg', [ImageGenerationController::class, 'batchUploadImg']);
         Route::post('batchUploadImg', [ImageGenerationController::class, 'batchUploadImg']);
         Route::post('batchSetRoleImg', [AnimeController::class, 'batchSetRoleImg']);
         Route::post('batchSetRoleImg', [AnimeController::class, 'batchSetRoleImg']);
         Route::post('batchSetSceneImg', [AnimeController::class, 'batchSetSceneImg']);
         Route::post('batchSetSceneImg', [AnimeController::class, 'batchSetSceneImg']);