cf-removal: patch registry, pipeline, settings, admin-page, interface
Wires out the Cloudflare Workers AI image provider across the plugin: - class-image-pipeline.php: drop 'cloudflare' dispatch branch; Runware becomes the unrecognised-provider fallback - class-image-model-registry.php: remove flux-1-schnell/cloudflare row; update provider-enum docblocks (runware|openrouter only) - class-settings-fields-extended.php: remove three CF fields (cloudflare_ai_token, cloudflare_account_id, cf_image_via_gateway); drop Cloudflare mention from model-picker + NSFW retry descriptions - class-admin-page.php: remove prautoblogger_cloudflare_ai_token from the encrypted-options list - interface-image-provider.php: retarget preamble @see at Runware + OpenRouter; update get_provider_name() example - class-image-nsfw-blocked.php: generalise preamble (Runware + OpenRouter can raise this) Also cleans stale CF Workers AI mentions in: class-ajax-handlers.php, interface-model-registry.php, class-image-nsfw-retry.php, class-open-router-image-pricing.php, prautoblogger.php. The Cloudflare AI Gateway path (in class-open-router-config.php, class-settings-fields.php 'prautoblogger_ai_gateway_base_url', class-open-router-request-builder.php cache headers) is intentionally untouched — it fronts OpenRouter and is unrelated to the CF Workers AI image provider.
This commit is contained in:
@@ -231,7 +231,7 @@ class PRAutoBlogger_Admin_Page {
|
||||
$option_name = substr( $filter, strlen( 'sanitize_option_' ) );
|
||||
}
|
||||
|
||||
$encrypted = [ 'prautoblogger_openrouter_api_key', 'prautoblogger_ga4_credentials_json', 'prautoblogger_cloudflare_ai_token', 'prautoblogger_runware_api_key' ];
|
||||
$encrypted = [ 'prautoblogger_openrouter_api_key', 'prautoblogger_ga4_credentials_json', 'prautoblogger_runware_api_key' ];
|
||||
if ( in_array( $option_name, $encrypted, true ) ) {
|
||||
// Empty value means password field wasn't touched — keep existing.
|
||||
if ( '' === $value ) {
|
||||
|
||||
@@ -22,7 +22,7 @@ class PRAutoBlogger_Image_Model_Registry {
|
||||
* Each entry contains:
|
||||
* - id: Model identifier used in API calls.
|
||||
* - name: Human-readable display name.
|
||||
* - provider: 'runware' | 'openrouter' | 'cloudflare'.
|
||||
* - provider: 'runware' | 'openrouter'.
|
||||
* - cost_per_image: Estimated USD cost per generation.
|
||||
* - capabilities: Array of capability tags.
|
||||
* - description: Short description for the admin UI.
|
||||
@@ -90,14 +90,6 @@ class PRAutoBlogger_Image_Model_Registry {
|
||||
'capabilities' => [ 'image_generation' ],
|
||||
'description' => __( 'OpenAI premium. Photorealistic.', 'prautoblogger' ),
|
||||
],
|
||||
[
|
||||
'id' => 'flux-1-schnell',
|
||||
'name' => 'FLUX.1 schnell (Cloudflare)',
|
||||
'provider' => 'cloudflare',
|
||||
'cost_per_image' => 0.0007,
|
||||
'capabilities' => [ 'image_generation' ],
|
||||
'description' => __( 'Legacy Cloudflare fallback. Use Runware FLUX instead.', 'prautoblogger' ),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -106,7 +98,7 @@ class PRAutoBlogger_Image_Model_Registry {
|
||||
* model id is not in the registry.
|
||||
*
|
||||
* @param string $model_id Model slug from the admin UI.
|
||||
* @return string Provider id ('runware' | 'openrouter' | 'cloudflare' | '').
|
||||
* @return string Provider id ('runware' | 'openrouter' | '').
|
||||
*/
|
||||
public static function provider_for( string $model_id ): string {
|
||||
foreach ( self::get_models() as $model ) {
|
||||
|
||||
@@ -221,25 +221,9 @@ class PRAutoBlogger_Settings_Fields_Extended {
|
||||
'section' => 'prautoblogger_images',
|
||||
'default' => PRAUTOBLOGGER_DEFAULT_IMAGE_MODEL,
|
||||
'capability' => 'image_generation',
|
||||
'description' => __( 'Pick an image model. The provider (OpenRouter or Cloudflare Workers AI) is derived from the model registry on save, so mismatched pairs are no longer possible.', 'prautoblogger' ),
|
||||
'description' => __( 'Pick an image model. The provider (Runware or OpenRouter) is derived from the model registry on save, so mismatched pairs are no longer possible.', 'prautoblogger' ),
|
||||
'badge' => __( 'Quality', 'prautoblogger' ),
|
||||
],
|
||||
[
|
||||
'id' => 'prautoblogger_cloudflare_ai_token',
|
||||
'label' => __( 'Cloudflare API Token', 'prautoblogger' ),
|
||||
'type' => 'password',
|
||||
'section' => 'prautoblogger_images',
|
||||
'description' => __( 'Only needed if using Cloudflare provider. Workers AI token with Read + Edit scope.', 'prautoblogger' ),
|
||||
'icon' => '🔑',
|
||||
],
|
||||
[
|
||||
'id' => 'prautoblogger_cloudflare_account_id',
|
||||
'label' => __( 'Cloudflare Account ID', 'prautoblogger' ),
|
||||
'type' => 'text',
|
||||
'section' => 'prautoblogger_images',
|
||||
'default' => '',
|
||||
'description' => __( 'Only needed if using Cloudflare provider.', 'prautoblogger' ),
|
||||
],
|
||||
[
|
||||
'id' => 'prautoblogger_runware_api_key',
|
||||
'label' => __( 'Runware API Key', 'prautoblogger' ),
|
||||
@@ -270,15 +254,7 @@ class PRAutoBlogger_Settings_Fields_Extended {
|
||||
'type' => 'toggle',
|
||||
'section' => 'prautoblogger_images',
|
||||
'default' => '1',
|
||||
'description' => __( 'When the provider rejects an image prompt as NSFW (e.g. Cloudflare code 3030), retry once with a generic fallback scene built from the article title. Disable to fail fast if the filter gets trigger-happy.', 'prautoblogger' ),
|
||||
],
|
||||
[
|
||||
'id' => 'prautoblogger_cf_image_via_gateway',
|
||||
'label' => __( 'Route Cloudflare Images via AI Gateway', 'prautoblogger' ),
|
||||
'type' => 'toggle',
|
||||
'section' => 'prautoblogger_images',
|
||||
'default' => '1',
|
||||
'description' => __( 'Route Cloudflare Workers AI image calls through the Cloudflare AI Gateway (requires the AI Gateway URL configured under API Keys). Adds response caching, cost logging, and rate-limiting. Turn off to hit the direct Workers AI API — only needed if the gateway route regresses.', 'prautoblogger' ),
|
||||
'description' => __( 'When the provider rejects an image prompt as NSFW, retry once with a generic fallback scene built from the article title. Disable to fail fast if the filter gets trigger-happy.', 'prautoblogger' ),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class PRAutoBlogger_Ajax_Handlers {
|
||||
return;
|
||||
}
|
||||
|
||||
// Image generation can take 20-30s on Cloudflare Workers AI.
|
||||
// Image generation can take 20-30s (Runware FLUX + OpenRouter image models).
|
||||
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
|
||||
@set_time_limit( 120 );
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
/**
|
||||
* Single-shot retry of NSFW-blocked image slots with a sanitized prompt.
|
||||
*
|
||||
* When an image provider (currently only Cloudflare Workers AI) rejects a
|
||||
* prompt via its content filter, its batch result carries
|
||||
* When an image provider rejects a prompt via its content filter, its
|
||||
* batch result carries
|
||||
* `['error_type' => 'nsfw_blocked']`. This helper reruns just the blocked
|
||||
* slot once with the rule-based fallback prompt (article title + style
|
||||
* suffix, no LLM rewrite) and merges the new result back into the batch.
|
||||
|
||||
@@ -38,7 +38,7 @@ class PRAutoBlogger_Image_Pipeline {
|
||||
*
|
||||
* When no provider is injected, the constructor reads the
|
||||
* `prautoblogger_image_provider` setting and instantiates the
|
||||
* matching concrete class ('runware', 'openrouter', or 'cloudflare').
|
||||
* matching concrete class ('runware' or 'openrouter').
|
||||
*
|
||||
* @param PRAutoBlogger_Image_Provider_Interface|null $provider Optional provider override.
|
||||
* @param PRAutoBlogger_Cost_Tracker|null $cost_tracker Optional cost tracker.
|
||||
@@ -56,17 +56,19 @@ class PRAutoBlogger_Image_Pipeline {
|
||||
/**
|
||||
* Instantiate the image provider based on the admin setting.
|
||||
*
|
||||
* Returns Runware by default when the setting is unrecognised —
|
||||
* Cloudflare Workers AI was removed as a provider in v0.10.0; legacy
|
||||
* 'cloudflare' values are migrated at admin_init, but an unmigrated
|
||||
* install should still get a working fallback rather than a fatal.
|
||||
*
|
||||
* @return PRAutoBlogger_Image_Provider_Interface
|
||||
*/
|
||||
private static function create_default_provider(): PRAutoBlogger_Image_Provider_Interface {
|
||||
$provider_id = (string) get_option( 'prautoblogger_image_provider', PRAUTOBLOGGER_DEFAULT_IMAGE_PROVIDER );
|
||||
if ( 'runware' === $provider_id ) {
|
||||
return new PRAutoBlogger_Runware_Image_Provider();
|
||||
}
|
||||
if ( 'openrouter' === $provider_id ) {
|
||||
return new PRAutoBlogger_OpenRouter_Image_Provider();
|
||||
}
|
||||
return new PRAutoBlogger_Cloudflare_Image_Provider();
|
||||
return new PRAutoBlogger_Runware_Image_Provider();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,18 +4,18 @@ declare(strict_types=1);
|
||||
/**
|
||||
* Exception raised when an image provider rejects a prompt as NSFW.
|
||||
*
|
||||
* Cloudflare Workers AI returns HTTP 400 with an `errors[].code === 3030`
|
||||
* body when its content filter blocks a prompt. We catch that shape in
|
||||
* the provider and raise this typed exception so the image pipeline can
|
||||
* distinguish a content-filter rejection from a generic 4xx and retry
|
||||
* once with a sanitized fallback prompt.
|
||||
* Image providers (Runware, OpenRouter) return provider-specific error
|
||||
* shapes when their content filters block a prompt. We catch those shapes
|
||||
* in each provider and raise this typed exception so the image pipeline
|
||||
* can distinguish a content-filter rejection from a generic 4xx and
|
||||
* retry once with a sanitized fallback prompt.
|
||||
*
|
||||
* Triggered by: PRAutoBlogger_Cloudflare_Image_Provider on NSFW 4xx.
|
||||
* Triggered by: image providers on NSFW-filter rejection.
|
||||
* Dependencies: None.
|
||||
*
|
||||
* @see providers/class-cloudflare-image-provider.php — Raises this.
|
||||
* @see core/class-image-nsfw-retry.php — Catches + rebuilds prompt.
|
||||
* @see https://developers.cloudflare.com/workers-ai/models/flux-1-schnell/ — Upstream error codes.
|
||||
* @see providers/class-runware-image-provider.php — May raise this.
|
||||
* @see providers/class-open-router-image-provider.php — May raise this.
|
||||
* @see core/class-image-nsfw-retry.php — Catches + rebuilds prompt.
|
||||
*/
|
||||
class PRAutoBlogger_Image_NSFW_Blocked extends \RuntimeException {
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
/**
|
||||
* Pricing + model-id resolution helpers for the OpenRouter image provider.
|
||||
*
|
||||
* Mirrors the Cloudflare pricing helper pattern. Each model's cost per image
|
||||
* Mirrors the Runware pricing helper pattern. Each model's cost per image
|
||||
* is a flat rate sourced from OpenRouter's pricing page (April 2026).
|
||||
*
|
||||
* Triggered by: PRAutoBlogger_OpenRouter_Image_Provider (both generate_image()
|
||||
@@ -12,7 +12,7 @@ declare(strict_types=1);
|
||||
* Dependencies: None — pure calculation + option reads.
|
||||
*
|
||||
* @see class-openrouter-image-provider.php — Caller.
|
||||
* @see class-cloudflare-image-pricing.php — Sibling pattern for Cloudflare.
|
||||
* @see class-runware-image-pricing.php — Sibling pattern for Runware.
|
||||
*/
|
||||
class PRAutoBlogger_OpenRouter_Image_Pricing {
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Contract for any image generation provider (Cloudflare Workers AI, DALL-E, etc.).
|
||||
* Contract for any image generation provider (Runware FLUX, OpenRouter Gemini, etc.).
|
||||
*
|
||||
* Consumers depend on this interface, never on a concrete provider — swapping
|
||||
* providers means writing one new class, not refactoring the pipeline. This
|
||||
@@ -13,7 +13,8 @@ declare(strict_types=1);
|
||||
* content generation run, after editorial review, before publish.
|
||||
* Dependencies: None at interface level — implementations wrap a specific HTTP API.
|
||||
*
|
||||
* @see class-cloudflare-image-provider.php — Cloudflare Workers AI implementation.
|
||||
* @see class-runware-image-provider.php — Runware FLUX implementation (default).
|
||||
* @see class-open-router-image-provider.php — OpenRouter image implementation.
|
||||
* @see interface-llm-provider.php — Parallel pattern for LLM providers.
|
||||
* @see ARCHITECTURE.md — External API Integrations table.
|
||||
*/
|
||||
@@ -79,7 +80,7 @@ interface PRAutoBlogger_Image_Provider_Interface {
|
||||
/**
|
||||
* Machine-readable provider identifier used in logs and settings.
|
||||
*
|
||||
* @return string Lowercase identifier, e.g. 'cloudflare_workers_ai'.
|
||||
* @return string Lowercase identifier, e.g. 'runware' or 'openrouter'.
|
||||
*/
|
||||
public function get_provider_name(): string;
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ declare(strict_types=1);
|
||||
* Contract for a provider-specific AI model registry.
|
||||
*
|
||||
* Phase 1 (v1): single implementation for OpenRouter (`class-open-router-model-registry.php`).
|
||||
* Phase 3: a second implementation wraps Cloudflare Workers AI model data. A
|
||||
* higher-level dispatcher iterates registered registries, calls each with the same
|
||||
* capability, and unions the results — the per-registry interface stays unchanged.
|
||||
* Phase 3: a second implementation wraps Runware model data. A higher-level
|
||||
* dispatcher iterates registered registries, calls each with the same capability,
|
||||
* and unions the results — the per-registry interface stays unchanged.
|
||||
*
|
||||
* Implementations MUST:
|
||||
* - Store the normalized registry as a WP option + transient cache layer.
|
||||
@@ -86,7 +86,7 @@ interface PRAutoBlogger_Model_Registry_Interface {
|
||||
public function get_fetched_at(): int;
|
||||
|
||||
/**
|
||||
* Machine-readable provider identifier (e.g. 'openrouter', 'cloudflare_workers_ai').
|
||||
* Machine-readable provider identifier (e.g. 'openrouter', 'runware').
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
||||
@@ -54,7 +54,7 @@ define( 'PRAUTOBLOGGER_DEFAULT_WRITING_MODEL', 'google/gemini-2.5-flash-lite' );
|
||||
define( 'PRAUTOBLOGGER_DEFAULT_EDITOR_MODEL', 'google/gemini-2.5-flash-lite' );
|
||||
|
||||
// Image generation defaults.
|
||||
// Default provider is Runware; OpenRouter (Gemini) + Cloudflare remain as alternates.
|
||||
// Default provider is Runware; OpenRouter (Gemini) remains as the alternate.
|
||||
// Default model is FLUX.1 schnell via Runware (~$0.0006/image, ~2s). CEO
|
||||
// decision 2026-04-21 after comic A/B: schnell's looser fidelity reads as
|
||||
// editorial-cartoon style and is 65× cheaper than Nano Banana. Users can
|
||||
|
||||
Reference in New Issue
Block a user