[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/php-ai-client/src/ -> AiClient.php (source)

   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\PromptBuilder;
   9  use WordPress\AiClient\Common\Exception\InvalidArgumentException;
  10  use WordPress\AiClient\Common\Exception\RuntimeException;
  11  use WordPress\AiClient\Providers\Contracts\ProviderAvailabilityInterface;
  12  use WordPress\AiClient\Providers\Contracts\ProviderInterface;
  13  use WordPress\AiClient\Providers\Models\Contracts\ModelInterface;
  14  use WordPress\AiClient\Providers\Models\DTO\ModelConfig;
  15  use WordPress\AiClient\Providers\ProviderRegistry;
  16  use WordPress\AiClient\Results\DTO\GenerativeAiResult;
  17  /**
  18   * Main AI Client class providing both fluent and traditional APIs for AI operations.
  19   *
  20   * This class serves as the primary entry point for AI operations, offering:
  21   * - Fluent API for easy-to-read chained method calls
  22   * - Traditional API for array-based configuration (WordPress style)
  23   * - Integration with provider registry for model discovery
  24   * - Support for three model specification approaches
  25   *
  26   * All model requirements analysis and capability matching is handled
  27   * automatically by the PromptBuilder, which provides intelligent model
  28   * discovery based on prompt content and configuration.
  29   *
  30   * ## Model Specification Approaches
  31   *
  32   * ### 1. Specific Model Instance
  33   * Use a specific ModelInterface instance when you know exactly which model to use:
  34   * ```php
  35   * $model = $registry->getProvider('openai')->getModel('gpt-4');
  36   * $result = AiClient::generateTextResult('What is PHP?', $model);
  37   * ```
  38   *
  39   * ### 2. ModelConfig for Auto-Discovery
  40   * Use ModelConfig to specify requirements and let the system discover the best model:
  41   * ```php
  42   * $config = new ModelConfig();
  43   * $config->setTemperature(0.7);
  44   * $config->setMaxTokens(150);
  45   *
  46   * $result = AiClient::generateTextResult('What is PHP?', $config);
  47   * ```
  48   *
  49   * ### 3. Automatic Discovery (Default)
  50   * Pass null or omit the parameter for intelligent model discovery based on prompt content:
  51   * ```php
  52   * // System analyzes prompt and selects appropriate model automatically
  53   * $result = AiClient::generateTextResult('What is PHP?');
  54   * $imageResult = AiClient::generateImageResult('A sunset over mountains');
  55   * ```
  56   *
  57   * ## Fluent API Examples
  58   * ```php
  59   * // Fluent API with automatic model discovery
  60   * $result = AiClient::prompt('Generate an image of a sunset')
  61   *     ->usingTemperature(0.7)
  62   *     ->generateImageResult();
  63   *
  64   * // Fluent API with specific model
  65   * $result = AiClient::prompt('What is PHP?')
  66   *     ->usingModel($specificModel)
  67   *     ->usingTemperature(0.5)
  68   *     ->generateTextResult();
  69   *
  70   * // Fluent API with model configuration
  71   * $result = AiClient::prompt('Explain quantum physics')
  72   *     ->usingModelConfig($config)
  73   *     ->generateTextResult();
  74   * ```
  75   *
  76   * @since 0.1.0
  77   *
  78   * @phpstan-import-type Prompt from PromptBuilder
  79   *
  80   * phpcs:ignore Generic.Files.LineLength.TooLong
  81   */
  82  class AiClient
  83  {
  84      /**
  85       * @var string The version of the AI Client.
  86       */
  87      public const VERSION = '1.3.1';
  88      /**
  89       * @var ProviderRegistry|null The default provider registry instance.
  90       */
  91      private static ?ProviderRegistry $defaultRegistry = null;
  92      /**
  93       * @var EventDispatcherInterface|null The event dispatcher for prompt lifecycle events.
  94       */
  95      private static ?EventDispatcherInterface $eventDispatcher = null;
  96      /**
  97       * @var CacheInterface|null The PSR-16 cache for storing and retrieving cached data.
  98       */
  99      private static ?CacheInterface $cache = null;
 100      /**
 101       * Gets the default provider registry instance.
 102       *
 103       * @since 0.1.0
 104       *
 105       * @return ProviderRegistry The default provider registry.
 106       */
 107      public static function defaultRegistry(): ProviderRegistry
 108      {
 109          if (self::$defaultRegistry === null) {
 110              self::$defaultRegistry = new ProviderRegistry();
 111          }
 112          return self::$defaultRegistry;
 113      }
 114      /**
 115       * Sets the event dispatcher for prompt lifecycle events.
 116       *
 117       * The event dispatcher will be used to dispatch BeforeGenerateResultEvent and
 118       * AfterGenerateResultEvent during prompt generation.
 119       *
 120       * @since 0.4.0
 121       *
 122       * @param EventDispatcherInterface|null $dispatcher The event dispatcher, or null to disable.
 123       * @return void
 124       */
 125      public static function setEventDispatcher(?EventDispatcherInterface $dispatcher): void
 126      {
 127          self::$eventDispatcher = $dispatcher;
 128      }
 129      /**
 130       * Gets the event dispatcher for prompt lifecycle events.
 131       *
 132       * @since 0.4.0
 133       *
 134       * @return EventDispatcherInterface|null The event dispatcher, or null if not set.
 135       */
 136      public static function getEventDispatcher(): ?EventDispatcherInterface
 137      {
 138          return self::$eventDispatcher;
 139      }
 140      /**
 141       * Sets the PSR-16 cache for storing and retrieving cached data.
 142       *
 143       * The cache can be used to store AI responses and other data to avoid
 144       * redundant API calls and improve performance.
 145       *
 146       * @since 0.4.0
 147       *
 148       * @param CacheInterface|null $cache The PSR-16 cache instance, or null to disable caching.
 149       * @return void
 150       */
 151      public static function setCache(?CacheInterface $cache): void
 152      {
 153          self::$cache = $cache;
 154      }
 155      /**
 156       * Gets the PSR-16 cache instance.
 157       *
 158       * @since 0.4.0
 159       *
 160       * @return CacheInterface|null The cache instance, or null if not set.
 161       */
 162      public static function getCache(): ?CacheInterface
 163      {
 164          return self::$cache;
 165      }
 166      /**
 167       * Checks if a provider is configured and available for use.
 168       *
 169       * Supports multiple input formats for developer convenience:
 170       * - ProviderAvailabilityInterface: Direct availability check
 171       * - string (provider ID): e.g., AiClient::isConfigured('openai')
 172       * - string (class name): e.g., AiClient::isConfigured(OpenAiProvider::class)
 173       *
 174       * When using string input, this method leverages the ProviderRegistry's centralized
 175       * dependency management, ensuring HttpTransporter and authentication are properly
 176       * injected into availability instances.
 177       *
 178       * @since 0.1.0
 179       * @since 0.2.0 Now supports being passed a provider ID or class name.
 180       *
 181       * @param ProviderAvailabilityInterface|string|class-string<ProviderInterface> $availabilityOrIdOrClassName
 182       *        The provider availability instance, provider ID, or provider class name.
 183       * @return bool True if the provider is configured and available, false otherwise.
 184       */
 185      public static function isConfigured($availabilityOrIdOrClassName): bool
 186      {
 187          // Handle direct ProviderAvailabilityInterface (backward compatibility)
 188          if ($availabilityOrIdOrClassName instanceof ProviderAvailabilityInterface) {
 189              return $availabilityOrIdOrClassName->isConfigured();
 190          }
 191          // Handle string input (provider ID or class name) via registry
 192          if (is_string($availabilityOrIdOrClassName)) {
 193              return self::defaultRegistry()->isProviderConfigured($availabilityOrIdOrClassName);
 194          }
 195          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)));
 196      }
 197      /**
 198       * Creates a new prompt builder for fluent API usage.
 199       *
 200       * Returns a PromptBuilder instance configured with the specified or default registry.
 201       * The traditional API methods in this class delegate to PromptBuilder
 202       * for all generation logic.
 203       *
 204       * @since 0.1.0
 205       *
 206       * @param Prompt $prompt Optional initial prompt content.
 207       * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default.
 208       * @return PromptBuilder The prompt builder instance.
 209       */
 210      public static function prompt($prompt = null, ?ProviderRegistry $registry = null): PromptBuilder
 211      {
 212          return new PromptBuilder($registry ?? self::defaultRegistry(), $prompt, self::$eventDispatcher);
 213      }
 214      /**
 215       * Generates content using a unified API that automatically detects model capabilities.
 216       *
 217       * When no model is provided, this method delegates to PromptBuilder for intelligent
 218       * model discovery based on prompt content and configuration. When a model is provided,
 219       * it infers the capability from the model's interfaces and delegates to the capability-based method.
 220       *
 221       * @since 0.1.0
 222       *
 223       * @param Prompt $prompt The prompt content.
 224       * @param ModelInterface|ModelConfig $modelOrConfig Specific model to use, or model configuration
 225       *                                                  for auto-discovery.
 226       * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default.
 227       * @return GenerativeAiResult The generation result.
 228       *
 229       * @throws \InvalidArgumentException If the provided model doesn't support any known generation type.
 230       * @throws \RuntimeException If no suitable model can be found for the prompt.
 231       */
 232      public static function generateResult($prompt, $modelOrConfig, ?ProviderRegistry $registry = null): GenerativeAiResult
 233      {
 234          self::validateModelOrConfigParameter($modelOrConfig);
 235          return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateResult();
 236      }
 237      /**
 238       * Generates text using the traditional API approach.
 239       *
 240       * @since 0.1.0
 241       *
 242       * @param Prompt $prompt The prompt content.
 243       * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use,
 244       *                                                        or model configuration for auto-discovery,
 245       *                                                        or null for defaults.
 246       * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default.
 247       * @return GenerativeAiResult The generation result.
 248       *
 249       * @throws \InvalidArgumentException If the prompt format is invalid.
 250       * @throws \RuntimeException If no suitable model is found.
 251       */
 252      public static function generateTextResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult
 253      {
 254          self::validateModelOrConfigParameter($modelOrConfig);
 255          return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateTextResult();
 256      }
 257      /**
 258       * Generates an image using the traditional API approach.
 259       *
 260       * @since 0.1.0
 261       *
 262       * @param Prompt $prompt The prompt content.
 263       * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use,
 264       *                                                        or model configuration for auto-discovery,
 265       *                                                        or null for defaults.
 266       * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default.
 267       * @return GenerativeAiResult The generation result.
 268       *
 269       * @throws \InvalidArgumentException If the prompt format is invalid.
 270       * @throws \RuntimeException If no suitable model is found.
 271       */
 272      public static function generateImageResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult
 273      {
 274          self::validateModelOrConfigParameter($modelOrConfig);
 275          return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateImageResult();
 276      }
 277      /**
 278       * Converts text to speech using the traditional API approach.
 279       *
 280       * @since 0.1.0
 281       *
 282       * @param Prompt $prompt The prompt content.
 283       * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use,
 284       *                                                        or model configuration for auto-discovery,
 285       *                                                        or null for defaults.
 286       * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default.
 287       * @return GenerativeAiResult The generation result.
 288       *
 289       * @throws \InvalidArgumentException If the prompt format is invalid.
 290       * @throws \RuntimeException If no suitable model is found.
 291       */
 292      public static function convertTextToSpeechResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult
 293      {
 294          self::validateModelOrConfigParameter($modelOrConfig);
 295          return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->convertTextToSpeechResult();
 296      }
 297      /**
 298       * Generates speech using the traditional API approach.
 299       *
 300       * @since 0.1.0
 301       *
 302       * @param Prompt $prompt The prompt content.
 303       * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use,
 304       *                                                        or model configuration for auto-discovery,
 305       *                                                        or null for defaults.
 306       * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default.
 307       * @return GenerativeAiResult The generation result.
 308       *
 309       * @throws \InvalidArgumentException If the prompt format is invalid.
 310       * @throws \RuntimeException If no suitable model is found.
 311       */
 312      public static function generateSpeechResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult
 313      {
 314          self::validateModelOrConfigParameter($modelOrConfig);
 315          return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateSpeechResult();
 316      }
 317      /**
 318       * Generates a video using the traditional API approach.
 319       *
 320       * @since 1.3.0
 321       *
 322       * @param Prompt $prompt The prompt content.
 323       * @param ModelInterface|ModelConfig|null $modelOrConfig Optional specific model to use,
 324       *                                                        or model configuration for auto-discovery,
 325       *                                                        or null for defaults.
 326       * @param ProviderRegistry|null $registry Optional custom registry. If null, uses default.
 327       * @return GenerativeAiResult The generation result.
 328       *
 329       * @throws \InvalidArgumentException If the prompt format is invalid.
 330       * @throws \RuntimeException If no suitable model is found.
 331       */
 332      public static function generateVideoResult($prompt, $modelOrConfig = null, ?ProviderRegistry $registry = null): GenerativeAiResult
 333      {
 334          self::validateModelOrConfigParameter($modelOrConfig);
 335          return self::getConfiguredPromptBuilder($prompt, $modelOrConfig, $registry)->generateVideoResult();
 336      }
 337      /**
 338       * Creates a new message builder for fluent API usage.
 339       *
 340       * This method will be implemented once MessageBuilder is available.
 341       * MessageBuilder will provide a fluent interface for constructing complex
 342       * messages with multiple parts, attachments, and metadata.
 343       *
 344       * @since 0.1.0
 345       *
 346       * @param string|null $text Optional initial message text.
 347       * @return object MessageBuilder instance (type will be updated when MessageBuilder is available).
 348       *
 349       * @throws \RuntimeException When MessageBuilder is not yet available.
 350       */
 351      public static function message(?string $text = null)
 352      {
 353          throw new RuntimeException('MessageBuilder is not yet available. This method depends on builder infrastructure. ' . 'Use direct generation methods (generateTextResult, generateImageResult, etc.) for now.');
 354      }
 355      /**
 356       * Validates that parameter is ModelInterface, ModelConfig, or null.
 357       *
 358       * @param mixed $modelOrConfig The parameter to validate.
 359       * @return void
 360       * @throws \InvalidArgumentException If parameter is invalid type.
 361       */
 362      private static function validateModelOrConfigParameter($modelOrConfig): void
 363      {
 364          if ($modelOrConfig !== null && !$modelOrConfig instanceof ModelInterface && !$modelOrConfig instanceof ModelConfig) {
 365              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)));
 366          }
 367      }
 368      /**
 369       * Configures PromptBuilder based on model/config parameter type.
 370       *
 371       * @param Prompt $prompt The prompt content.
 372       * @param ModelInterface|ModelConfig|null $modelOrConfig The model or config parameter.
 373       * @param ProviderRegistry|null $registry Optional custom registry to use.
 374       * @return PromptBuilder Configured prompt builder.
 375       */
 376      private static function getConfiguredPromptBuilder($prompt, $modelOrConfig, ?ProviderRegistry $registry = null): PromptBuilder
 377      {
 378          $builder = self::prompt($prompt, $registry);
 379          if ($modelOrConfig instanceof ModelInterface) {
 380              $builder->usingModel($modelOrConfig);
 381          } elseif ($modelOrConfig instanceof ModelConfig) {
 382              $builder->usingModelConfig($modelOrConfig);
 383          }
 384          // null case: use default model discovery
 385          return $builder;
 386      }
 387  }


Generated : Sat Jun 13 09:38:55 2026 Cross-referenced by PHPXref