deepseekService = $deepseekService; } /** * 可选供应商 * * @param Request $request * @return mixed */ public function chatWithReasoner(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); $result = $this->deepseekService->chatWithReasoner($data); return $this->success($result); } /** * 音色列表 * * @param Request $request * @return mixed */ public function timbreList(Request $request) { $data = $request->all(); $result = $this->deepseekService->timbreList($data); return $this->success($result); } // 重置段落音频状态 public function resetParagraphAudio(Request $request) { $data = $request->all(); $result = $this->deepseekService->resetParagraphAudio($data); return $this->success(['success'=>$result ? 1 : 0]); } // 保存段落音频 public function saveParagraphAudio(Request $request) { $data = $request->all(); $result = $this->deepseekService->saveParagraphAudio($data); return $this->success(['success'=>$result ? 1 : 0]); } // 保存段落音频 public function insertAudioEffect(Request $request) { $data = $request->all(); $result = $this->deepseekService->insertAudioEffect($data); return $this->success(['success'=>$result ? 1 : 0]); } // 保存段落音频 public function insertBgm(Request $request) { $data = $request->all(); $result = $this->deepseekService->insertBgm($data); return $this->success(['success'=>$result ? 1 : 0]); } /** * 获取段落视频 */ public function paragraphAudios(Request $request) { $data = $request->all(); $result = $this->deepseekService->getParagraphAudios($data); return $this->success($result); } /** * 新增合成任务 * * @param Request $request * @return mixed */ public function addGenerateTask(Request $request) { $data = $request->all(); $result = $this->deepseekService->addGenerateTask($data); return $this->success(['success'=>$result ? 1 : 0]); } // 获取火山临时token public function setStsToken(Request $request) { $data = $request->all(); $result = $this->deepseekService->setStsToken($data); return $this->success($result); } public function sseLink(Request $request) { $data = $request->all(); $bid = getProp($data, 'bid'); $version_id = getProp($data, 'version_id'); $cid = getProp($data, 'cid'); // 禁用输出缓冲 while (ob_get_level()) ob_end_clean(); // 设置SSE所需的HTTP头 header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); header('X-Accel-Buffering: no'); // 防止Nginx缓冲 // 允许跨域请求(根据需求设置) header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Credentials: true'); // 设置脚本执行时间无限 set_time_limit(0); // 手动刷新输出缓冲区 ob_implicit_flush(true); if(ob_get_level()>0) ob_flush(); flush(); // 客户端ID(用于多用户区分) $clientId = $_SERVER['REMOTE_ADDR'] . ':' . $_SERVER['REMOTE_PORT']; $lastEventId = isset($_SERVER['HTTP_LAST_EVENT_ID']) ? intval($_SERVER['HTTP_LAST_EVENT_ID']) : 0; // dd($clientId, $lastEventId); // 发送初始欢迎消息 $this->sendEvent([ // 'message' => "欢迎使用SSE服务! 你的客户端ID: {$clientId}", // 'type' => 'info', // 'timestamp' => date('H:i:s') 'code' => 0, 'msg' => "已连接! 你的客户端ID: {$clientId}", 'data' => [], ]); if (!$bid && !$version_id && !$cid) { $this->sendEvent([ // 'message' => '参数异常', // 'type' => 'error', // 'timestamp' => date('H:i:s') 'code' => -1, 'msg' => "参数异常", 'data' => [], ]); } $redis_key = "select-{$bid}-{$version_id}-{$cid}"; // 主循环 - 定期发送数据 while (true) { // 检查客户端是否断开连接 if (connection_aborted()) { exit(); } // 判断是否有待更新数据,有则查询 $ids = Redis::smembers($redis_key); if (count($ids) > 0) { $count = DB::table('mp_chapter_paragraph_audios')->whereIn('id', $ids)->where(function($query) { return $query->where('generate_status', '!=', '制作中')->orWhere('error_msg', '!=', ''); })->count('id'); // 如果有更新数据,则发送消息 if ($count > 0) { // 查询更新后的信息 $paragraph_urls = DB::table('mp_chapter_paragraph_audios')->where('bid', $bid)->where('version_id', $version_id) ->where('cid', $cid)->where(function($query) { return $query->where('generate_status', '!=', '制作中')->orWhere('error_msg', '!=', ''); })->select('id', 'sequence', 'generate_status', 'paragraph_audio_url', 'error_msg') ->get()->map(function ($value) { return (array)$value; })->toArray(); $rem_ids = []; foreach ($paragraph_urls as $item) { $rem_ids[] = getProp($item, 'id'); } // 发送消息 $this->sendEvent([ 'code' => 0, 'msg' => "", 'data' => $paragraph_urls, // 'message' => '数据更新', // 'type' => 'update', // 'timestamp' => date('H:i:s') ]); // 删除有数据的id Redis::srem($redis_key, $rem_ids); } } // 等待1秒 sleep(1); } } private function sendEvent($data, $event = null, $id = null) { // // 事件ID // if ($id !== null) { // echo "id: {$id}\n"; // } // 事件类型 if ($event !== null) { echo "event: {$event}\n"; } // 数据部分(JSON格式) echo "data: " . json_encode($data) . "\n\n"; // 立即发送数据 if(ob_get_level()>0) ob_flush(); flush(); } public function emotionGroups(Request $request) { $data = $request->all(); $result = $this->deepseekService->emotionGroups($data); return $this->success($result); } /** * 剧本列表 * * @param Request $request * @return mixed */ public function scriptList(Request $request) { $data = $request->all(); $result = $this->deepseekService->scriptList($data); return $this->success($result, [new DeepSeekTransformer(), 'newBuildScriptList']); } public function scripts(Request $request) { $data = $request->all(); $result = $this->deepseekService->scripts($data); return $this->success($result); } // 剧本详情 public function scriptInfo(Request $request) { $data = $request->all(); $result = $this->deepseekService->scriptInfo($data); return $this->success($result); } /** * 创建剧本 * * @param Request $request * @return mixed */ public function createScript(Request $request) { $data = $request->all(); $result = $this->deepseekService->createScript($data); return $this->success(['script_id' => $result]); } // 编辑剧本 public function editScript(Request $request) { $data = $request->all(); $result = $this->deepseekService->editScript($data); return $this->success(['success' => $result ? 1 : 0]); } // 删除剧本 public function delScript(Request $request) { $data = $request->all(); $result = $this->deepseekService->delScript($data); return $this->success(['success' => $result ? 1 : 0]); } /** * 创建分集组 * * @param Request $request * @return mixed */ public function createEpisode(Request $request) { $data = $request->all(); $result = $this->deepseekService->createEpisode($data); return $this->success(['group_id' => $result]); } // 编辑剧本 public function editEpisode(Request $request) { $data = $request->all(); $result = $this->deepseekService->editEpisode($data); return $this->success(['success' => $result ? 1 : 0]); } // 删除剧本 public function delEpisode(Request $request) { $data = $request->all(); $result = $this->deepseekService->delEpisode($data); return $this->success(['success' => $result ? 1 : 0]); } /** * 与DeepSeek对话(带文件上传) * @param Request $request * @return mixed * @throws ApiException */ public function chatWithFile(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); $result = $this->deepseekService->chatWithFile($data); return $this->success($result); } /** * 与DeepSeek对话(带文件上传 - 流式输出版本) * @param Request $request * @return \Symfony\Component\HttpFoundation\StreamedResponse * @throws ApiException */ public function chatWithFileStream(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); return response()->stream(function () use ($data) { // 禁用所有输出缓冲 if (ob_get_level()) { ob_end_clean(); } // 设置输出缓冲为关闭 ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', 'off'); // 立即刷新 if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); } try { $generator = $this->deepseekService->chatWithFileStream($data); foreach ($generator as $chunk) { // 发送 SSE 格式的数据 $jsonData = json_encode($chunk, JSON_UNESCAPED_UNICODE); echo "data: {$jsonData}\n\n"; // 强制刷新输出缓冲区 if (ob_get_level() > 0) { ob_flush(); } flush(); // 检查客户端是否断开连接 if (connection_aborted()) { break; } } // 发送结束标记 echo "data: [DONE]\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } catch (\Exception $e) { // 发送错误信息 $error = [ 'type' => 'error', 'msg' => $e->getMessage(), 'code' => $e->getCode() ]; $jsonError = json_encode($error, JSON_UNESCAPED_UNICODE); echo "data: {$jsonError}\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'X-Accel-Buffering' => 'no', // 防止 Nginx 缓冲 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Credentials' => 'true' ]); } public function generateEpisodes(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); return response()->stream(function () use ($data) { // 禁用所有输出缓冲 if (ob_get_level()) { ob_end_clean(); } // 设置输出缓冲为关闭 ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', 'off'); // 立即刷新 if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); } try { $generator = $this->deepseekService->generateEpisodes($data); foreach ($generator as $chunk) { // 发送 SSE 格式的数据 $jsonData = json_encode($chunk, JSON_UNESCAPED_UNICODE); echo "data: {$jsonData}\n\n"; // 强制刷新输出缓冲区 if (ob_get_level() > 0) { ob_flush(); } flush(); // 检查客户端是否断开连接 if (connection_aborted()) { break; } } // 发送结束标记 echo "data: [DONE]\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } catch (\Exception $e) { // 发送错误信息 $error = [ 'type' => 'error', 'msg' => $e->getMessage(), 'code' => $e->getCode() ]; $jsonError = json_encode($error, JSON_UNESCAPED_UNICODE); echo "data: {$jsonError}\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'X-Accel-Buffering' => 'no', // 防止 Nginx 缓冲 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Credentials' => 'true' ]); } public function getEpisodeContent(Request $request) { $data = $request->all(); $result = $this->deepseekService->getEpisodeContent($data); return $this->success($result); } // 保存剧本 public function saveEpisodeContent(Request $request) { $data = $request->all(); $result = $this->deepseekService->saveEpisodeContent($data); return $this->success(['success'=>$result ? 1 : 0]); } // 导出剧本 public function exportScript(Request $request) { $data = $request->all(); // 验证必要参数 if (empty($data['script_id'])) { return $this->error('20003:缺少剧本ID参数'); } // 直接调用导出服务,该方法会直接输出文件并退出 $this->deepseekService->exportScript($data); } public function getBookContent(Request $request) { $data = $request->all(); // 直接调用导出服务,该方法会直接输出文件并退出 $result = $this->deepseekService->getBookContent($data); return $this->success($result); } /** * 通用文生文(非流式版本) * @param Request $request * @return mixed */ public function newGenerateText(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); $result = $this->deepseekService->newGenerateText($data); return $this->success($result); } // 新建对话 public function addChat(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); return response()->stream(function () use ($data) { // 禁用所有输出缓冲 if (ob_get_level()) { ob_end_clean(); } // 设置输出缓冲为关闭 ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', 'off'); // 立即刷新 if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); } try { $generator = $this->deepseekService->addChat($data); foreach ($generator as $chunk) { // 发送 SSE 格式的数据 $jsonData = json_encode($chunk, JSON_UNESCAPED_UNICODE); echo "data: {$jsonData}\n\n"; // 强制刷新输出缓冲区 if (ob_get_level() > 0) { ob_flush(); } flush(); // 检查客户端是否断开连接 if (connection_aborted()) { break; } } // 发送结束标记 echo "data: [DONE]\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } catch (\Exception $e) { // 发送错误信息 $error = [ 'type' => 'error', 'msg' => $e->getMessage(), 'code' => $e->getCode() ]; $jsonError = json_encode($error, JSON_UNESCAPED_UNICODE); echo "data: {$jsonError}\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'X-Accel-Buffering' => 'no', // 防止 Nginx 缓冲 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Credentials' => 'true' ]); } // 调整大纲 public function reGenerateAnime(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); return response()->stream(function () use ($data) { // 禁用所有输出缓冲 if (ob_get_level()) { ob_end_clean(); } // 设置输出缓冲为关闭 ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', 'off'); // 立即刷新 if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); } try { $generator = $this->deepseekService->reGenerateAnime($data); foreach ($generator as $chunk) { // 发送 SSE 格式的数据 $jsonData = json_encode($chunk, JSON_UNESCAPED_UNICODE); echo "data: {$jsonData}\n\n"; // 强制刷新输出缓冲区 if (ob_get_level() > 0) { ob_flush(); } flush(); // 检查客户端是否断开连接 if (connection_aborted()) { break; } } // 发送结束标记 echo "data: [DONE]\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } catch (\Exception $e) { // 发送错误信息 $error = [ 'type' => 'error', 'msg' => $e->getMessage(), 'code' => $e->getCode() ]; $jsonError = json_encode($error, JSON_UNESCAPED_UNICODE); echo "data: {$jsonError}\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'X-Accel-Buffering' => 'no', // 防止 Nginx 缓冲 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Credentials' => 'true' ]); } public function chat(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); return response()->stream(function () use ($data) { // 禁用所有输出缓冲 if (ob_get_level()) { ob_end_clean(); } // 设置输出缓冲为关闭 ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', 'off'); // 立即刷新 if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); } try { $generator = $this->deepseekService->chat($data); foreach ($generator as $chunk) { // 发送 SSE 格式的数据 $jsonData = json_encode($chunk, JSON_UNESCAPED_UNICODE); echo "data: {$jsonData}\n\n"; // 强制刷新输出缓冲区 if (ob_get_level() > 0) { ob_flush(); } flush(); // 检查客户端是否断开连接 if (connection_aborted()) { break; } } // 发送结束标记 echo "data: [DONE]\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } catch (\Exception $e) { // 发送错误信息 $error = [ 'type' => 'error', 'msg' => $e->getMessage(), 'code' => $e->getCode() ]; $jsonError = json_encode($error, JSON_UNESCAPED_UNICODE); echo "data: {$jsonError}\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'X-Accel-Buffering' => 'no', // 防止 Nginx 缓冲 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Credentials' => 'true' ]); } // 新建对话 public function addChatForAce(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); return response()->stream(function () use ($data) { // 禁用所有输出缓冲 if (ob_get_level()) { ob_end_clean(); } // 设置输出缓冲为关闭 ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', 'off'); // 立即刷新 if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); } try { $generator = $this->deepseekService->addChatForAce($data); foreach ($generator as $chunk) { // 发送 SSE 格式的数据 $jsonData = json_encode($chunk, JSON_UNESCAPED_UNICODE); echo "data: {$jsonData}\n\n"; // 强制刷新输出缓冲区 if (ob_get_level() > 0) { ob_flush(); } flush(); // 检查客户端是否断开连接 if (connection_aborted()) { break; } } // 发送结束标记 echo "data: [DONE]\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } catch (\Exception $e) { // 发送错误信息 $error = [ 'type' => 'error', 'msg' => $e->getMessage(), 'code' => $e->getCode() ]; $jsonError = json_encode($error, JSON_UNESCAPED_UNICODE); echo "data: {$jsonError}\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'X-Accel-Buffering' => 'no', // 防止 Nginx 缓冲 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Credentials' => 'true' ]); } // 调整大纲 public function reGenerateAnimeForAce(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); return response()->stream(function () use ($data) { // 禁用所有输出缓冲 if (ob_get_level()) { ob_end_clean(); } // 设置输出缓冲为关闭 ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', 'off'); // 立即刷新 if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); } try { $generator = $this->deepseekService->reGenerateAnimeForAce($data); foreach ($generator as $chunk) { // 发送 SSE 格式的数据 $jsonData = json_encode($chunk, JSON_UNESCAPED_UNICODE); echo "data: {$jsonData}\n\n"; // 强制刷新输出缓冲区 if (ob_get_level() > 0) { ob_flush(); } flush(); // 检查客户端是否断开连接 if (connection_aborted()) { break; } } // 发送结束标记 echo "data: [DONE]\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } catch (\Exception $e) { // 发送错误信息 $error = [ 'type' => 'error', 'msg' => $e->getMessage(), 'code' => $e->getCode() ]; $jsonError = json_encode($error, JSON_UNESCAPED_UNICODE); echo "data: {$jsonError}\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'X-Accel-Buffering' => 'no', // 防止 Nginx 缓冲 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Credentials' => 'true' ]); } public function chatForAce(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); return response()->stream(function () use ($data) { // 禁用所有输出缓冲 if (ob_get_level()) { ob_end_clean(); } // 设置输出缓冲为关闭 ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', 'off'); // 立即刷新 if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); } try { $generator = $this->deepseekService->chatForAce($data); foreach ($generator as $chunk) { // 发送 SSE 格式的数据 $jsonData = json_encode($chunk, JSON_UNESCAPED_UNICODE); echo "data: {$jsonData}\n\n"; // 强制刷新输出缓冲区 if (ob_get_level() > 0) { ob_flush(); } flush(); // 检查客户端是否断开连接 if (connection_aborted()) { break; } } // 发送结束标记 echo "data: [DONE]\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } catch (\Exception $e) { // 发送错误信息 $error = [ 'type' => 'error', 'msg' => $e->getMessage(), 'code' => $e->getCode() ]; $jsonError = json_encode($error, JSON_UNESCAPED_UNICODE); echo "data: {$jsonError}\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'X-Accel-Buffering' => 'no', // 防止 Nginx 缓冲 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Credentials' => 'true' ]); } // 对话改图 public function chatChangeImg(Request $request) { $data = $request->all(); $result = $this->deepseekService->chatChangeImg($data); return $this->success($result); } /** * 通用文生文接口 - 流式输出 * @param Request $request * @return \Symfony\Component\HttpFoundation\StreamedResponse */ public function generateText(Request $request) { // 忽略所有超时限制 set_time_limit(0); ini_set('max_execution_time', '0'); $data = $request->all(); // 处理上传的图片文件 if ($request->hasFile('images')) { $data['images'] = $request->file('images'); } else if ($request->hasFile('image')) { // 支持单张图片 $data['images'] = [$request->file('image')]; } return response()->stream(function () use ($data) { // 禁用所有输出缓冲 if (ob_get_level()) { ob_end_clean(); } // 设置输出缓冲为关闭 ini_set('output_buffering', 'off'); ini_set('zlib.output_compression', 'off'); // 立即刷新 if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); } try { $generator = $this->deepseekService->generateText($data); foreach ($generator as $chunk) { // 发送 SSE 格式的数据 $jsonData = json_encode($chunk, JSON_UNESCAPED_UNICODE); echo "data: {$jsonData}\n\n"; // 强制刷新输出缓冲区 if (ob_get_level() > 0) { ob_flush(); } flush(); // 检查客户端是否断开连接 if (connection_aborted()) { break; } } // 发送结束标记 echo "data: [DONE]\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } catch (\Exception $e) { // 发送错误信息 $error = [ 'type' => 'error', 'msg' => $e->getMessage(), 'code' => $e->getCode() ]; $jsonError = json_encode($error, JSON_UNESCAPED_UNICODE); echo "data: {$jsonError}\n\n"; if (ob_get_level() > 0) { ob_flush(); } flush(); } }, 200, [ 'Content-Type' => 'text/event-stream', 'Cache-Control' => 'no-cache', 'Connection' => 'keep-alive', 'X-Accel-Buffering' => 'no', // 防止 Nginx 缓冲 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Credentials' => 'true' ]); } }