HEX
Server: Apache/2.4.65 (Debian)
System: Linux 88f31f35b0b8 6.1.0-38-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.147-1 (2025-08-02) x86_64
User: www-data (33)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: /var/www/html/wp-content/plugins/ai-engine/classes/query/image.php
<?php

class Meow_MWAI_Query_Image extends Meow_MWAI_Query_Base {
  public ?string $resolution = null;
  public ?string $quality = null;
  public ?string $style = null;
  public ?string $localDownload = 'uploads';
  public ?string $localDownloadExpiry = 'uploads';
  public ?array $attachedFiles = null;

  #region Constructors, Serialization

  public function __construct( ?string $message = '', ?string $model = null ) {
    parent::__construct( $message );
    $this->model = $model;
    $this->feature = 'text-to-image'; // image-to-image, inpainting, etc
    global $mwai_core;
    $this->localDownload = $mwai_core->get_option( 'image_local_download' );
    $this->localDownloadExpiry = $mwai_core->get_option( 'image_expires_download' );
  }

  #[\ReturnTypeWillChange]
  public function jsonSerialize(): array {
    $json = [
      'message' => $this->message,

      'ai' => [
        'model' => $this->model,
        'feature' => $this->feature,
        'resolution' => $this->resolution,
        'quality' => $this->quality
      ],

      'system' => [
        'class' => get_class( $this ),
        'envId' => $this->envId,
        'scope' => $this->scope,
        'session' => $this->session,
        'customId' => $this->customId,
      ]
    ];

    if ( !empty( $this->context ) ) {
      $json['context']['content'] = $this->context;
    }

    return $json;
  }

  #endregion

  #region Parameters

  public function set_resolution( string $resolution ) {
    $this->resolution = $resolution;
  }

  public function set_quality( ?string $quality ) {
    $this->quality = $quality !== null && $quality !== '' ? $quality : null;
  }

  public function set_style( string $style ) {
    $this->style = $style;
  }

  /**
  * Set how the image will be treated locally, if it will be downloaded or not, etc.
  * @param string $localDownload The local download method. Could be 'uploads', 'library' or null.
  */
  public function set_local_download( ?string $localDownload ) {
    $this->localDownload = $localDownload;
  }

  public function add_file( Meow_MWAI_Query_DroppedFile $file ): void {
    if ( $this->attachedFiles === null ) {
      $this->attachedFiles = [];
    }
    $this->attachedFiles[] = $file;
  }

  public function set_files( array $files ): void {
    $this->attachedFiles = $files;
  }

  public function get_files(): ?array {
    return $this->attachedFiles;
  }

  public function getAttachments(): array {
    return $this->attachedFiles ?? [];
  }

  // Based on the params of the query, update the attributes
  public function inject_params( array $params ): void {
    parent::inject_params( $params );
    $params = $this->convert_keys( $params );

    if ( !empty( $params['resolution'] ) ) {
      $this->set_resolution( $params['resolution'] );
    }
    if ( array_key_exists( 'quality', $params ) ) {
      $this->set_quality( $params['quality'] );
    }
    if ( !empty( $params['style'] ) ) {
      $this->set_style( $params['style'] );
    }
    // Check both camelCase and snake_case versions for compatibility
    if ( array_key_exists( 'localDownload', $params ) ) {
      $this->set_local_download( $params['localDownload'] );
    }
    elseif ( array_key_exists( 'local_download', $params ) ) {
      $this->set_local_download( $params['local_download'] );
    }
  }

  #endregion

  #region Final Checks

  public function final_checks() {
    parent::final_checks();

    // Force a single image per request (matches the supported behavior of current image models).
    $this->maxResults = 1;

    global $mwai_core;

    $engine = Meow_MWAI_Engines_Factory::get( $mwai_core, $this->envId );

    // If model is empty, use the image-specific default model (not the general default)
    if ( empty( $this->model ) ) {
      $this->model = $mwai_core->get_option( 'ai_images_default_model' );
      if ( empty( $this->model ) ) {
        // Fallback to general default if image-specific default is not set
        $this->model = $mwai_core->get_option( 'ai_default_model' );
      }
    }

    $modelInfo = $engine->retrieve_model_info( $this->model );
    if ( empty( $modelInfo ) ) {
      Meow_MWAI_Logging::error( 'No model info found for model: ' . $this->model, '🖼️' );
      return;
    }

    // Let's check for resolutions.
    if ( !isset( $modelInfo['resolutions'] ) || empty( $modelInfo['resolutions'] ) ) {
      // Skip warning for non-image models (e.g., when using image_generation as a tool)
      return;
    }

    // If we have no resolution set, we will use the first one
    if ( empty( $this->resolution ) ) {
      $this->resolution = $modelInfo['resolutions'][0]['name'];
    }

    // If we have a resolutions array ([ name, label ]), let's ensure our current resolution (name) is supported
    $resolutions = $modelInfo['resolutions'];
    $found = false;
    foreach ( $resolutions as $resolution ) {
      if ( $resolution['name'] === $this->resolution ) {
        $found = true;
        break;
      }
    }

    // If we don't find the resolution, we will set it to the first one.
    if ( !$found ) {
      $supportedResolutions = [];
      foreach ( $resolutions as $resolution ) {
        $supportedResolutions[] = $resolution['name'];
      }
      $supportedResolutions = implode( ', ', $supportedResolutions );
      $error = sprintf( 'The model %s does not support the resolution %s (using %s instead). Supported resolutions are: %s.', $this->model, $this->resolution, $resolutions[0]['name'], $supportedResolutions );
      $this->resolution = $resolutions[0]['name'];
      Meow_MWAI_Logging::error( $error, '🖼️' );
    }

    // Quality: only validate when the model declares supported qualities. Otherwise leave it as-is
    // (null means "do not send the quality param to the API"; the provider picks its default).
    if ( !empty( $modelInfo['qualities'] ) && empty( $this->quality ) ) {
      // Fall back to the global default. If the saved default is not supported by the active
      // model (e.g. user switched from GPT Image to a model with different vocabulary), the
      // validation block below will silently reset it to the model's first declared quality.
      $defaultQuality = $mwai_core->get_option( 'ai_images_default_quality' );
      if ( !empty( $defaultQuality ) ) {
        $this->quality = $defaultQuality;
      }
    }
    if ( !empty( $modelInfo['qualities'] ) && !empty( $this->quality ) ) {
      $qualities = $modelInfo['qualities'];
      $foundQuality = false;
      foreach ( $qualities as $quality ) {
        if ( $quality['name'] === $this->quality ) {
          $foundQuality = true;
          break;
        }
      }
      if ( !$foundQuality ) {
        $supportedQualities = [];
        foreach ( $qualities as $quality ) {
          $supportedQualities[] = $quality['name'];
        }
        $supportedQualities = implode( ', ', $supportedQualities );
        $error = sprintf( 'The model %s does not support the quality %s (using %s instead). Supported qualities are: %s.', $this->model, $this->quality, $qualities[0]['name'], $supportedQualities );
        $this->quality = $qualities[0]['name'];
        Meow_MWAI_Logging::error( $error, '🖼️' );
      }
    }
  }

  #endregion
}