DeepSeekService.php 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. <?php
  2. namespace App\Services\LLM;
  3. use Illuminate\Support\Facades\Http;
  4. use Illuminate\Support\Facades\Log;
  5. class DeepSeekService
  6. {
  7. public static function streamedResponseChat($message): void
  8. {
  9. $headers = [
  10. 'Authorization' => 'Bearer ' . config('llm.deepseek.key'),
  11. 'Content-Type' => 'application/json',
  12. ];
  13. $body = [
  14. 'model' => 'deepseek-chat',
  15. 'messages' => $message,
  16. 'stream' => true,
  17. ];
  18. // 3. 调用DeepSeek流式API
  19. $response = Http::withHeaders($headers)->timeout(300)->send('POST', 'https://api.deepseek.com/chat/completions', [
  20. 'json' => $body
  21. ]);
  22. // 4. 流式转发数据
  23. $body = $response->toPsrResponse()->getBody();
  24. while (true) {
  25. if ($body->eof() || !$body->isReadable()) {
  26. break;
  27. }
  28. $chunk = $body->getContents();
  29. // 分割完整的JSON行
  30. $lines = explode("\n\n", $chunk);
  31. foreach ($lines as $line) {
  32. $line = trim($line);
  33. if ($line === '') {
  34. continue; // 跳过空行
  35. }
  36. // 处理单条事件
  37. if (str_starts_with($line, 'data: ')) {
  38. // 去除 "data: " 前缀
  39. $jsonStr = substr($line, 6);
  40. self::processEvent($jsonStr);
  41. }
  42. }
  43. // 检测连接是否中断
  44. if (connection_aborted()) {
  45. break;
  46. }
  47. }
  48. }
  49. // 处理单个事件的方法
  50. protected static function processEvent(string $jsonStr): void
  51. {
  52. if ($jsonStr === '[DONE]') {
  53. echo "event: end\n\n";
  54. ob_flush();
  55. flush();
  56. return;
  57. }
  58. try {
  59. $data = json_decode($jsonStr, true, 512, JSON_THROW_ON_ERROR);
  60. $content = $data['choices'][0]['delta']['content'] ?? '';
  61. echo "data: " . json_encode(['content' => $content], JSON_UNESCAPED_UNICODE) . "\n\n";
  62. ob_flush();
  63. flush();
  64. } catch (\JsonException $e) {
  65. Log::error('JSON 解析失败: ' . $e->getMessage());
  66. }
  67. }
  68. }