feat: extend model picker to image model (Cloudflare FLUX)
Apply the same interactive model picker UI to the image model field. Since Cloudflare models don't come from OpenRouter's registry, the two FLUX models are embedded as static data in the page config and the JS popup renders cost-per-image instead of token pricing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -80,6 +80,33 @@ class PRAutoBlogger_Admin_Page {
|
||||
'generateText' => __( 'Generate Now', 'prautoblogger' ),
|
||||
'testingText' => __( 'Testing...', 'prautoblogger' ),
|
||||
'testText' => __( 'Test Connections', 'prautoblogger' ),
|
||||
// Static Cloudflare image models for the picker (no registry API for these).
|
||||
'cloudflareModels' => [
|
||||
[
|
||||
'id' => 'flux-1-schnell',
|
||||
'name' => 'FLUX.1 [schnell]',
|
||||
'provider' => 'cloudflare',
|
||||
'context_length' => 0,
|
||||
'input_price_per_m' => 0,
|
||||
'output_price_per_m' => 0,
|
||||
'cost_per_image' => 0.0007,
|
||||
'capabilities' => [ 'cloudflare_image' ],
|
||||
'deprecated' => false,
|
||||
'description' => __( 'Fast + cheap (4 steps). Default choice.', 'prautoblogger' ),
|
||||
],
|
||||
[
|
||||
'id' => 'flux-1-dev',
|
||||
'name' => 'FLUX.1 [dev]',
|
||||
'provider' => 'cloudflare',
|
||||
'context_length' => 0,
|
||||
'input_price_per_m' => 0,
|
||||
'output_price_per_m' => 0,
|
||||
'cost_per_image' => 0.0028,
|
||||
'capabilities' => [ 'cloudflare_image' ],
|
||||
'deprecated' => false,
|
||||
'description' => __( 'Higher quality (20 steps), ~4× cost.', 'prautoblogger' ),
|
||||
],
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
|
||||
@@ -134,13 +134,10 @@ class PRAutoBlogger_Settings_Fields_Extended {
|
||||
[
|
||||
'id' => 'prautoblogger_image_model',
|
||||
'label' => __( 'Image Model', 'prautoblogger' ),
|
||||
'type' => 'select',
|
||||
'type' => 'model_select',
|
||||
'section' => 'prautoblogger_images',
|
||||
'default' => PRAUTOBLOGGER_DEFAULT_IMAGE_MODEL,
|
||||
'options' => [
|
||||
'flux-1-schnell' => __( 'FLUX.1 [schnell] — fast + cheap (default)', 'prautoblogger' ),
|
||||
'flux-1-dev' => __( 'FLUX.1 [dev] — higher quality, ~4× cost', 'prautoblogger' ),
|
||||
],
|
||||
'capability' => 'cloudflare_image',
|
||||
'description' => __( 'Schnell is the normal choice. Switch to [dev] for higher quality.', 'prautoblogger' ),
|
||||
'badge' => __( 'Low cost', 'prautoblogger' ),
|
||||
],
|
||||
|
||||
@@ -23,19 +23,51 @@ class PRAutoBlogger_OpenRouter_Model_Field {
|
||||
* @param string $value Current model id (e.g. 'google/gemini-2.5-flash-lite').
|
||||
* @param array<string, mixed> $args Field definition from settings fields.
|
||||
*/
|
||||
/**
|
||||
* Static Cloudflare Workers AI model definitions.
|
||||
*
|
||||
* These don't come from an API registry — Cloudflare has only two FLUX
|
||||
* models and pricing is stable. Costs are per-image at 1024×632 (default).
|
||||
*
|
||||
* @var array<string, array{name: string, cost_per_image: string}>
|
||||
*/
|
||||
private const CLOUDFLARE_MODELS = [
|
||||
'flux-1-schnell' => [
|
||||
'name' => 'FLUX.1 [schnell]',
|
||||
'provider' => 'Cloudflare',
|
||||
'cost_per_image' => '$0.0007',
|
||||
'description' => 'Fast + cheap, 4 inference steps',
|
||||
],
|
||||
'flux-1-dev' => [
|
||||
'name' => 'FLUX.1 [dev]',
|
||||
'provider' => 'Cloudflare',
|
||||
'cost_per_image' => '$0.0028',
|
||||
'description' => 'Higher quality, ~4× cost, 20 steps',
|
||||
],
|
||||
];
|
||||
|
||||
public static function render( string $id, string $value, array $args ): void {
|
||||
$capability = $args['capability'] ?? 'text→text';
|
||||
$display_name = $value ?: __( '— Select a model —', 'prautoblogger' );
|
||||
$display_price = '';
|
||||
|
||||
// Try to resolve display name + price from the cached registry.
|
||||
$registry = prautoblogger()->get_executor()->get_model_registry();
|
||||
$model = $registry->find_model( $value );
|
||||
if ( null !== $model ) {
|
||||
$display_name = $model['name'] ?? $value;
|
||||
$in = (float) ( $model['input_price_per_m'] ?? 0 );
|
||||
$out = (float) ( $model['output_price_per_m'] ?? 0 );
|
||||
$display_price = self::format_price( $in ) . ' / ' . self::format_price( $out );
|
||||
if ( 'cloudflare_image' === $capability ) {
|
||||
// Resolve from static Cloudflare model list.
|
||||
$cf_model = self::CLOUDFLARE_MODELS[ $value ] ?? null;
|
||||
if ( null !== $cf_model ) {
|
||||
$display_name = $cf_model['name'];
|
||||
$display_price = $cf_model['cost_per_image'] . '/image';
|
||||
}
|
||||
} else {
|
||||
// Resolve from the OpenRouter model registry cache.
|
||||
$registry = prautoblogger()->get_executor()->get_model_registry();
|
||||
$model = $registry->find_model( $value );
|
||||
if ( null !== $model ) {
|
||||
$display_name = $model['name'] ?? $value;
|
||||
$in = (float) ( $model['input_price_per_m'] ?? 0 );
|
||||
$out = (float) ( $model['output_price_per_m'] ?? 0 );
|
||||
$display_price = self::format_price( $in ) . ' / ' . self::format_price( $out );
|
||||
}
|
||||
}
|
||||
|
||||
// Hidden input carries the actual value for the form submission.
|
||||
|
||||
Reference in New Issue
Block a user