feat(images): Cloudflare Workers AI image provider (commit 1a)
First commit of the image + Instagram A/B pipeline workstream. Ships the Cloudflare Workers AI image provider, its pricing + validator helpers, four new settings fields in a new "Images" admin section, and unit tests with mocked HTTP. Nothing calls the provider yet from the article pipeline — integration lands in commit 1b. Why: CEO-approved on 2026-04-15 (see convo/prautoblogger/threads/2026-04-image-pipeline/01-cto-handoff.md). Style is locked to the 90s infomercial pastiche; default model is FLUX.1 [schnell] at ~$0.0011/MP (~$0.01/article for 8 images across 4 placements x 2 variants). Risk flags: - Direct call to Cloudflare Workers AI bypassing AI Gateway (decision D-001, documented in convo/prautoblogger/decisions/). Gateway route to Workers AI currently 403s; OpenRouter gateway path unaffected. - prab_event_log structured writes deferred to commit 1b when the table lands (decision D-002). Logger-based logging is in place now. - No schema changes. No existing code paths touched outside settings. - Backward compatible: provider is instantiable but not wired to any consumer yet. Test plan: - CI runs PHPUnit including the new CloudflareImageProviderTest. - After merge: verify the new Images section appears on the settings page, the style-suffix textarea pre-fills with the infomercial prompt, and entering the existing CLOUDFLARE_AI_TOKEN + account UUID lets a future "Test Connection" button return OK (button ships in a later commit; the underlying validate_credentials_detailed() works today). Files: - includes/providers/interface-image-provider.php (adopted from CTO draft) - includes/providers/class-cloudflare-image-provider.php (283 lines) - includes/providers/class-cloudflare-image-pricing.php (78 lines) - includes/providers/class-cloudflare-image-validator.php (107 lines) - includes/admin/class-settings-fields.php (+ Images section, 4 fields) - prautoblogger.php (+ PRAUTOBLOGGER_DEFAULT_IMAGE_MODEL, _STYLE_SUFFIX) - tests/unit/Providers/CloudflareImageProviderTest.php - ARCHITECTURE.md (file tree, integrations table, options table, decision #16) - CONVENTIONS.md (How To: Add a New Image Provider) - CHANGELOG.md (Unreleased section) Agent-Session: cowork-2026-04-15-image-pipeline-commit-1a
This commit is contained in:
100
includes/providers/interface-image-provider.php
Normal file
100
includes/providers/interface-image-provider.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Contract for any image generation provider (Cloudflare Workers AI, DALL-E, etc.).
|
||||
*
|
||||
* Consumers depend on this interface, never on a concrete provider — swapping
|
||||
* providers means writing one new class, not refactoring the pipeline. This
|
||||
* mirrors the LLM provider pattern in `interface-llm-provider.php` (see CTO
|
||||
* rule #7 — interface for external service integrations).
|
||||
*
|
||||
* Triggered by: PRAutoBlogger_Image_Pipeline (added in commit #1b) during the
|
||||
* 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 — Default implementation (FLUX.1 via Workers AI).
|
||||
* @see interface-llm-provider.php — Parallel pattern for LLM providers.
|
||||
* @see ARCHITECTURE.md — External API Integrations table.
|
||||
*/
|
||||
interface PRAutoBlogger_Image_Provider_Interface {
|
||||
|
||||
/**
|
||||
* Generate a single image from a prompt at the requested dimensions.
|
||||
*
|
||||
* Implementations MUST:
|
||||
* - Apply retry + exponential backoff on transient failures (5xx, network).
|
||||
* - Fail loudly on client errors (4xx) rather than silently returning empty.
|
||||
* - Log each attempt via PRAutoBlogger_Logger.
|
||||
* - Persist a structured event row via PRAutoBlogger_Event_Log (added in a
|
||||
* later commit — safe to no-op until then).
|
||||
*
|
||||
* Side effects: HTTP request to the provider API.
|
||||
*
|
||||
* @param string $prompt Full prompt (concept + style suffix already concatenated).
|
||||
* @param int $width Target width in pixels (>= 64, <= 2048).
|
||||
* @param int $height Target height in pixels (>= 64, <= 2048).
|
||||
* @param array{
|
||||
* seed?: int,
|
||||
* steps?: int,
|
||||
* model?: string,
|
||||
* } $options Optional tuning. `seed` lets the caller ask for visually
|
||||
* coherent variants across placements. `steps` trades quality
|
||||
* for cost (default model-dependent). `model` picks a specific
|
||||
* model identifier; implementations may ignore values they
|
||||
* don't support.
|
||||
*
|
||||
* @return array{
|
||||
* bytes: string,
|
||||
* mime_type: string,
|
||||
* width: int,
|
||||
* height: int,
|
||||
* model: string,
|
||||
* seed: ?int,
|
||||
* cost_usd: float,
|
||||
* latency_ms: int,
|
||||
* } Raw image bytes (PNG or JPEG) plus metadata. Metadata is used by the
|
||||
* caller to write post meta and to bill against the plugin's cost budget.
|
||||
*
|
||||
* @throws \RuntimeException On API error after retries exhausted, or on
|
||||
* an invalid response shape.
|
||||
* @throws \InvalidArgumentException If dimensions are out of range.
|
||||
*/
|
||||
public function generate_image( string $prompt, int $width, int $height, array $options = [] ): array;
|
||||
|
||||
/**
|
||||
* Estimate the USD cost of a single generation call before making it.
|
||||
*
|
||||
* Used by the cost tracker to pre-check budget and to show an expected
|
||||
* spend figure in the dry-run preview.
|
||||
*
|
||||
* @param int $width Target width in pixels.
|
||||
* @param int $height Target height in pixels.
|
||||
* @param array $options Same shape as generate_image() options.
|
||||
*
|
||||
* @return float Estimated cost in USD for a single image at the given dimensions.
|
||||
*/
|
||||
public function estimate_cost( int $width, int $height, array $options = [] ): float;
|
||||
|
||||
/**
|
||||
* Machine-readable provider identifier used in logs and settings.
|
||||
*
|
||||
* @return string Lowercase identifier, e.g. 'cloudflare_workers_ai'.
|
||||
*/
|
||||
public function get_provider_name(): string;
|
||||
|
||||
/**
|
||||
* Verify the provider credentials are present and the API is reachable.
|
||||
*
|
||||
* Used by the admin "Test Connections" action. Implementations should make
|
||||
* a lightweight request (e.g. a models list or token verify endpoint) — NOT
|
||||
* generate a real image.
|
||||
*
|
||||
* Side effects: HTTP request, logs the result.
|
||||
*
|
||||
* @return array{status: string, message: string, debug?: string}
|
||||
* status is 'ok' or 'error'; message is human-readable for the
|
||||
* admin UI; debug is optional diagnostic detail for logs.
|
||||
*/
|
||||
public function validate_credentials_detailed(): array;
|
||||
}
|
||||
Reference in New Issue
Block a user