Ver Fonte

新增角色库管理

lh há 1 mês atrás
pai
commit
01c6b56b3d

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

@@ -1974,6 +1974,41 @@ class AnimeController extends BaseController
         return $this->success($result);
     }
 
+    // 角色库
+    public function globalRoles(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->globalRoles($data);
+        return $this->success($result);
+    }
+
+    // 新建角色
+    public function createRole(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->createRole($data);
+        return $this->success($result);
+    }
+
+    // 编辑角色
+    public function editRole(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->editRole($data);
+        return $this->success(['success' => $result ? 1 : 0]);
+    }
+
+    // 删除角色
+    public function deleteRole(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->deleteRole($data);
+        return $this->success(['success' => $result ? 1 : 0]);
+    }
+
+    // 生成三视图
+    public function generateThreeView(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->generateThreeView($data);
+        return $this->success($result);
+    }
+
     private function handleVideoTimePointEnd() {
         // 处理音频时长,循环查询dub_video_task_queue列表中的任务
         $queueLength = Redis::llen('dub_video_task_queue');

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

@@ -4317,5 +4317,253 @@ class AnimeService
             Utils::throwError('20003:' . $e->getMessage());
         }
     }
+
+    public function globalRoles($data) {
+        $role = getProp($data, 'role');
+        $query = DB::table('mp_roles')->where('is_deleted', 0)->select('id', 'role', 'url', 'pic_prompt', 'three_view_image_url', 'created_at');
+        if ($role) $query->where('role', 'like', "%{$role}%");
+        $result = $query->orderBy('id', 'desc')->get()->map(function($value) {
+            $value = (array)$value;
+            $value['created_at'] = transDate($value['created_at'], 'Y-m-d');
+            return $value;
+        })->toArray();
+
+        return $result;
+    }
+
+    public function createRole($data) {
+        $uid = Site::getUid();
+        $role = trim(getProp($data, 'role'));
+        if (!$role) Utils::throwError('20003:角色名不能为空');
+        $url = trim(getProp($data, 'url'));
+        if (!$url) Utils::throwError('20003:图片地址不能为空');
+        
+        // 检查是否是正确的图片格式
+        $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
+        $urlPath = parse_url($url, PHP_URL_PATH);
+        $extension = strtolower(pathinfo($urlPath, PATHINFO_EXTENSION));
+        
+        if (!in_array($extension, $allowedExtensions)) {
+            Utils::throwError('20003:图片格式不正确,仅支持 jpg、jpeg、png、gif、webp、bmp 格式');
+        }
+        $pic_prompt = trim(getProp($data, 'pic_prompt'));
+        if (!$pic_prompt) Utils::throwError('20003:角色提示词不能为空');
+
+        $id = DB::table('mp_roles')->insertGetId([
+            'user_id'       => $uid,
+            'role'          => $role,
+            'url'           => $url,
+            'pic_prompt'     => $pic_prompt,
+            'created_at'    => date('Y-m-d H:i:s'),
+            'updated_at'    => date('Y-m-d H:i:s')
+        ]);
+
+        if (!$id) Utils::throwError('20003:创建角色失败');
+        return [
+            'id'            => $id,
+            'role'          => $role,
+            'url'           => $url,
+            'pic_prompt'    => $pic_prompt
+        ];
+    }
+
+    public function editRole($data) {
+        $uid = Site::getUid();
+        $id = getProp($data, 'id');
+        if (!$id) Utils::throwError('20003:角色ID不能为空');
+        
+        // 检查角色是否存在且属于当前用户
+        $role = DB::table('mp_roles')
+        // ->where('user_id', $uid)
+        ->where('id', $id)->first();
+        if (!$role) Utils::throwError('20003:角色不存在或无权限操作');
+        
+        $updateData = [];
+        
+        // 角色名
+        $roleName = trim(getProp($data, 'role'));
+        if ($roleName) {
+            $updateData['role'] = $roleName;
+        }
+        
+        // 图片地址
+        $url = trim(getProp($data, 'url'));
+        if ($url) {
+            // 检查是否是正确的图片格式
+            $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
+            $urlPath = parse_url($url, PHP_URL_PATH);
+            $extension = strtolower(pathinfo($urlPath, PATHINFO_EXTENSION));
+            
+            if (!in_array($extension, $allowedExtensions)) {
+                Utils::throwError('20003:图片格式不正确,仅支持 jpg、jpeg、png、gif、webp、bmp 格式');
+            }
+            $updateData['url'] = $url;
+        }
+        
+        // 角色提示词
+        $pic_prompt = trim(getProp($data, 'pic_prompt'));
+        if ($pic_prompt) {
+            $updateData['pic_prompt'] = $pic_prompt;
+        }
+        
+        if (empty($updateData)) {
+            Utils::throwError('20003:没有需要更新的数据');
+        }
+        
+        $updateData['updated_at'] = date('Y-m-d H:i:s');
+        
+        return DB::table('mp_roles')
+        // ->where('user_id', $uid)
+        ->where('id', $id)->update($updateData);
+    }
+
+    public function deleteRole($data) {
+        $uid = Site::getUid();
+        $id = getProp($data, 'id');
+        if (!$id) Utils::throwError('20003:角色ID不能为空');
+        
+        // 检查角色是否存在且属于当前用户
+        $role = DB::table('mp_roles')
+        // ->where('user_id', $uid)
+        ->where('id', $id)->first();
+        if (!$role) Utils::throwError('20003:角色不存在或无权限操作');
+        
+        return DB::table('mp_roles')
+        // ->where('user_id', $uid)
+        ->where('id', $id)->delete();
+    }
+
+    public function generateThreeView($data) {
+        $uid = Site::getUid();
+        $id = getProp($data, 'id');
+        if (!$id) Utils::throwError('20003:角色ID不能为空');
+        
+        // 检查角色是否存在且属于当前用户
+        $role = DB::table('mp_roles')
+        // ->where('user_id', $uid)
+        ->where('id', $id)->first();
+        if (!$role) Utils::throwError('20003:角色不存在或无权限操作');
+        
+        $prompt = trim(getProp($data, 'prompt', '基于参考图生成主体的标准正面、侧面、后面三视图,主体完整。在最左侧添加主体正视图的特写,主体清晰完整。背景修改成纯白色,整体保持与参考图一致的美术风格和色彩搭配。画面无说明文字'));
+        $ref_img_url = trim(getProp($data, 'ref_img_url'));
+        if (!$ref_img_url) {
+            // 如果没有传入参考图,使用角色表中的图片
+            $ref_img_url = $role->url ?? '';
+            if (!$ref_img_url) {
+                Utils::throwError('20003:参考图不能为空');
+            }
+        }
+        
+        // 检查参考图是否是正确的图片格式
+        $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
+        $urlPath = parse_url($ref_img_url, PHP_URL_PATH);
+        $extension = strtolower(pathinfo($urlPath, PATHINFO_EXTENSION));
+        
+        if (!in_array($extension, $allowedExtensions)) {
+            Utils::throwError('20003:参考图格式不正确,仅支持 jpg、jpeg、png、gif、webp、bmp 格式');
+        }
+        
+        // 处理图片模型
+        $model = getProp($data, 'model');
+        if (!$model) {
+            // 使用默认模型
+            $model = 'doubao-seedream-5-0-lite-260128';
+        }
+        // 验证模型是否在可用模型表中
+        if (!DB::table('mp_image_models')->where('model', $model)->where('is_enabled', 1)->exists()) {
+            Utils::throwError('20003:该模型已不可用,请更换!');
+        }
+        
+        try {
+            // 创建图片生成任务
+            $params = [
+                'prompt' => $prompt,
+                'model' => $model,
+                'ref_img_urls' => [$ref_img_url],
+                'width' => 1600,
+                'height' => 2848
+            ];
+            
+            $task = $this->aiImageGenerationService->createImageGenerationTask($params);
+            $task_id = $task->id;
+            
+            if (!$task_id) {
+                Utils::throwError('20003:创建图片生成任务失败');
+            }
+            
+            // 检查任务模型类型
+            $isVolcModel = in_array($model, \App\Consts\BaseConst::VOLC_PIC_MODELS);
+            $isGptModel = in_array($model, \App\Consts\BaseConst::GPT_IMAGE2_MODELS);
+            $isSyncModel = $isVolcModel || $isGptModel;
+
+            // 轮询获取结果(5分钟超时,每3秒查询一次)
+            $start_time = time();
+            $timeout = 300; // 5分钟
+            $img_url = '';
+            
+            while (time() - $start_time < $timeout) {
+                sleep(3);
+
+                // 火山API和GPT-Image2 API是同步返回结果的,直接检查任务状态
+                if ($isSyncModel) {
+                    // 刷新任务状态
+                    $task = MpGeneratePicTask::where('id', $task_id)->first();
+                    
+                    if ($task->status === 'success' && $task->result_url) {
+                        $result_urls = is_array($task->result_url) ? $task->result_url : json_decode($task->result_url, true);
+                        $img_url = is_array($result_urls) ? $result_urls[0] : $task->result_url;
+                        break;
+                    } elseif ($task->status === 'failed') {
+                        Utils::throwError('20003:三视图生成失败,' . ($task->error_message ?? '未知错误'));
+                    }
+                } else {
+                    $task = MpGeneratePicTask::where('id', $task_id)->first();
+                    $statusInfo = $this->aiImageGenerationService->queryTaskStatus($task);
+                    
+                    if ($statusInfo['status'] === 'success') {
+                        $task->updateStatus('success', [
+                            'result_url' => $statusInfo['result_url'],
+                            'result_json' => $statusInfo['result_json'] ?? []
+                        ]);
+                        
+                        $img_url = $statusInfo['result_url'][0];
+                        break;
+                    } elseif ($statusInfo['status'] === 'failed') {
+                        $task->updateStatus('failed', [
+                            'error_message' => $statusInfo['error_message'],
+                            'result_json' => $statusInfo['result_json'] ?? []
+                        ]);
+                        dLog('anime')->error('三视图生成失败', [
+                            'error' => $statusInfo['error_message'] ?? '未知错误'
+                        ]);
+                        Utils::throwError('20003:三视图生成失败,' . ($statusInfo['error_message'] ?? '未知错误'));
+                    }
+                }
+            }
+            
+            if (empty($img_url)) {
+                Utils::throwError('20003:三视图生成超时,请稍后重试');
+            }
+            
+            // 保存三视图到 mp_roles 表
+            DB::table('mp_roles')
+                ->where('id', $id)
+                // ->where('user_id', $uid)
+                ->update([
+                    'three_view_image_url' => $img_url,
+                    'updated_at' => date('Y-m-d H:i:s')
+                ]);
+            
+            return ['three_view_image_url' => $img_url];
+            
+        } catch (\Exception $e) {
+            dLog('anime')->error('生成三视图失败', [
+                'error' => $e->getMessage()
+            ]);
+            logDB('anime', 'error', '生成三视图失败', ['error' => $e->getMessage()]);
+            
+            Utils::throwError('20003:' . $e->getMessage());
+        }
+    }
 }
 

+ 8 - 0
routes/api.php

@@ -193,6 +193,14 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
         
         // 导出全部分镜
         Route::get('exportEpisodeImages', [AnimeController::class, 'exportEpisodeImages']);
+
+        Route::get('globalRoles', [AnimeController::class, 'globalRoles']);     // 角色库
+        Route::post('createRole', [AnimeController::class, 'createRole']);      // 创建角色
+        Route::post('editRole', [AnimeController::class, 'editRole']);          // 编辑角色
+        Route::get('deleteRole', [AnimeController::class, 'deleteRole']);       // 删除角色
+        // 生成三视图(基于参考图生成主体的标准正面、侧面、后面三视图,主体完整。在最左侧添加主体正视图的特写,主体清晰完整。背景修改成纯白色,整体保持与参考图一致的美术风格和色彩搭配。画面无说明文字)
+        Route::post('generateThreeView', [AnimeController::class, 'generateThreeView']);
+
     });
     
 });