DeepSeekService.php 2.4 KB

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