123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- <?php
- namespace App\Services\LLM;
- use Illuminate\Support\Facades\Http;
- use Illuminate\Support\Facades\Log;
- class DeepSeekService
- {
- public static function streamedResponseChat($message): void
- {
- $headers = [
- 'Authorization' => 'Bearer ' . config('llm.deepseek.key'),
- 'Content-Type' => 'application/json',
- ];
- $body = [
- 'model' => 'deepseek-chat',
- 'messages' => $message,
- 'stream' => true,
- ];
- // 3. 调用DeepSeek流式API
- $response = Http::withHeaders($headers)->timeout(300)->send('POST', 'https://api.deepseek.com/chat/completions', [
- 'json' => $body
- ]);
- // 4. 流式转发数据
- $body = $response->toPsrResponse()->getBody();
- while (true) {
- if ($body->eof() || !$body->isReadable()) {
- break;
- }
- $chunk = $body->getContents();
- // 分割完整的JSON行
- $lines = explode("\n\n", $chunk);
- foreach ($lines as $line) {
- $line = trim($line);
- if ($line === '') {
- continue; // 跳过空行
- }
- // 处理单条事件
- if (str_starts_with($line, 'data: ')) {
- // 去除 "data: " 前缀
- $jsonStr = substr($line, 6);
- self::processEvent($jsonStr);
- }
- }
- // 检测连接是否中断
- if (connection_aborted()) {
- break;
- }
- }
- }
- // 处理单个事件的方法
- protected static function processEvent(string $jsonStr): void
- {
- if ($jsonStr === '[DONE]') {
- echo "event: end\n\n";
- ob_flush();
- flush();
- return;
- }
- try {
- $data = json_decode($jsonStr, true, 512, JSON_THROW_ON_ERROR);
- $content = $data['choices'][0]['delta']['content'] ?? '';
- echo "data: " . json_encode(['content' => $content], JSON_UNESCAPED_UNICODE) . "\n\n";
- ob_flush();
- flush();
- } catch (\JsonException $e) {
- Log::error('JSON 解析失败: ' . $e->getMessage());
- }
- }
- }
|