lh преди 22 часа
родител
ревизия
c7452eeb6b
променени са 5 файла, в които са добавени 121 реда и са изтрити 11 реда
  1. 2 0
      app/Console/Test/TestCommand.php
  2. 7 0
      app/Http/Controllers/DeepSeek/DeepSeekController.php
  3. 20 5
      app/Libs/Helpers.php
  4. 91 6
      app/Services/DeepSeek/DeepSeekService.php
  5. 1 0
      routes/api.php

Файловите разлики са ограничени, защото са твърде много
+ 2 - 0
app/Console/Test/TestCommand.php


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

@@ -52,6 +52,13 @@ class DeepSeekController extends BaseController
         return $this->success($result);
     }
 
+    // 保存段落音频
+    public function saveParagraphAudio(Request $request) {
+        $data = $request->all();
+        $result = $this->deepseekService->saveParagraphAudio($data);
+        return $this->success(['success'=>$result ? 1 : 0]);
+    }
+
     /**
      * 新增合成任务
      *

+ 20 - 5
app/Libs/Helpers.php

@@ -1689,18 +1689,26 @@ function getTextTokens($text) {
 }
 
 // 处理小说剧本文本
-function handleScriptWords($text) {
+function handleScriptWords($text, $enable_emotion=1) {
     $text = preg_replace('/[\r\n]+/', PHP_EOL, $text);
     $text_arr = explode(PHP_EOL, $text);
     $roles = [];
     $words = [];
     $role_gender = [];
+    // $sequence = 0;
     foreach ($text_arr as $line) {
         $line = trim($line);
 
-        preg_match('/^(.*?)\:(.*?)\{(.*?)\}$/', $line, $matches);
+        if ($enable_emotion) {
+            $match_rule = '/^(.*?)\:(.*?)\{(.*?)\}$/';
+            $count = 4;
+        } else {
+            $match_rule = '/^(.*?)\:(.*?)$/';
+            $count = 3;
+        }
+        preg_match($match_rule, $line, $matches);
         
-        if (count($matches) == 4) {
+        if (count($matches) == $count) {
             $gender = '0';
             // 角色部分拆分
             preg_match('/^(.*?)\((.*?)\)$/', $matches[1], $matches2);
@@ -1719,10 +1727,11 @@ function handleScriptWords($text) {
                 'role'      => $role,
                 'gender'    => $gender,
                 'text'      => $matches[2],
-                'emotion'   => $matches[3],
+                'emotion'   => $enable_emotion ? $matches[3] : '',
             ];
         }
     }
+    dd($words);
 
     $new_words = [];
     $tmp = '';
@@ -1740,6 +1749,8 @@ function handleScriptWords($text) {
                 'emotion'   => $word['emotion'],
             ];
         }else {
+            // $sequence++;
+            // $tmp_arr['sequence'] = $sequence;
             $new_words[] = $tmp_arr;
             $tmp = $word['role'].'-'.$word['emotion'];
             $tmp_text = $word['text'];
@@ -1751,7 +1762,11 @@ function handleScriptWords($text) {
             ];
         }
     }
-    if ($tmp_arr) $new_words[] = $tmp_arr;
+    if ($tmp_arr) {
+        // $sequence++;
+        // $tmp_arr['sequence'] = $sequence;
+        $new_words[] = $tmp_arr;
+    }
 
     return [
         'roles' => $roles,

+ 91 - 6
app/Services/DeepSeek/DeepSeekService.php

@@ -88,7 +88,7 @@ class DeepSeekService
         }
 
         // 处理获取到的剧本数据
-        $script_content = handleScriptWords($content);
+        $script_content = handleScriptWords($content, $enable_emotion);
         $result = [
             'origin_content'    => $content,
             'roles'             => getProp($script_content, 'roles'),
@@ -98,6 +98,40 @@ class DeepSeekService
         return $result;
     }
 
+    public function saveParagraphAudio($data) {
+        $bid = getProp($data, 'bid');
+        $cid = getProp($data, 'cid');
+        $version_id = getProp($data, 'version_id');
+        $sequence = getProp($data, 'sequence');
+        $id = DB::table('mp_chapter_paragraph_audios')->where('bid', $bid)->where('cid', $cid)->where('version_id', $version_id)->where('sequence', $sequence)->value('id');
+        $list = [
+            'bid'           => $bid,
+            'cid'           => $cid,
+            'version_id'    => $version_id,
+            'sequence'      => $sequence,
+            'role'          => getProp($data, 'role'),
+            'gender'        => getProp($data, 'gender'),
+            'text'          => trim(getProp($data, 'text')),
+            'emotion'       => getProp($data, 'emotion'),
+            'emotion_type'  => getProp($data, 'emotion_type'),
+            'voice_type'    => getProp($data, 'voice_type'),
+            'voice_name'    => getProp($data, 'voice_name'),
+            'speed_ratio'   => getProp($data, 'speed_ratio'),
+            'loudness_ratio'=> getProp($data, 'loudness_ratio'),
+            'emotion_scale' => getProp($data, 'emotion_scale'),
+            'updated_at'    => date('Y-m-d H:i:s')
+        ];
+        if (getProp($data, 'paragraph_audio_url')) $list['paragraph_audio_url'] = getProp($data, 'paragraph_audio_url');
+        if ($id) {
+            $boolen = DB::table('mp_chapter_paragraph_audios')->where('id', $id)->update($list);
+        }else {
+            $list['created_at'] = date('Y-m-d H:i:s');
+            $boolen = DB::table('mp_chapter_paragraph_audios')->insert($list);
+        }
+
+        return $boolen;
+    }
+
     // 新增合成任务
     public function addGenerateTask($data) {
         $bid = getProp($data, 'bid');
@@ -105,6 +139,26 @@ class DeepSeekService
         $version_id = getProp($data, 'version_id');
         $generate_json = getProp($data, 'generate_json');
 
+        // 获取已生成的音频
+        $paragraph_audios = DB::table('mp_chapter_paragraph_audios')->where('bid', $bid)->where('cid', $cid)->where('version_id', $version_id)->get();
+
+        $paragraph_list = [];
+        foreach($paragraph_audios as $item) {
+            $paragraph_list[getProp($item, 'sequence')] = [
+                'role'                  => getProp($item, 'role'),
+                'gender'                => getProp($item, 'gender'),
+                'text'                  => trim(getProp($item, 'text')),
+                'emotion'               => getProp($item, 'emotion'),
+                'emotion_type'          => getProp($item, 'emotion_type'),
+                'voice_type'            => getProp($item, 'voice_type'),
+                'voice_name'            => getProp($item, 'voice_name'),
+                'speed_ratio'           => getProp($item, 'speed_ratio'),
+                'loudness_ratio'        => getProp($item, 'loudness_ratio'),
+                'emotion_scale'         => getProp($item, 'emotion_scale'),
+                'paragraph_audio_url'   => getProp($item, 'paragraph_audio_url'),
+            ];
+        }
+
         // 更新角色-音色信息
         $existed_role_info = DB::table('mp_book_version')->where('bid', $bid)->where('id', $version_id)->value('role_info');
         $existed_role_info = json_decode($existed_role_info, true);
@@ -117,6 +171,10 @@ class DeepSeekService
 
         // 构造生成音频的json
         $words = json_decode($generate_json, true);
+
+        // 最终合成前的参数组
+        $mp_chapter_paragraph_audios = [];
+        $sequence = 1;
         foreach($words as &$word) {
             if (!isset($word['text']) || !isset($word['emotion']) || !isset($word['voice_type']) || !isset($word['voice_name']) || !isset($word['speed_ratio']) || !isset($word['loudness_ratio']) || !isset($word['emotion_scale'])) Utils::throwError('20003:参数格式有误');
             if (!($word['text']) || !($word['voice_type']) || !($word['voice_name']) || !($word['speed_ratio']) || !($word['loudness_ratio']) || !($word['emotion_scale'])) Utils::throwError('20003:参数不得为空');
@@ -134,12 +192,32 @@ class DeepSeekService
                     'timbre_name' => $word['voice_name'],
                 ];
             }
+            $word['paragraph_audio_url'] = '';
+
+            // 判断生成参数是否相同,相同则直接使用已生成的音频
+            $paragraph = isset($paragraph_list[$sequence]) ? $paragraph_list[$sequence] : [];
+            // 如果音频存在并且参数都未改变则使用已生成的音频
+            if (getProp($paragraph, 'paragraph_audio_url')) {
+                if (getProp($paragraph, 'role') == getProp($word, 'role') && getProp($paragraph, 'text') == getProp($word, 'text') && 
+                    getProp($paragraph, 'emotion_type') == getProp($word, 'emotion_type') && getProp($paragraph, 'voice_type') == getProp($word, 'voice_type') && 
+                    getProp($paragraph, 'speed_ratio') == getProp($word, 'speed_ratio') && getProp($paragraph, 'loudness_ratio') == getProp($word, 'loudness_ratio') &&
+                    getProp($paragraph, 'emotion_scale') == getProp($word, 'emotion_scale'))
+                {
+                        $word['paragraph_audio_url'] = getProp($paragraph, 'paragraph_audio_url');
+                }
+            }
 
-            // $word['voice_name'] = $role_timbre[$role]['timbre_name'];
-            // $word['voice_type'] = $role_timbre[$role]['timbre_type'];
-            // $word['speed_ratio'] = mt_rand(9,11)/10;
-            // $word['loudness_ratio'] = mt_rand(5,12)/10;
-            // $word['emotion_scale'] = mt_rand(1,5);
+            // 组装章节分句音频数据
+            $tmp = $word;
+            $tmp['bid'] = $bid;
+            $tmp['version_id'] = $version_id;
+            $tmp['cid'] = $cid;
+            $tmp['sequence'] = $sequence;
+            $tmp['created_at'] = date('Y-m-d H:i:s');
+            $tmp['updated_at'] = date('Y-m-d H:i:s');
+            $mp_chapter_paragraph_audios[] = $tmp;
+
+            $sequence++;
         }
         $generate_json = json_encode($words, 256);
 
@@ -183,6 +261,13 @@ class DeepSeekService
                 Utils::throwError('20003:创建任务失败');
             }
 
+            // 删除章节分句音频数据并重新插入
+            DB::table('mp_chapter_paragraph_audios')->where('bid', $bid)->where('version_id', $version_id)->where('cid', $cid)->delete();
+            $boolen3 = DB::table('mp_chapter_paragraph_audios')->insert($mp_chapter_paragraph_audios);
+            if (!$boolen3) {
+                DB::rollBack();
+                Utils::throwError('20003:更新章节分句音频失败');
+            }
         } catch (\Exception $e) {
             DB::rollBack();
             Utils::throwError('20003:'.$e->getMessage());

+ 1 - 0
routes/api.php

@@ -54,6 +54,7 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
         Route::get('timbreList', [DeepSeekController::class, 'timbreList']);
         Route::post('addGenerateTask', [DeepSeekController::class, 'addGenerateTask']);
         Route::get('setStsToken', [DeepSeekController::class, 'setStsToken']);
+        Route::post(('saveParagraphAudio'), [DeepSeekController::class, 'saveParagraphAudio']);
     });
     
 });