mcp-core.php
1 day ago
mcp-oauth.php
1 month ago
mcp-rest.php
3 weeks ago
mcp.conf
1 year ago
mcp.js
8 months ago
mcp.md
8 months ago
mcp.php
1 week ago
wpai-connectors.php
2 months ago
wpai-gateway-availability.php
2 months ago
wpai-gateway-directory.php
2 months ago
wpai-gateway-image-model.php
2 months ago
wpai-gateway-model.php
2 months ago
wpai-gateway-providers.php
2 months ago
wpai-gateway.php
2 months ago
wpai-gateway-image-model.php
137 lines
| 1 | <?php |
| 2 | /** |
| 3 | * ImageGenerationModel for the AI Engine gateway. |
| 4 | * |
| 5 | * Routes AiClient image prompts through `Meow_MWAI_Query_Image` and wraps the |
| 6 | * resulting image URLs as `File` parts on a `ModelMessage` inside a |
| 7 | * `GenerativeAiResult`. |
| 8 | */ |
| 9 | |
| 10 | use WordPress\AiClient\Common\Exception\RuntimeException; |
| 11 | use WordPress\AiClient\Files\DTO\File; |
| 12 | use WordPress\AiClient\Messages\DTO\Message; |
| 13 | use WordPress\AiClient\Messages\DTO\MessagePart; |
| 14 | use WordPress\AiClient\Messages\DTO\ModelMessage; |
| 15 | use WordPress\AiClient\Providers\DTO\ProviderMetadata; |
| 16 | use WordPress\AiClient\Providers\Models\Contracts\ModelInterface; |
| 17 | use WordPress\AiClient\Providers\Models\DTO\ModelConfig; |
| 18 | use WordPress\AiClient\Providers\Models\DTO\ModelMetadata; |
| 19 | use WordPress\AiClient\Providers\Models\ImageGeneration\Contracts\ImageGenerationModelInterface; |
| 20 | use WordPress\AiClient\Results\DTO\Candidate; |
| 21 | use WordPress\AiClient\Results\DTO\GenerativeAiResult; |
| 22 | use WordPress\AiClient\Results\DTO\TokenUsage; |
| 23 | use WordPress\AiClient\Results\Enums\FinishReasonEnum; |
| 24 | |
| 25 | class Meow_MWAI_Labs_WPAI_Gateway_ImageModel implements ModelInterface, ImageGenerationModelInterface { |
| 26 | |
| 27 | private ModelMetadata $modelMetadata; |
| 28 | private ProviderMetadata $providerMetadata; |
| 29 | private ModelConfig $config; |
| 30 | |
| 31 | public function __construct( ModelMetadata $modelMetadata, ProviderMetadata $providerMetadata ) { |
| 32 | $this->modelMetadata = $modelMetadata; |
| 33 | $this->providerMetadata = $providerMetadata; |
| 34 | $this->config = new ModelConfig(); |
| 35 | } |
| 36 | |
| 37 | public function metadata(): ModelMetadata { return $this->modelMetadata; } |
| 38 | public function providerMetadata(): ProviderMetadata { return $this->providerMetadata; } |
| 39 | public function setConfig( ModelConfig $config ): void { $this->config = $config; } |
| 40 | public function getConfig(): ModelConfig { return $this->config; } |
| 41 | |
| 42 | public function generateImageResult( array $prompt ): GenerativeAiResult { |
| 43 | $core = Meow_MWAI_Labs_WPAI_Gateway::$core; |
| 44 | if ( ! $core ) { |
| 45 | throw new RuntimeException( 'AI Engine core unavailable.' ); |
| 46 | } |
| 47 | |
| 48 | $model_id = $this->modelMetadata->getId(); |
| 49 | $env = $this->resolve_env_for_model( $core, $model_id ); |
| 50 | if ( ! $env ) { |
| 51 | throw new RuntimeException( sprintf( |
| 52 | 'No AI Engine environment is configured for model "%s".', |
| 53 | $model_id |
| 54 | ) ); |
| 55 | } |
| 56 | |
| 57 | // Collapse all text parts across the prompt into a single image prompt. |
| 58 | $text = ''; |
| 59 | foreach ( $prompt as $msg ) { |
| 60 | if ( ! $msg instanceof Message ) { continue; } |
| 61 | foreach ( $msg->getParts() as $part ) { |
| 62 | if ( $part instanceof MessagePart && $part->getType()->isText() ) { |
| 63 | $text .= (string) $part->getText(); |
| 64 | } |
| 65 | } |
| 66 | } |
| 67 | if ( $text === '' ) { |
| 68 | throw new RuntimeException( 'Empty image prompt.' ); |
| 69 | } |
| 70 | |
| 71 | $query = new Meow_MWAI_Query_Image( $text ); |
| 72 | $query->set_scope( 'wp-ai-client' ); |
| 73 | $query->set_env_id( $env['id'] ); |
| 74 | $query->set_model( $model_id ); |
| 75 | |
| 76 | $reply = $core->run_query( $query ); |
| 77 | |
| 78 | // AI Engine places generated images in $reply->results as a list of URLs. |
| 79 | // Fall back to $reply->result if results is empty. |
| 80 | $urls = []; |
| 81 | if ( ! empty( $reply->results ) && is_array( $reply->results ) ) { |
| 82 | foreach ( $reply->results as $u ) { |
| 83 | if ( is_string( $u ) && $u !== '' ) { |
| 84 | $urls[] = $u; |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 | if ( empty( $urls ) && ! empty( $reply->result ) ) { |
| 89 | $urls[] = (string) $reply->result; |
| 90 | } |
| 91 | if ( empty( $urls ) ) { |
| 92 | throw new RuntimeException( 'Image generation returned no URLs.' ); |
| 93 | } |
| 94 | |
| 95 | $candidates = []; |
| 96 | foreach ( $urls as $url ) { |
| 97 | $file = new File( $url ); |
| 98 | $part = new MessagePart( $file ); |
| 99 | $message = new ModelMessage( [ $part ] ); |
| 100 | $candidates[] = new Candidate( $message, FinishReasonEnum::stop() ); |
| 101 | } |
| 102 | |
| 103 | $tokens = new TokenUsage( 0, 0, 0 ); |
| 104 | $id = (string) ( $reply->id ?? uniqid( 'mwai-img-', true ) ); |
| 105 | return new GenerativeAiResult( |
| 106 | $id, |
| 107 | $candidates, |
| 108 | $tokens, |
| 109 | $this->providerMetadata, |
| 110 | $this->modelMetadata |
| 111 | ); |
| 112 | } |
| 113 | |
| 114 | private function resolve_env_for_model( $core, string $model_id ): ?array { |
| 115 | $options = $core->get_all_options(); |
| 116 | $engines = $options['ai_engines'] ?? []; |
| 117 | $engine_type_for_model = null; |
| 118 | foreach ( $engines as $engine ) { |
| 119 | foreach ( $engine['models'] ?? [] as $m ) { |
| 120 | if ( ( $m['model'] ?? '' ) === $model_id ) { |
| 121 | $engine_type_for_model = $engine['type'] ?? null; |
| 122 | break 2; |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | if ( ! $engine_type_for_model ) { |
| 127 | return null; |
| 128 | } |
| 129 | foreach ( $options['ai_envs'] ?? [] as $env ) { |
| 130 | if ( ( $env['type'] ?? '' ) === $engine_type_for_model ) { |
| 131 | return $env; |
| 132 | } |
| 133 | } |
| 134 | return null; |
| 135 | } |
| 136 | } |
| 137 |