|
|
@@ -8652,6 +8652,231 @@ Q版卡通风格,头大身小,造型圆润可爱,线条简单,色彩明
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * chatForAce的非流式版本 - 用于队列任务
|
|
|
+ * 与chatForAce逻辑完全一致,但不使用流式输出
|
|
|
+ *
|
|
|
+ * @param array $data 请求数据
|
|
|
+ * @return array 生成结果
|
|
|
+ */
|
|
|
+ public function chatForAceNonStream($data) {
|
|
|
+ $allChunks = [];
|
|
|
+ $finalResult = null;
|
|
|
+
|
|
|
+ // 调用流式方法并收集所有数据
|
|
|
+ foreach ($this->chatForAce($data) as $chunk) {
|
|
|
+ $allChunks[] = $chunk;
|
|
|
+
|
|
|
+ // 保存最终结果
|
|
|
+ if (isset($chunk['type']) && $chunk['type'] === 'done') {
|
|
|
+ $finalResult = $chunk;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 返回最终结果
|
|
|
+ if ($finalResult) {
|
|
|
+ return $finalResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没有done类型的数据,返回最后一个chunk
|
|
|
+ return end($allChunks) ?: ['error' => '生成失败'];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量生成多个分集
|
|
|
+ *
|
|
|
+ * @param array $data 请求数据
|
|
|
+ * @return array 任务信息
|
|
|
+ */
|
|
|
+ public function batchGenerateEpisodes($data) {
|
|
|
+ $uid = Site::getUid();
|
|
|
+ $cpid = Site::getCpid();
|
|
|
+ $anime_id = getProp($data, 'anime_id');
|
|
|
+ $generate_episode_number = (int)getProp($data, 'generate_episode_number', 1);
|
|
|
+
|
|
|
+ if (!$anime_id) {
|
|
|
+ Utils::throwError('20003:anime_id参数缺失');
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($generate_episode_number < 1) {
|
|
|
+ Utils::throwError('20003:生成集数必须大于0');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取动漫信息
|
|
|
+ $anime = DB::table('mp_animes')->where('id', $anime_id)->first();
|
|
|
+ if (!$anime) {
|
|
|
+ Utils::throwError('20003:该剧集不存在');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否是多剧集模式
|
|
|
+ if ((int)getProp($anime, 'is_multi') !== 1) {
|
|
|
+ Utils::throwError('20003:单剧集不支持批量生成');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取当前已生成的最大集数
|
|
|
+ $currentMaxEpisode = DB::table('mp_anime_episodes')
|
|
|
+ ->where('anime_id', $anime_id)
|
|
|
+ ->where('is_default', 1)
|
|
|
+ ->max('episode_number');
|
|
|
+
|
|
|
+ $currentMaxEpisode = $currentMaxEpisode ?: 0;
|
|
|
+
|
|
|
+ // 确定起始集数
|
|
|
+ $startEpisodeNumber = $currentMaxEpisode + 1;
|
|
|
+
|
|
|
+ // 如果用户指定了起始集数(通过episode_number参数)
|
|
|
+ if (isset($data['episode_number'])) {
|
|
|
+ $userStartEpisode = (int)getProp($data, 'episode_number');
|
|
|
+ if ($userStartEpisode > $currentMaxEpisode) {
|
|
|
+ $startEpisodeNumber = $userStartEpisode;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算结束集数
|
|
|
+ $endEpisodeNumber = $startEpisodeNumber + $generate_episode_number - 1;
|
|
|
+
|
|
|
+ // 检查是否超过总集数限制
|
|
|
+ $end_episode_sequence = getProp($anime, 'end_episode_sequence');
|
|
|
+ if ($end_episode_sequence && $endEpisodeNumber > $end_episode_sequence) {
|
|
|
+ Utils::throwError("20003:总集数只有{$end_episode_sequence}集,无法生成到第{$endEpisodeNumber}集");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否已有进行中的任务
|
|
|
+ $existingTask = DB::table('mp_batch_episode_generation_tasks')
|
|
|
+ ->where('anime_id', $anime_id)
|
|
|
+ ->whereIn('status', ['pending', 'processing'])
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ if ($existingTask) {
|
|
|
+ Utils::throwError('20003:该剧集已有批量生成任务正在进行中,请等待完成后再试');
|
|
|
+ }
|
|
|
+
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+
|
|
|
+ // 准备任务数据
|
|
|
+ $taskData = [
|
|
|
+ 'anime_id' => $anime_id,
|
|
|
+ 'uid' => $uid,
|
|
|
+ 'cpid' => $cpid,
|
|
|
+ 'start_episode' => $startEpisodeNumber,
|
|
|
+ 'end_episode' => $endEpisodeNumber,
|
|
|
+ 'total_episodes' => $generate_episode_number,
|
|
|
+ 'current_episode' => 0,
|
|
|
+ 'completed_episodes' => 0,
|
|
|
+ 'status' => 'pending',
|
|
|
+ 'request_data' => json_encode($data, JSON_UNESCAPED_UNICODE),
|
|
|
+ 'created_at' => $now,
|
|
|
+ 'updated_at' => $now
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 创建批量生成任务记录
|
|
|
+ $taskId = DB::table('mp_batch_episode_generation_tasks')->insertGetId($taskData);
|
|
|
+
|
|
|
+ if (!$taskId) {
|
|
|
+ Utils::throwError('20003:创建批量生成任务失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新任务状态为processing
|
|
|
+ DB::table('mp_batch_episode_generation_tasks')
|
|
|
+ ->where('id', $taskId)
|
|
|
+ ->update([
|
|
|
+ 'status' => 'processing',
|
|
|
+ 'updated_at' => $now
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 分发到队列
|
|
|
+ \App\Jobs\ProcessBatchEpisodeGenerationJob::dispatch(
|
|
|
+ $taskId,
|
|
|
+ $anime_id,
|
|
|
+ $startEpisodeNumber,
|
|
|
+ $generate_episode_number,
|
|
|
+ $data,
|
|
|
+ $uid,
|
|
|
+ $cpid
|
|
|
+ );
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'task_id' => $taskId,
|
|
|
+ 'anime_id' => $anime_id,
|
|
|
+ 'start_episode' => $startEpisodeNumber,
|
|
|
+ 'end_episode' => $endEpisodeNumber,
|
|
|
+ 'total_episodes' => $generate_episode_number,
|
|
|
+ 'status' => 'processing',
|
|
|
+ 'message' => "已创建批量生成任务,将生成第{$startEpisodeNumber}集到第{$endEpisodeNumber}集,共{$generate_episode_number}集"
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取批量生成任务状态
|
|
|
+ *
|
|
|
+ * @param array $data 请求数据
|
|
|
+ * @return array 任务状态信息
|
|
|
+ */
|
|
|
+ public function getBatchGenerationTaskStatus($data) {
|
|
|
+ $task_id = getProp($data, 'task_id');
|
|
|
+ $anime_id = getProp($data, 'anime_id');
|
|
|
+
|
|
|
+ if (!$task_id && !$anime_id) {
|
|
|
+ Utils::throwError('20003:task_id或anime_id参数缺失');
|
|
|
+ }
|
|
|
+
|
|
|
+ $query = DB::table('mp_batch_episode_generation_tasks');
|
|
|
+
|
|
|
+ if ($task_id) {
|
|
|
+ $query->where('id', $task_id);
|
|
|
+ } else {
|
|
|
+ // 获取该anime最新的任务
|
|
|
+ $query->where('anime_id', $anime_id)
|
|
|
+ ->orderByDesc('id')
|
|
|
+ ->limit(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ $task = $query->first();
|
|
|
+
|
|
|
+ if (!$task) {
|
|
|
+ Utils::throwError('20003:任务不存在');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取任务详情
|
|
|
+ $details = DB::table('mp_batch_episode_generation_details')
|
|
|
+ ->where('task_id', $task->id)
|
|
|
+ ->orderBy('episode_number')
|
|
|
+ ->get()
|
|
|
+ ->map(function($item) {
|
|
|
+ return [
|
|
|
+ 'episode_number' => $item->episode_number,
|
|
|
+ 'status' => $item->status,
|
|
|
+ 'error_message' => $item->error_message,
|
|
|
+ 'created_at' => $item->created_at,
|
|
|
+ 'updated_at' => $item->updated_at
|
|
|
+ ];
|
|
|
+ })
|
|
|
+ ->toArray();
|
|
|
+
|
|
|
+ // 计算进度百分比
|
|
|
+ $progress = 0;
|
|
|
+ if ($task->total_episodes > 0) {
|
|
|
+ $progress = round(($task->completed_episodes / $task->total_episodes) * 100, 2);
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'task_id' => $task->id,
|
|
|
+ 'anime_id' => $task->anime_id,
|
|
|
+ 'start_episode' => $task->start_episode,
|
|
|
+ 'end_episode' => $task->end_episode,
|
|
|
+ 'total_episodes' => $task->total_episodes,
|
|
|
+ 'current_episode' => $task->current_episode,
|
|
|
+ 'completed_episodes' => $task->completed_episodes,
|
|
|
+ 'progress' => $progress,
|
|
|
+ 'status' => $task->status,
|
|
|
+ 'error_message' => $task->error_message,
|
|
|
+ 'details' => $details,
|
|
|
+ 'created_at' => $task->created_at,
|
|
|
+ 'updated_at' => $task->updated_at,
|
|
|
+ 'completed_at' => $task->completed_at
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 智能匹配并替换主体和场景名称
|
|
|
* 如果生成的主体或场景名称是强制设定名称的子串,则自动替换为完整名称
|
|
|
*
|