| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 3 declare (strict_types=1); 4 namespace WordPress\AiClient; 5 6 use WordPress\AiClientDependencies\Psr\EventDispatcher\EventDispatcherInterface; 7 use WordPress\AiClientDependencies\Psr\SimpleCache\CacheInterface; 8 use WordPress\AiClient\Builders\EmbeddingBuilder; 9 use WordPress\AiClient\Builders\PromptBuilder; 10 use WordPress\AiClient\Common\Exception\InvalidArgumentException; 11 use WordPress\AiClient\Common\Exception\RuntimeException; 12 use WordPress\AiClient\Providers\Contracts\ProviderAvailabilityInterface; 13 use WordPress\AiClient\Providers\Contracts\ProviderInterface; 14 use WordPress\AiClient\Providers\ModelResolver; 15 use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; 16 use WordPress\AiClient\Providers\Models\DTO\ModelConfig; 17 use WordPress\AiClient\Providers\ProviderRegistry; 18 use WordPress\AiClient\Results\DTO\Embedding; 19 use WordPress\AiClient\Results\DTO\EmbeddingResult; 20 use WordPress\AiClient\Results\DTO\GenerativeAiResult; 21 /** 22 * Main AI Client class providing both fluent and traditional APIs for AI operations. 23 * 24 * This class serves as the primary entry point for AI operations, offering: 25 * - Fluent API for easy-to-read chained method calls 26 * - Traditional API for array-based configuration (WordPress style) 27 * - Integration with provider registry for model discovery 28 * - Support for three model specification approaches 29 * 30 * All model requirements analysis and capability matching is handled 31 * automatically by the PromptBuilder, which provides intelligent model 32 * discovery based on prompt content and configuration. 33 * 34 * ## Model Specification Approaches 35 * 36 * ### 1. Specific Model Instance 37 * Use a specific ModelInterface instance when you know exactly which model to use: 38 * ```php 39 * $model = $registry->getProvider('openai')->getModel('gpt-4'); 40 * $result = AiClient::generateTextResult('What is PHP?', $model); 41 * ``` 42 * 43 * ### 2. ModelConfig for Auto-Discovery 44 * Use ModelConfig to specify requirements and let the system discover the best model: 45 * ```php 46 * $config = new ModelConfig(); 47 * $config->setTemperature(0.7); 48 * $config->setMaxTokens(150); 49 * 50 * $result = AiClient::generateTextResult('What is PHP?', $config); 51 * ``` 52 * 53 * ### 3. Automatic Discovery (Default) 54 * Pass null or omit the parameter for intelligent model discovery based on prompt content: 55 * ```php 56 * // System analyzes prompt and selects appropriate model automatically 57 * $result = AiClient::generateTextResult('What is PHP?'); 58 * $imageResult = AiClient::generateImageResult('A sunset over mountains'); 59 * ``` 60 * 61 * ## Fluent API Examples 62 * ```php 63 * // Fluent API with automatic model discovery 64 * $result = AiClient::prompt('Generate an image of a sunset') 65 * ->usingTemperature(0.7) 66 * ->generateImageResult(); 67 * 68 * // Fluent API with specific model 69 * $result = AiClient::prompt('What is PHP?') 70 * ->usingModel($specificModel) 71 * ->usingTemperature(0.5) 72 * ->generateTextResult(); 73 * 74 * // Fluent API with model configuration 75 * $result = AiClient::prompt('Explain quantum physics') 76 * ->usingModelConfig($config) 77 * ->generateTextResult(); 78 * ``` 79 * 80 * @since 0.1.0 81 * 82 * @phpstan-import-type Prompt from PromptBuilder 83 * @phpstan-import-type EmbeddingInput from EmbeddingBuilder 84 * @phpstan-import-type ProviderModelTuple from ModelResolver 85 * 86 * phpcs:ignore Generic.Files.LineLength.TooLong 87 */ 88 class AiClient 89 { 90 /** 91 * @var string The version of the AI Client. 92 */ 93 public const VERSION = '1.5.1'; 94 /** 95 * @var ProviderRegistry|null The default provider registry instance. 96 */ 97 private static ?ProviderRegistry $defaultRegistry = null; 98 /** 99 * @var EventDispatcherInterface|null The event dispatcher for prompt lifecycle events. 100 */ 101 private static ?EventDispatcherInterface $eventDispatcher = null; 102 /** 103 * @var CacheInterface|null The PSR-16 cache for storing and retrieving cached data. 104 */ 105 private static ?CacheInterface $cache = null; 106 /** 107 * Gets the default provider registry instance. 108 * 109 * @since 0.1.0 110 * 111 * @return ProviderRegistry The default provider registry. 112 */ 113 public static function defaultRegistry(): ProviderRegistry 114 { 115 if (self::$defaultRegistry === null) { 116 self::$defaultRegistry = new ProviderRegistry(); 117 } 118 return self::$defaultRegistry; 119 } 120 /** 121 * Sets the event dispatcher for prompt lifecycle events. 122 * 123 * The event dispatcher will be used to dispatch BeforeGenerateResultEvent and 124 * AfterGenerateResultEvent during prompt generation. 125 * 126 * @since 0.4.0 127 * 128 * @param EventDispatcherInterface|null $dispatcher The event dispatcher, or null to disable. 129 * @return void 130 */ 131 public static function setEventDispatcher(?EventDispatcherInterface $dispatcher): void 132 { 133 self::$eventDispatcher = $dispatcher; 134 } 135 /** 136 * Gets the event dispatcher for prompt lifecycle events. 137 * 138 * @since 0.4.0 139 * 140 * @return EventDispatcherInterface|null The event dispatcher, or null if not set. 141 */ 142 public static function getEventDispatcher(): ?EventDispatcherInterface 143 { 144 return self::$eventDispatcher; 145 } 146 /** 147 * Sets the PSR-16 cache for storing and retrieving cached data. 148 * 149 * The cache can be used to store AI responses and other data to avoid 150 * redundant API calls and improve performance. 151 * 152 * @since 0.4.0 153 * 154 * @param CacheInterface|null $cache The PSR-16 cache instance, or null to disable caching. 155 * @return void 156 */ 157 public static function setCache(?CacheInterface $cache): void 158 { 159 self::$cache = $cache; 160 } 161 /** 162 * Gets the PSR-16 cache instance. 163 * 164 * @since 0.4.0 165 * 166 * @return CacheInterface|null The cache instance, or null if not set. 167 */ 168 public static function getCache(): ?CacheInterface 169 { 170 return self::$cache; 171 } 172 /** 173 * Checks if a provider is configured and available for use. 174 * 175 * Supports multiple input formats for developer convenience: 176 * - ProviderAvailabilityInterface: Direct availability check 177 * - string (provider ID): e.g., AiClient::isConfigured('openai') 178 * - string (class name): e.g., AiClient::isConfigured(OpenAiProvider::class) 179 * 180 * When using string input, this method leverages the ProviderRegistry's centralized 181 * dependency management, ensuring HttpTransporter and authentication are properly 182 * injected into availability instances. 183 * 184 * @since 0.1.0 185 * @since 0.2.0 Now supports being passed a provider ID or class name. 186 * 187 * @param ProviderAvailabilityInterface|string|class-string<ProviderInterface> $availabilityOrIdOrClassName 188 * The provider availability instance, provider ID, or provider class name. 189 * @return bool True if the provider is configured and available, false otherwise. 190 */ 191 public static function isConfigured($availabilityOrIdOrClassName): bool 192 { 193 // Handle direct ProviderAvailabilityInterface (backward compatibility) 194 if ($availabilityOrIdOrClassName instanceof ProviderAvailabilityInterface) { 195 return $availabilityOrIdOrClassName->isConfigured(); 196 } 197 // Handle string input (provider ID or class name) via registry 198 if (is_string($availabilityOrIdOrClassName)) { 199 return self::defaultRegistry()->isProviderConfigured($availabilityOrIdOrClassName); 200 } 201 throw new \InvalidArgumentException('Parameter must be a ProviderAvailabilityInterface instance, provider ID string, or provider class name. ' . sprintf('Received: %s', is_object($availabilityOrIdOrClassName) ? get_class($availabilityOrIdOrClassName) : gettype($availabilityOrIdOrClassName))); 202 } 203 /** 204 * Creates a new prompt builder for fluent API usage. 205 * 206 * Returns a PromptBuilder instance configured with the specified or default registry. 207 * The traditional API methods in this class delegate to PromptBuilder 208 * for all generation logic. 209 * 210 * @since 0.1.0 211 * 212 * @param Prompt $prompt Optional initial prompt content. 213 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 214 * @return PromptBuilder The prompt builder instance. 215 */ 216 public static function prompt($prompt = null, ?ProviderRegistry $registry = null): PromptBuilder 217 { 218 return new PromptBuilder($registry ?? self::defaultRegistry(), $prompt, self::$eventDispatcher); 219 } 220 /** 221 * Creates an embedding builder for fluent embedding generation. 222 * 223 * Accepts a single input or a list of inputs; each input is embedded independently. Chain an 224 * embedding generation method such as generateEmbedding() or generateEmbeddings() to produce 225 * one vector per input. 226 * 227 * A model must be specified on the returned builder via usingModel() or usingProviderModel(). 228 * Embedding vectors are only comparable to other vectors from the same model, so no model is 229 * selected automatically. 230 * 231 * @since 1.4.0 232 * 233 * @param EmbeddingInput|list<EmbeddingInput>|null $input Optional initial input(s) to embed. 234 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 235 * @return EmbeddingBuilder The embedding builder instance. 236 */ 237 public static function input($input = null, ?ProviderRegistry $registry = null): EmbeddingBuilder 238 { 239 return new EmbeddingBuilder($registry ?? self::defaultRegistry(), $input, self::$eventDispatcher); 240 } 241 /** 242 * Generates content using a unified API that automatically detects model capabilities. 243 * 244 * When no model is provided, this method delegates to PromptBuilder for intelligent 245 * model discovery based on prompt content and configuration. When a model is provided, 246 * it infers the capability from the model's interfaces and delegates to the capability-based method. 247 * 248 * @since 0.1.0 249 * 250 * @param Prompt $prompt The prompt content. 251 * @param ModelInterface|ModelConfig $modelOrConfig Specific model to use, or model configuration 252 * for auto-discovery. 253 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 254 * @return GenerativeAiResult The generation result. 255 * 256 * @throws \InvalidArgumentException If the provided model doesn't support any known generation type. 257 * @throws \RuntimeException If no suitable model can be found for the prompt. 258 */ 259 public static function generateResult($prompt, $modelOrConfig, ?ProviderRegistry $registry = null): GenerativeAiResult 260 { 261 self::validateModelOrConfigParameter($modelOrConfig); 262 return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateResult(); 263 } 264 /** 265 * Generates text using the traditional API approach. 266 * 267 * @since 0.1.0 268 * 269 * @param Prompt $prompt The prompt content. 270 * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use, 271 * or model configuration for auto-discovery, 272 * or null for defaults. 273 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 274 * @return GenerativeAiResult The generation result. 275 * 276 * @throws \InvalidArgumentException If the prompt format is invalid. 277 * @throws \RuntimeException If no suitable model is found. 278 */ 279 public static function generateTextResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult 280 { 281 self::validateModelOrConfigParameter($modelOrConfig); 282 return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateTextResult(); 283 } 284 /** 285 * Generates an image using the traditional API approach. 286 * 287 * @since 0.1.0 288 * 289 * @param Prompt $prompt The prompt content. 290 * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use, 291 * or model configuration for auto-discovery, 292 * or null for defaults. 293 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 294 * @return GenerativeAiResult The generation result. 295 * 296 * @throws \InvalidArgumentException If the prompt format is invalid. 297 * @throws \RuntimeException If no suitable model is found. 298 */ 299 public static function generateImageResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult 300 { 301 self::validateModelOrConfigParameter($modelOrConfig); 302 return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateImageResult(); 303 } 304 /** 305 * Converts text to speech using the traditional API approach. 306 * 307 * @since 0.1.0 308 * 309 * @param Prompt $prompt The prompt content. 310 * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use, 311 * or model configuration for auto-discovery, 312 * or null for defaults. 313 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 314 * @return GenerativeAiResult The generation result. 315 * 316 * @throws \InvalidArgumentException If the prompt format is invalid. 317 * @throws \RuntimeException If no suitable model is found. 318 */ 319 public static function convertTextToSpeechResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult 320 { 321 self::validateModelOrConfigParameter($modelOrConfig); 322 return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->convertTextToSpeechResult(); 323 } 324 /** 325 * Generates speech using the traditional API approach. 326 * 327 * @since 0.1.0 328 * 329 * @param Prompt $prompt The prompt content. 330 * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use, 331 * or model configuration for auto-discovery, 332 * or null for defaults. 333 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 334 * @return GenerativeAiResult The generation result. 335 * 336 * @throws \InvalidArgumentException If the prompt format is invalid. 337 * @throws \RuntimeException If no suitable model is found. 338 */ 339 public static function generateSpeechResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult 340 { 341 self::validateModelOrConfigParameter($modelOrConfig); 342 return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateSpeechResult(); 343 } 344 /** 345 * Generates a video using the traditional API approach. 346 * 347 * @since 1.3.0 348 * 349 * @param Prompt $prompt The prompt content. 350 * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use, 351 * or model configuration for auto-discovery, 352 * or null for defaults. 353 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 354 * @return GenerativeAiResult The generation result. 355 * 356 * @throws \InvalidArgumentException If the prompt format is invalid. 357 * @throws \RuntimeException If no suitable model is found. 358 */ 359 public static function generateVideoResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult 360 { 361 self::validateModelOrConfigParameter($modelOrConfig); 362 return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateVideoResult(); 363 } 364 /** 365 * Generates embeddings using the traditional API approach. 366 * 367 * A model is required. Embedding vectors are only comparable to other vectors from the same 368 * model, so no model is selected automatically. 369 * 370 * @since 1.4.0 371 * 372 * @param EmbeddingInput|list<EmbeddingInput> $input The input(s) to embed. 373 * @param ModelInterface|ProviderModelTuple $model The model to use. 374 * @param ModelConfig|null $modelConfig Optional model configuration to apply. 375 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 376 * @return EmbeddingResult The embedding result. 377 * 378 * @throws \InvalidArgumentException If the input or model format is invalid, or if the model 379 * cannot fulfill the request. 380 */ 381 public static function generateEmbeddingResult($input, $model, ?ModelConfig $modelConfig = null, ?ProviderRegistry $registry = null): EmbeddingResult 382 { 383 return self::getConfiguredEmbeddingBuilder($input, $model, $modelConfig, $registry)->generateEmbeddingResult(); 384 } 385 /** 386 * Generates an embedding using the traditional API approach. 387 * 388 * A model is required. Embedding vectors are only comparable to other vectors from the same 389 * model, so no model is selected automatically. 390 * 391 * @since 1.4.0 392 * 393 * @param EmbeddingInput $input The input to embed. 394 * @param ModelInterface|ProviderModelTuple $model The model to use. 395 * @param ModelConfig|null $modelConfig Optional model configuration to apply. 396 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 397 * @return Embedding The generated embedding vector. 398 */ 399 public static function generateEmbedding($input, $model, ?ModelConfig $modelConfig = null, ?ProviderRegistry $registry = null): Embedding 400 { 401 return self::generateEmbeddingResult($input, $model, $modelConfig, $registry)->getEmbedding(); 402 } 403 /** 404 * Generates embeddings for a list of inputs using the traditional API approach. 405 * 406 * A model is required. Embedding vectors are only comparable to other vectors from the same 407 * model, so no model is selected automatically. 408 * 409 * @since 1.4.0 410 * 411 * @param list<EmbeddingInput> $inputs The inputs to embed. 412 * @param ModelInterface|ProviderModelTuple $model The model to use. 413 * @param ModelConfig|null $modelConfig Optional model configuration to apply. 414 * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default. 415 * @return list<Embedding> The generated embedding vectors. 416 */ 417 public static function generateEmbeddings(array $inputs, $model, ?ModelConfig $modelConfig = null, ?ProviderRegistry $registry = null): array 418 { 419 return self::getConfiguredEmbeddingBuilder($inputs, $model, $modelConfig, $registry)->generateEmbeddings(); 420 } 421 /** 422 * Creates a new message builder for fluent API usage. 423 * 424 * This method will be implemented once MessageBuilder is available. 425 * MessageBuilder will provide a fluent interface for constructing complex 426 * messages with multiple parts, attachments, and metadata. 427 * 428 * @since 0.1.0 429 * 430 * @param string|null $text Optional initial message text. 431 * @return object MessageBuilder instance (type will be updated when MessageBuilder is available). 432 * 433 * @throws \RuntimeException When MessageBuilder is not yet available. 434 */ 435 public static function message(?string $text = null) 436 { 437 throw new RuntimeException('MessageBuilder is not yet available. This method depends on builder infrastructure. ' . 'Use direct generation methods (generateTextResult, generateImageResult, etc.) for now.'); 438 } 439 /** 440 * Validates that parameter is ModelInterface, ModelConfig, or null. 441 * 442 * @param mixed $modelOrConfig The parameter to validate. 443 * @return void 444 * @throws \InvalidArgumentException If parameter is invalid type. 445 */ 446 private static function validateModelOrConfigParameter($modelOrConfig): void 447 { 448 if ($modelOrConfig !== null && !$modelOrConfig instanceof ModelInterface && !$modelOrConfig instanceof ModelConfig) { 449 throw new InvalidArgumentException('Parameter must be a ModelInterface instance (specific model), ' . 'ModelConfig instance (for auto-discovery), or null (default auto-discovery). ' . sprintf('Received: %s', is_object($modelOrConfig) ? get_class($modelOrConfig) : gettype($modelOrConfig))); 450 } 451 } 452 /** 453 * Configures PromptBuilder based on model/config parameter type. 454 * 455 * @param Prompt $prompt The prompt content. 456 * @param ModelInterface|ModelConfig|null $modelOrConfig The model or config parameter. 457 * @param ProviderRegistry|null $registry Optional custom registry to use. 458 * @return PromptBuilder Configured prompt builder. 459 */ 460 private static function getConfiguredPromptBuilder($prompt, $modelOrConfig, ?ProviderRegistry $registry = null): PromptBuilder 461 { 462 return self::applyModelOrConfig(self::prompt($prompt, $registry), $modelOrConfig); 463 } 464 /** 465 * Configures an EmbeddingBuilder with the required model and optional configuration. 466 * 467 * @param EmbeddingInput|list<EmbeddingInput> $input The input(s) to embed. 468 * @param mixed $model The model to use, expected to be a ModelInterface instance or a 469 * ProviderModelTuple; any other value is rejected. 470 * @param ModelConfig|null $modelConfig Optional model configuration to apply. 471 * @param ProviderRegistry|null $registry Optional custom registry to use. 472 * @return EmbeddingBuilder Configured embedding builder. 473 * @throws InvalidArgumentException If the model parameter is not of a supported type. 474 */ 475 private static function getConfiguredEmbeddingBuilder($input, $model, ?ModelConfig $modelConfig = null, ?ProviderRegistry $registry = null): EmbeddingBuilder 476 { 477 $builder = self::input($input, $registry); 478 // The builder's configuration takes precedence over the model's own configuration. 479 if ($modelConfig !== null) { 480 $builder->usingModelConfig($modelConfig); 481 } 482 if ($model instanceof ModelInterface) { 483 return $builder->usingModel($model); 484 } 485 if (is_array($model) && array_is_list($model) && count($model) === 2 && is_string($model[0]) && is_string($model[1])) { 486 return $builder->usingProviderModel($model[0], $model[1]); 487 } 488 throw new InvalidArgumentException('Model must be a ModelInterface instance or a [provider ID, model ID] tuple. ' . 'Embeddings are only comparable to other embeddings from the same model, so a model ' . 'is required. ' . sprintf('Received: %s', is_object($model) ? get_class($model) : gettype($model))); 489 } 490 /** 491 * Applies a model or model configuration to a builder. 492 * 493 * Works with any builder that exposes the shared model resolution methods 494 * (see {@see \WordPress\AiClient\Builders\Traits\ModelResolutionTrait}). 495 * 496 * @template T of PromptBuilder 497 * 498 * @param T $builder The builder to configure. 499 * @param ModelInterface|ModelConfig|null $modelOrConfig Specific model, model configuration, 500 * or null for default discovery. 501 * @return T The configured builder. 502 */ 503 private static function applyModelOrConfig($builder, $modelOrConfig) 504 { 505 if ($modelOrConfig instanceof ModelInterface) { 506 $builder->usingModel($modelOrConfig); 507 } elseif ($modelOrConfig instanceof ModelConfig) { 508 $builder->usingModelConfig($modelOrConfig); 509 } 510 // null case: use default model discovery 511 return $builder; 512 } 513 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sun Nov 1 08:20:35 2026 | Cross-referenced by PHPXref |