From 0d25202345c5229b99768998e83cf8d4cb8bfb79 Mon Sep 17 00:00:00 2001 From: Christopher Hertel Date: Tue, 18 Feb 2025 20:27:40 +0100 Subject: [PATCH] refactor: gpt stream conversion --- src/Bridge/OpenAI/GPT/ResponseConverter.php | 57 ++++++++------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/src/Bridge/OpenAI/GPT/ResponseConverter.php b/src/Bridge/OpenAI/GPT/ResponseConverter.php index 9abb78a3..247003e5 100644 --- a/src/Bridge/OpenAI/GPT/ResponseConverter.php +++ b/src/Bridge/OpenAI/GPT/ResponseConverter.php @@ -32,7 +32,7 @@ public function supports(Model $model, array|string|object $input): bool public function convert(HttpResponse $response, array $options = []): LlmResponse { if ($options['stream'] ?? false) { - return $this->convertStream($response); + return new StreamResponse($this->convertStream($response)); } try { @@ -52,7 +52,7 @@ public function convert(HttpResponse $response, array $options = []): LlmRespons } /** @var Choice[] $choices */ - $choices = \array_map([$this, 'convertChoice'], $data['choices']); + $choices = \array_map($this->convertChoice(...), $data['choices']); if (1 !== count($choices)) { return new ChoiceResponse(...$choices); @@ -65,15 +65,9 @@ public function convert(HttpResponse $response, array $options = []): LlmRespons return new TextResponse($choices[0]->getContent()); } - private function convertStream(HttpResponse $response): StreamResponse - { - $stream = $this->streamResponse($response); - - return new StreamResponse($this->convertStreamContent($stream)); - } - - private function streamResponse(HttpResponse $response): \Generator + private function convertStream(HttpResponse $response): \Generator { + $toolCalls = []; foreach ((new EventSourceHttpClient())->stream($response) as $chunk) { if (!$chunk instanceof ServerSentEvent || '[DONE]' === $chunk->getData()) { continue; @@ -81,20 +75,25 @@ private function streamResponse(HttpResponse $response): \Generator try { $data = $chunk->getArrayData(); - - yield $data; } catch (JsonException) { // try catch only needed for Symfony 6.4 continue; } - } - } - private function streamIsToolCall(\Generator $response): bool - { - $data = $response->current(); + if ($this->streamIsToolCall($data)) { + $toolCalls = $this->convertStreamToToolCalls($toolCalls, $data); + } - return isset($data['choices'][0]['delta']['tool_calls']); + if ([] !== $toolCalls && $this->isToolCallsStreamFinished($data)) { + yield new ToolCallResponse(...\array_map($this->convertToolCall(...), $toolCalls)); + } + + if (!isset($data['choices'][0]['delta']['content'])) { + continue; + } + + yield $data['choices'][0]['delta']['content']; + } } /** @@ -126,24 +125,12 @@ private function convertStreamToToolCalls(array $toolCalls, array $data): array return $toolCalls; } - private function convertStreamContent(\Generator $generator): \Generator + /** + * @param array $data + */ + private function streamIsToolCall(array $data): bool { - $toolCalls = []; - foreach ($generator as $data) { - if ($this->streamIsToolCall($generator)) { - $toolCalls = $this->convertStreamToToolCalls($toolCalls, $data); - } - - if ([] !== $toolCalls && $this->isToolCallsStreamFinished($data)) { - yield new ToolCallResponse(...\array_map([$this, 'convertToolCall'], $toolCalls)); - } - - if (!isset($data['choices'][0]['delta']['content'])) { - continue; - } - - yield $data['choices'][0]['delta']['content']; - } + return isset($data['choices'][0]['delta']['tool_calls']); } /**