config = $config ?? config('LLMapi.embedding', []); $baseUrl = rtrim((string) ($this->config['base_url'] ?? ''), '/'); $this->client = new Client([ 'base_uri' => $baseUrl . '/', 'timeout' => (int) ($this->config['timeout'] ?? 60), 'connect_timeout' => (int) ($this->config['connect_timeout'] ?? 10), ]); } public function isConfigured(): bool { return trim((string) ($this->config['api_key'] ?? '')) !== '' && trim((string) ($this->config['base_url'] ?? '')) !== ''; } public function embed(array $texts, array $options = []): array { if (!$this->isConfigured()) { throw new RuntimeException('BigModel embedding API is not configured.'); } $texts = array_values($texts); if ($texts === []) { return [ 'model' => (string) ($options['model'] ?? $this->config['model'] ?? 'embedding-3'), 'data' => [], 'usage' => [], ]; } $batchSize = (int) ($this->config['batch_size'] ?? 64); if (count($texts) > $batchSize) { throw new RuntimeException("Embedding batch exceeds configured batch size {$batchSize}."); } $body = [ 'model' => $options['model'] ?? $this->config['model'] ?? 'embedding-3', 'input' => $texts, ]; $dimensions = $options['dimensions'] ?? $this->config['dimensions'] ?? null; if ($dimensions !== null) { $dimensions = (int) $dimensions; if (!in_array($dimensions, [256, 512, 1024, 2048], true)) { throw new RuntimeException('Embedding dimensions must be one of 256, 512, 1024, or 2048.'); } $body['dimensions'] = $dimensions; } try { $response = $this->client->post('embeddings', [ 'headers' => [ 'Authorization' => 'Bearer ' . $this->config['api_key'], 'Content-Type' => 'application/json', ], 'json' => $body, ]); } catch (RequestException $exception) { throw $this->requestException($exception); } catch (Throwable $exception) { throw new RuntimeException('BigModel embedding request failed: ' . $exception->getMessage(), 0, $exception); } $payload = json_decode((string) $response->getBody(), true); if (!is_array($payload) || !isset($payload['data']) || !is_array($payload['data'])) { throw new RuntimeException('BigModel embedding response is invalid.'); } return $payload; } private function requestException(RequestException $exception): LLMRequestException { $statusCode = $exception->getResponse()?->getStatusCode(); $body = $exception->getResponse() ? (string) $exception->getResponse()->getBody() : ''; $payload = json_decode($body, true); $providerCode = null; $providerMessage = null; if (is_array($payload)) { $providerCode = isset($payload['error']['code']) ? (string) $payload['error']['code'] : null; $providerMessage = isset($payload['error']['message']) ? (string) $payload['error']['message'] : null; if ($providerCode === null && isset($payload['code'])) { $providerCode = (string) $payload['code']; } if ($providerMessage === null && isset($payload['message'])) { $providerMessage = (string) $payload['message']; } } $message = 'BigModel embedding request failed'; if ($statusCode !== null) { $message .= " with HTTP {$statusCode}"; } if ($providerCode !== null) { $message .= " and provider code {$providerCode}"; } if ($providerMessage !== null) { $message .= ": {$providerMessage}"; } else { $message .= ': ' . $exception->getMessage(); } return new LLMRequestException($message, $statusCode, $providerCode, is_array($payload) ? $payload : null); } }