|
|
@@ -2794,11 +2794,13 @@ class AnimeService
|
|
|
|
|
|
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');
|
|
|
+ $query = DB::table('mp_anime_records')->where('act_id', $act_id)->select('role', 'content', 'act_id', 'image_url', 'video_url', 'reference_images', 'created_at');
|
|
|
|
|
|
$chat = $query->orderBy('id')->get()->map(function ($value) {
|
|
|
$value = (array)$value;
|
|
|
$value['created_at'] = transDate($value['created_at']);
|
|
|
+ if ($value['reference_images']) $value['reference_images'] = json_decode($value['reference_images'], 256);
|
|
|
+ else $value['reference_images'] = [];
|
|
|
return $value;
|
|
|
})->toArray();
|
|
|
|
|
|
@@ -2825,7 +2827,86 @@ class AnimeService
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return compact('chat', 'url');
|
|
|
+ // 获取资产库
|
|
|
+ $products = [];
|
|
|
+
|
|
|
+ // 通过act_id查询片段信息获取episode_id
|
|
|
+ $segment = DB::table('mp_episode_segments')->where('id', $act_id)->first();
|
|
|
+ if ($segment) {
|
|
|
+ $episode_id = getProp($segment, 'episode_id');
|
|
|
+
|
|
|
+ // 查询剧集信息获取roles、scenes和extra_products
|
|
|
+ $episode = DB::table('mp_anime_episodes')->where('id', $episode_id)->first();
|
|
|
+ if ($episode) {
|
|
|
+ $roles = json_decode(getProp($episode, 'roles', '[]'), true) ?: [];
|
|
|
+ $scenes = json_decode(getProp($episode, 'scenes', '[]'), true) ?: [];
|
|
|
+ $extra_products = json_decode(getProp($episode, 'extra_products', '[]'), true) ?: [];
|
|
|
+
|
|
|
+ // 先合并roles和scenes
|
|
|
+ // 处理角色数组
|
|
|
+ foreach ($roles as $role) {
|
|
|
+ $product = $role;
|
|
|
+ // 将role字段重命名为product_name
|
|
|
+ if (isset($product['role'])) {
|
|
|
+ $product['product_name'] = $product['role'];
|
|
|
+ unset($product['role']);
|
|
|
+ }
|
|
|
+ $product['product'] = 1; // 标记类型为角色
|
|
|
+ $products[$product['product_name']] = $product; // 使用product_name作为key便于后续覆盖
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理场景数组
|
|
|
+ foreach ($scenes as $scene) {
|
|
|
+ $product = $scene;
|
|
|
+ // 将scene字段重命名为product_name
|
|
|
+ if (isset($product['scene'])) {
|
|
|
+ $product['product_name'] = $product['scene'];
|
|
|
+ unset($product['scene']);
|
|
|
+ }
|
|
|
+ $product['product'] = 2; // 标记类型为场景
|
|
|
+ $products[$product['product_name']] = $product; // 使用product_name作为key便于后续覆盖
|
|
|
+ }
|
|
|
+
|
|
|
+ // extra_products优先级更高,直接覆盖同名的roles和scenes
|
|
|
+ foreach ($extra_products as $extra_product) {
|
|
|
+ $product_name = getProp($extra_product, 'product_name');
|
|
|
+ if ($product_name) {
|
|
|
+ $products[$product_name] = $extra_product; // 覆盖同名数据
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重新索引数组(去除key)
|
|
|
+ $products = array_values($products);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取执行中的任务
|
|
|
+ $tasks = DB::table('mp_generate_video_tasks')->where('alias_act_id', $act_id)->whereNotIn('status', ['success', 'failed'])->select('id as task_id', 'alias_act_id', 'prompt', 'ref_image_url', 'status')->orderBy('id')->get()->map(function($value) {
|
|
|
+ $value = (array)$value;
|
|
|
+ if ($value['ref_image_url']) $value['ref_image_url'] = json_decode($value['ref_image_url'], true);
|
|
|
+ else $value['ref_image_url'] = [];
|
|
|
+ $value['status'] = $value['status'] == 'pending' ? '视频待生成' : '视频生成中';
|
|
|
+
|
|
|
+ // 处理prompt:删除人物音色部分,保留【镜头】开始的内容,并去掉<图片X>标记
|
|
|
+ if (!empty($value['prompt'])) {
|
|
|
+ $prompt = $value['prompt'];
|
|
|
+
|
|
|
+ // 查找第一个【镜头】的位置
|
|
|
+ if (preg_match('/【镜头\d+】/u', $prompt, $matches, PREG_OFFSET_CAPTURE)) {
|
|
|
+ // 从【镜头】开始截取
|
|
|
+ $prompt = substr($prompt, $matches[0][1]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 去除所有<图片X>格式的标记(X可以是任意数字)
|
|
|
+ $prompt = preg_replace('/<图片\d+>/u', '', $prompt);
|
|
|
+
|
|
|
+ $value['prompt'] = $prompt;
|
|
|
+ }
|
|
|
+
|
|
|
+ return $value;
|
|
|
+ })->toArray();
|
|
|
+
|
|
|
+ return compact('chat', 'url', 'products', 'tasks');
|
|
|
}
|
|
|
|
|
|
public function applyAudioData($data) {
|
|
|
@@ -6419,10 +6500,11 @@ class AnimeService
|
|
|
// 重新查询更新后的片段数据
|
|
|
$acts = DB::table('mp_episode_segments')->where('episode_id', $episode_id)->orderBy('act_number')->get();
|
|
|
|
|
|
- // 合并角色和场景作为products,统一字段名为product_name
|
|
|
+ // 合并角色、场景和extra_products作为products,统一字段名为product_name
|
|
|
+ // extra_products优先级更高,会覆盖同名的roles和scenes
|
|
|
$products = [];
|
|
|
|
|
|
- // 处理角色数组
|
|
|
+ // 先处理角色数组
|
|
|
foreach ($roles as $role) {
|
|
|
$product = $role;
|
|
|
// 将role字段重命名为product_name
|
|
|
@@ -6431,7 +6513,7 @@ class AnimeService
|
|
|
unset($product['role']);
|
|
|
}
|
|
|
$product['product'] = 1; // 标记类型为角色
|
|
|
- $products[] = $product;
|
|
|
+ $products[$product['product_name']] = $product; // 使用product_name作为key便于后续覆盖
|
|
|
}
|
|
|
|
|
|
// 处理场景数组
|
|
|
@@ -6443,9 +6525,21 @@ class AnimeService
|
|
|
unset($product['scene']);
|
|
|
}
|
|
|
$product['product'] = 2; // 标记类型为场景
|
|
|
- $products[] = $product;
|
|
|
+ $products[$product['product_name']] = $product; // 使用product_name作为key便于后续覆盖
|
|
|
+ }
|
|
|
+
|
|
|
+ // extra_products优先级更高,直接覆盖同名的roles和scenes
|
|
|
+ $extra_products = json_decode(getProp($episode, 'extra_products', '[]'), true) ?: [];
|
|
|
+ foreach ($extra_products as $extra_product) {
|
|
|
+ $product_name = getProp($extra_product, 'product_name');
|
|
|
+ if ($product_name) {
|
|
|
+ $products[$product_name] = $extra_product; // 覆盖同名数据
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ // 重新索引数组(去除key)
|
|
|
+ $products = array_values($products);
|
|
|
+
|
|
|
// 构建返回的acts数组
|
|
|
$return_acts = [];
|
|
|
foreach ($acts as $act) {
|
|
|
@@ -6464,6 +6558,9 @@ class AnimeService
|
|
|
return [
|
|
|
'anime_id' => getProp($episode, 'anime_id'),
|
|
|
'episode_id' => $episode_id,
|
|
|
+ 'title' => getProp($episode, 'title'),
|
|
|
+ 'episode_number' => getProp($episode, 'episode_number'),
|
|
|
+ 'is_generated' => getProp($episode, 'is_generated'),
|
|
|
'products' => $products,
|
|
|
'acts' => $return_acts
|
|
|
];
|