Explorar el Código

新增试听音频接口

lh hace 2 meses
padre
commit
2ea3cde438

+ 11 - 1
app/Http/Controllers/Anime/AnimeController.php

@@ -1097,7 +1097,7 @@ class AnimeController extends BaseController
         $data = $request->all();
 
         $result = $this->AnimeService->applyAudioData($data);
-        return $this->success(['success' => $result ? 1 : 0]);
+        return $this->success($result);
     }
 
     // 获取分集生成图片信息
@@ -1938,4 +1938,14 @@ class AnimeController extends BaseController
             'X-Accel-Buffering' => 'no', // 禁用 Nginx 缓冲
         ]);
     }
+
+    /**
+     * 音频试听接口
+     * 创建音频任务并返回结果
+     */
+    public function previewAudio(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->previewAudio($data);
+        return $this->success($result);
+    }
 }

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

@@ -2257,6 +2257,42 @@ class AnimeService
         if ($dialogue_item) {
             $segment_data[] = $dialogue_item;
         }
+
+        // 特殊参数: audio_url,audio_duration,subtitle_info
+        // 这些特殊参数必须同时存在才对当前分镜有效,直接保存但不创建音频任务
+        // 如果不是全部存在,则仍需创建音频任务
+        $special_fields = ['audio_url', 'audio_duration', 'subtitle_info'];
+        $special_update_data = [];
+        $has_all_special_params = false;
+        
+        // 从segment_data中提取特殊参数
+        $filtered_segment_data = [];
+        foreach ($segment_data as $item) {
+            $field_name = trim((string)getProp($item, 'name'));
+            if (in_array($field_name, $special_fields)) {
+                $special_update_data[$field_name] = getProp($item, 'value');
+            } else {
+                // 非特殊参数保留,继续后续处理
+                $filtered_segment_data[] = $item;
+            }
+        }
+        
+        // 检查是否三个特殊参数都存在
+        if (count($special_update_data) === 3 && 
+            isset($special_update_data['audio_url']) && 
+            isset($special_update_data['audio_duration']) && 
+            isset($special_update_data['subtitle_info'])) {
+            $has_all_special_params = true;
+            
+            // 立即更新到当前分镜
+            $special_update_data['updated_at'] = date('Y-m-d H:i:s');
+            DB::table('mp_episode_segments')
+                ->where('segment_id', $segment_id)
+                ->update($special_update_data);
+        }
+        
+        // 使用过滤后的segment_data继续处理其他参数
+        $segment_data = $filtered_segment_data;
         
         $allow_fields = ['dialogue', 'voice_type', 'speed_ratio', 'loudness_ratio', 'emotion_scale'];
         $global_update_data = [];
@@ -2416,8 +2452,14 @@ class AnimeService
             }
 
             // 为所有有变化的分镜创建音频合成任务
+            // 但如果当前分镜同时设置了全部三个特殊参数(audio_url, audio_duration, subtitle_info),则跳过该分镜
             if (!empty($segment_ids_to_create_task)) {
                 foreach ($segment_ids_to_create_task as $sid) {
+                    // 如果当前分镜同时设置了全部三个特殊参数,则跳过音频任务创建
+                    if ($sid === $segment_id && $has_all_special_params) {
+                        continue;
+                    }
+                    
                     // 重新获取更新后的分镜数据
                     $updated_segment = DB::table('mp_episode_segments')
                         ->where('segment_id', $sid)
@@ -3602,4 +3644,76 @@ class AnimeService
             return '图片描述生成失败: ' . $e->getMessage();
         }
     }
+
+    /**
+     * 音频试听接口
+     * 创建音频任务并轮询获取结果
+     * 
+     * @param array $data 参数数组
+     * @return array 返回音频URL或错误信息
+     */
+    public function previewAudio($data) {
+        $dialogue = getProp($data, 'dialogue');
+        
+        // 必填参数验证
+        if (!$dialogue) Utils::throwError('20003:dialogue不能为空');
+    
+        // 获取参数,优先使用传入的参数,否则使用分镜中的参数
+        $voice_type = getProp($data, 'voice_type');
+        $voice_name = getProp($data, 'voice_name');
+        $voice_actor = getProp($data, 'voice_actor');
+        $emotion_type = getProp($data, 'emotion_type');
+        $gender = getProp($data, 'gender', 0);
+        $emotion = getProp($data, 'emotion');
+        $speed_ratio = getProp($data, 'speed_ratio', 0);
+        $loudness_ratio = getProp($data, 'loudness_ratio', 0);
+        $emotion_scale = getProp($data, 'emotion_scale', 0);
+        $pitch = getProp($data, 'pitch', 0);
+        
+        try {
+            $now = date('Y-m-d H:i:s');
+            
+            // 构建生成参数
+            $generate_json = json_encode([
+                'text' => $dialogue,
+                'role' => $voice_actor,
+                'voice_type' => $voice_type,
+                'voice_name' => $voice_name,
+                'emotion' => $emotion,
+                'emotion_type' => $emotion_type,
+                'gender' => $gender,
+                'speed_ratio' => $speed_ratio,
+                'loudness_ratio' => $loudness_ratio,
+                'emotion_scale' => $emotion_scale,
+                'pitch' => $pitch,
+            ], 256);
+            
+            // 请求远程服务器执行生成
+            $client = new Client(['timeout' => 600, 'verify' => false]);
+            $result = $client->get("http://122.9.129.83:5000/api/anime/audioPreview?generateJson={$generate_json}");
+            $response = $result->getBody()->getContents();
+            $response_arr = json_decode($response, true);
+            
+            if (!isset($response_arr['code']) || (int)$response_arr['code'] !== 0) {
+                $error_msg = isset($response_arr['msg']) ? $response_arr['msg'] : '未知错误';
+                dLog('anime')->error('音频试听任务创建失败', ['error' => $error_msg, 'response_arr' => $response_arr]);
+                Utils::throwError('20003:音频试听任务创建失败: ' . $error_msg);
+            }
+
+            $arr = $response_arr['data'];
+            $subtitle_info = $arr['subtitle_info'];
+            $audio_duration = json_decode($subtitle_info, true)['duration'];
+            if (!isset($arr['url']) || !$audio_duration || !$subtitle_info) Utils::throwError('20003:音频参数生成异常');
+            return [
+                'audio_url'         => $arr['url'],
+                'subtitle_info'     => $subtitle_info,
+                'audio_duration'    => $audio_duration
+            ];
+            
+        } catch (\Exception $e) {
+            dLog('anime')->error('音频试听失败', ['error' => $e->getMessage()]);
+            Utils::throwError('20003:' . $e->getMessage());
+        }
+    }
 }
+

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3 - 3
app/Services/DeepSeek/DeepSeekService.php


+ 1 - 0
routes/api.php

@@ -168,6 +168,7 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
         Route::post('createSegmentVideoTask', [AnimeController::class, 'createSegmentVideoTask']);  // 分镜图片转视频
         Route::post('batchSetSegmentVideos', [AnimeController::class, 'batchSetSegmentVideos']);    // 一键转视频
         Route::post('applyAudioData', [AnimeController::class, 'applyAudioData']);                  // 修改分镜音频参数
+        Route::post('previewAudio', [AnimeController::class, 'previewAudio']);                      // 音频试听
         Route::get('episodePicsInfo', [AnimeController::class, 'episodePicsInfo']);                 // 获取主体和场景图片生成信息
         
         // 完整视频合成任务