| 
4 | 4 | 
 
  | 
5 | 5 | namespace GeminiAPI;  | 
6 | 6 | 
 
  | 
 | 7 | +use BadMethodCallException;  | 
 | 8 | +use CurlHandle;  | 
7 | 9 | use GeminiAPI\ClientInterface as GeminiClientInterface;  | 
8 | 10 | use GeminiAPI\Enums\ModelName;  | 
 | 11 | +use GeminiAPI\Json\ObjectListParser;  | 
9 | 12 | use GeminiAPI\Requests\CountTokensRequest;  | 
10 | 13 | use GeminiAPI\Requests\EmbedContentRequest;  | 
11 | 14 | use GeminiAPI\Requests\GenerateContentRequest;  | 
 | 15 | +use GeminiAPI\Requests\GenerateContentStreamRequest;  | 
12 | 16 | use GeminiAPI\Requests\ListModelsRequest;  | 
13 | 17 | use GeminiAPI\Requests\RequestInterface;  | 
14 | 18 | use GeminiAPI\Responses\CountTokensResponse;  | 
 | 
23 | 27 | use Psr\Http\Message\StreamFactoryInterface;  | 
24 | 28 | use RuntimeException;  | 
25 | 29 | 
 
  | 
 | 30 | +use function curl_close;  | 
 | 31 | +use function curl_exec;  | 
 | 32 | +use function curl_init;  | 
 | 33 | +use function curl_setopt;  | 
 | 34 | +use function extension_loaded;  | 
26 | 35 | use function json_decode;  | 
27 | 36 | 
 
  | 
28 | 37 | class Client implements GeminiClientInterface  | 
@@ -76,6 +85,38 @@ public function generateContent(GenerateContentRequest $request): GenerateConten  | 
76 | 85 |  return GenerateContentResponse::fromArray($json);  | 
77 | 86 |  }  | 
78 | 87 | 
 
  | 
 | 88 | + /**  | 
 | 89 | + * @param callable(GenerateContentResponse): void $callback  | 
 | 90 | + * @throws BadMethodCallException  | 
 | 91 | + * @throws RuntimeException  | 
 | 92 | + */  | 
 | 93 | + public function generateContentStream(  | 
 | 94 | + GenerateContentStreamRequest $request,  | 
 | 95 | + callable $callback,  | 
 | 96 | + ): void {  | 
 | 97 | + if (!extension_loaded('curl')) {  | 
 | 98 | + throw new BadMethodCallException('Gemini API requires `curl` extension for streaming responses');  | 
 | 99 | + }  | 
 | 100 | + | 
 | 101 | + $parser = new ObjectListParser(  | 
 | 102 | + /* @phpstan-ignore-next-line */  | 
 | 103 | + static fn (array $arr) => $callback(GenerateContentResponse::fromArray($arr)),  | 
 | 104 | + );  | 
 | 105 | + | 
 | 106 | + $ch = curl_init("{$this->baseUrl}/v1/{$request->getOperation()}");  | 
 | 107 | + curl_setopt($ch, CURLOPT_POST, true);  | 
 | 108 | + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request));  | 
 | 109 | + curl_setopt($ch, CURLOPT_HTTPHEADER, [  | 
 | 110 | + 'Content-type: application/json',  | 
 | 111 | + self::API_KEY_HEADER_NAME . ": {$this->apiKey}",  | 
 | 112 | + ]);  | 
 | 113 | + curl_setopt($ch, CURLOPT_WRITEFUNCTION,  | 
 | 114 | + static fn (CurlHandle $ch, string $str): int => $parser->consume($str),  | 
 | 115 | + );  | 
 | 116 | + curl_exec($ch);  | 
 | 117 | + curl_close($ch);  | 
 | 118 | + }  | 
 | 119 | + | 
79 | 120 |  /**  | 
80 | 121 |  * @throws ClientExceptionInterface  | 
81 | 122 |  */  | 
 | 
0 commit comments