import { TokenUsageRatesInterface } from "../../../foundations/tokenusage/services/tokenusage.service"; import { ModelService } from "./model.service"; /** * Result of one image GENERATION call. * * `imageBase64` is the FULL data URL (`data:image/png;base64,…`) exactly as the * provider returned it, so a caller can render it directly or decode it for * upload without having to re-assemble the prefix. */ export interface ImageGenerationResult { /** Full data URL, e.g. "data:image/png;base64,…" */ imageBase64: string; /** MIME type parsed out of the data URL prefix, e.g. "image/png" */ mimeType: string; tokenUsage: { input: number; output: number; }; /** * What the provider ACTUALLY charged for this request (OpenRouter usage * accounting: `usage.cost`, in USD credits). Preferred over token-based * pricing because image models bill output image tokens at a different rate * than output text tokens, and both arrive lumped into `completion_tokens`. * Undefined when the provider does not report a cost. */ cost?: number; /** * Per-1M-token rates of the CONNECTION THAT SERVED THE CALL — a DB-configured * AiConnection of type "image", or the IMAGE_* env block as the final link of * the chain. Fallback pricing only (used when `cost` is absent). Undefined * when the serving connection declares no rates, so the caller can tell * "no rates configured" apart from "rates of zero". */ rates?: TokenUsageRatesInterface; } /** Parameters for an image generation call. */ interface ImageGenerationParams { prompt: string; /** e.g. "1:1", "16:9". Forwarded as `image_config.aspect_ratio`. */ aspectRatio?: string; } /** * Image GENERATION service (the counterpart of `VisionLLMService`, which * ANALYSES images). * * Deliberately a plain `@Injectable()` over `fetch` rather than a LangChain * model: image output is not part of the LangChain chat surface, and the * OpenRouter contract is a single documented chat-completions body — * `modalities: ["image","text"]` plus an optional `image_config`, with the * image handed back as a data URL at * `choices[0].message.images[0].image_url.url`. This mirrors the direct HTTP * path `AudioLLMService` already uses for transcription. * * Configuration resolves through the "image" AI-connection chain * (`ModelService.getCandidatesForType`): database-configured `AiConnection` * nodes first (per-company, then global, administered from the AI-connections * page), with the IMAGE_* env block as the final link. There is deliberately * NO fallback onto the AI_* chat configuration — image generation defines its * own provider, key, endpoint and pricing. A rate-limited attempt cools the * failing connection down and retries against the next link of the chain. */ export declare class ImageLLMService { private readonly modelService; private readonly logger; private readonly MAX_RETRIES; private readonly INITIAL_DELAY_MS; private readonly CALL_TIMEOUT_MS; constructor(modelService: ModelService); /** * Checks if an error is a rate limit (429) error */ private isRateLimitError; /** * Sleep for specified milliseconds */ private sleep; /** * Wrap a promise with a timeout */ private withTimeout; /** * Execute a function with exponential backoff retry on rate limit errors. * * `fn` receives the ATTEMPT INDEX so each retry can address the next link of * the image connection chain (mirrors `VisionLLMService.withRetry`); a chain * of one simply re-targets the same connection. `onRateLimited` fires before * every backoff — including the final attempt — so the failing connection's * cooldown outlives this call. */ private withRetry; /** The serving connection's rates, or undefined when it declares none. */ private ratesOf; /** One provider round-trip against one connection of the chain. */ private callCandidate; /** * Generates ONE image from a text prompt. * * @param params.prompt - The full image prompt. * @param params.aspectRatio - Optional aspect ratio (e.g. "16:9"), sent as * `image_config.aspect_ratio`. Omitted from the body when unset so the * provider default applies. * @returns The image as a data URL, its MIME type, token usage, the * provider-reported cost when available, and the serving connection's rates. * @throws {Error} If no image connection is configured, the endpoint fails, * or no image comes back. * @throws {ContentModerationError} If the provider refused on safety grounds. */ generate(params: ImageGenerationParams): Promise; } export {}; //# sourceMappingURL=image.llm.service.d.ts.map