DeepSeekChatController.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. namespace App\Http\Controllers\API;
  3. use App\Http\Controllers\Controller;
  4. use App\Models\LlmMessage;
  5. use App\Models\LlmSession;
  6. use App\Services\LLM\DeepSeekService;
  7. use Illuminate\Http\JsonResponse;
  8. use Illuminate\Http\Request;
  9. use Illuminate\Http\Response;
  10. use Illuminate\Support\Facades\Auth;
  11. use Illuminate\Support\Str;
  12. use Symfony\Component\HttpFoundation\StreamedResponse;
  13. class DeepSeekChatController extends Controller
  14. {
  15. public function getLlmList(): JsonResponse
  16. {
  17. $list = config('llm');
  18. $llmList = [];
  19. foreach ($list as $key => $item) {
  20. if (!isset($item['enabled']) || !$item['enabled']) {
  21. continue;
  22. }
  23. $llmList[] = [
  24. 'name' => $item['name'],
  25. 'model' => $item['model'],
  26. ];
  27. }
  28. return $this->success(['data' => $llmList]);
  29. }
  30. // 重命名
  31. public function renameSession(Request $request, $sessionId): JsonResponse
  32. {
  33. $userId = Auth::id();
  34. $title = $request->input('title');
  35. if (!$title) {
  36. return $this->badRequest('会话标题不能为空');
  37. }
  38. $session = LlmSession::query()
  39. ->where('session_id', $sessionId)
  40. ->where('user_id', $userId)
  41. ->first();
  42. if (!$session) {
  43. return $this->badRequest('会话不存在或无权访问');
  44. }
  45. $session->update([
  46. 'title' => $title,
  47. ]);
  48. return $this->success(['data' => $session]);
  49. }
  50. // 删除接口
  51. public function deleteSession(Request $request, $sessionId)
  52. {
  53. $userId = Auth::id();
  54. $session = LlmSession::query()
  55. ->where('session_id', $sessionId)
  56. ->where('user_id', $userId)
  57. ->first();
  58. if (!$session) {
  59. return $this->badRequest('会话不存在或无权访问');
  60. }
  61. $session->delete();
  62. $session->messages()->delete();
  63. }
  64. /**
  65. * 添加会话
  66. *
  67. * @param Request $request
  68. * @return JsonResponse
  69. */
  70. public function addSession(Request $request): JsonResponse
  71. {
  72. $userId = Auth::id();
  73. if (!$request->input('title')) {
  74. return $this->badRequest('会话标题不能为空');
  75. }
  76. $list = config('llm');
  77. $modelMap = array_column($list, null, 'model');
  78. $llm = $modelMap[$request->input('model')] ?? null;
  79. if (!$llm || !$llm['enabled']) {
  80. return $this->badRequest('LLM服务未启用或未配置');
  81. }
  82. $session = LlmSession::create([
  83. 'session_id' => Str::uuid(),
  84. 'user_id' => $userId,
  85. 'title' => $request->input('title', ''),
  86. 'model' => $llm['model'],
  87. ]);
  88. return $this->success(['data' => $session]);
  89. }
  90. /**
  91. * 获取会话列表
  92. *
  93. * @param Request $request
  94. * @return JsonResponse
  95. */
  96. public function getSessionList(Request $request): JsonResponse
  97. {
  98. $userId = Auth::id();
  99. $sessions = LlmSession::where('user_id', $userId)
  100. ->where('updated_at', '>', now()->subDays(30))
  101. ->orderBy('updated_at', 'desc')->get();
  102. return $this->success(['data' => $sessions]);
  103. }
  104. /**
  105. * 获取对话详情
  106. *
  107. * @param Request $request
  108. * @param int $sessionId
  109. * @return JsonResponse
  110. */
  111. public function getSessionDetail(Request $request, $sessionId): JsonResponse
  112. {
  113. $userId = Auth::id();
  114. $session = LlmSession::where('id', $sessionId)
  115. ->where('user_id', $userId)
  116. ->first();
  117. if (!$session) {
  118. return $this->error('会话不存在或无权访问', 404);
  119. }
  120. // 获取会话详情,包括消息历史
  121. $sessionData = [
  122. 'session' => $session->toArray(),
  123. 'messages' => $session->messages ?? []
  124. ];
  125. return $this->success(['data' => $sessionData]);
  126. }
  127. public function handleStream(Request $request): StreamedResponse
  128. {
  129. // 一个session进行多轮对话
  130. $sessionId = $request->input("session_id");
  131. $list = config('llm');
  132. $modelMap = array_column($list, null, 'model');
  133. $llm = $modelMap[$request->input('model')] ?? null;
  134. // 获取该session的历史对话记录
  135. $history = [];
  136. if ($sessionId) {
  137. // 获取该session的历史对话记录
  138. $session = LlmSession::query()->where('session_id', $sessionId)->firstOrFail();
  139. $history = $session->messages->map(function ($item) {
  140. return [
  141. 'role' => $item['role'],
  142. 'content' => $item['content'],
  143. ];
  144. });
  145. }
  146. return new StreamedResponse(function () use ($llm, $request, $history) {
  147. // 1. 设置SSE头
  148. header('Content-Type: text/event-stream');
  149. header('Cache-Control: no-cache');
  150. header('Connection: keep-alive');
  151. header('X-Accel-Buffering: no');
  152. header('Transfer-Encoding: chunked');
  153. if (!$llm) {
  154. return [
  155. 'role' => 'assistant',
  156. 'content' => '服务器错误,请稍后再试~',
  157. ];
  158. }
  159. // 2. 获取请求参数
  160. $prompt = $request->input('prompt', '');
  161. // 追加该会话上下文
  162. $message = array_merge($history ? $history->toArray() : [], [
  163. ['role' => 'user', 'content' => $prompt],
  164. ]);
  165. DeepSeekService::streamedResponseChat($llm, $message, $request->input("session_id"));
  166. }, 200, [
  167. 'Content-Type' => 'text/event-stream',
  168. ]);
  169. }
  170. }