import { buildGatewayUrl } from './client' export type BatchImageStatus = | 'queued' | 'running' | 'indexing' | 'processing_results' | 'settling' | 'completed' | 'failed' | 'cancelled' | 'output_deleted' | string export interface BatchImageSubmitItem { custom_id: string prompt: string output_count?: number reference_images?: BatchImageReferenceImage[] } export interface BatchImageReferenceImage { id?: string type?: string mime_type: string data?: string file_uri?: string } export interface BatchImageSubmitRequest { model: string task_name?: string parent_batch_id?: string provider?: '' | 'gemini_api' | 'vertex' | string image_size?: '1K' | '2K' | '4K' | string response_mime_type?: string aspect_ratio?: string items: BatchImageSubmitItem[] metadata?: Record } export interface BatchImageJob { id: string object: string task_name: string parent_batch_id?: string | null status: BatchImageStatus model: string provider: string item_count: number success_count: number fail_count: number estimated_cost: number hold_amount: number actual_cost: number | null created_at: number submitted_at: number | null settled_at: number | null downloaded_at?: number | null output_deleted_at?: number | null } export interface BatchImageItem { batch_id?: string source_task_name?: string custom_id: string status: string prompt_preview?: string | null mime_type: string | null file_extension: string | null image_count: number error?: { code: string message: string source?: 'provider' | 'system' | string } | null } export interface BatchImageItemsResponse { object: string data: BatchImageItem[] has_more: boolean } export interface BatchImageJobsResponse { object: string data: BatchImageJob[] has_more: boolean } export interface BatchImageModel { id: string object: string provider: string } export interface BatchImageModelsResponse { object: string data: BatchImageModel[] } export interface BatchImageJobsListOptions { limit?: number cursor?: string status?: string taskName?: string downloaded?: '' | 'true' | 'false' | string from?: string to?: string } async function parseBatchImageError(response: Response): Promise { try { const body = await response.json() const message = body?.error?.message || body?.message || response.statusText const error = new Error(message) ;(error as any).code = body?.error?.code || response.status ;(error as any).status = response.status ;(error as any).requestId = response.headers.get('X-Request-Id') || '' return error } catch { const error = new Error(response.statusText || `HTTP ${response.status}`) ;(error as any).code = response.status ;(error as any).status = response.status ;(error as any).requestId = response.headers.get('X-Request-Id') || '' return error } } function authHeaders(apiKey: string, extra?: HeadersInit): HeadersInit { return { Authorization: `Bearer ${apiKey}`, ...extra, } } export async function submitBatchImageJob( apiKey: string, payload: BatchImageSubmitRequest, idempotencyKey: string, ): Promise { const response = await fetch(buildGatewayUrl('/v1/images/batches'), { method: 'POST', headers: authHeaders(apiKey, { 'Content-Type': 'application/json', 'Idempotency-Key': idempotencyKey, }), body: JSON.stringify(payload), }) if (!response.ok) throw await parseBatchImageError(response) return response.json() } export async function getBatchImageJob(apiKey: string, batchId: string): Promise { const response = await fetch(buildGatewayUrl(`/v1/images/batches/${encodeURIComponent(batchId)}`), { headers: authHeaders(apiKey), }) if (!response.ok) throw await parseBatchImageError(response) return response.json() } export async function listBatchImageJobs(apiKey: string, options: number | BatchImageJobsListOptions = 20): Promise { const params = new URLSearchParams() if (typeof options === 'number') { params.set('limit', String(options)) } else { params.set('limit', String(options.limit || 20)) if (options.cursor) params.set('cursor', options.cursor) if (options.status) params.set('status', options.status) if (options.taskName) params.set('task_name', options.taskName) if (options.downloaded) params.set('downloaded', options.downloaded) if (options.from) params.set('from', options.from) if (options.to) params.set('to', options.to) } const response = await fetch(buildGatewayUrl(`/v1/images/batches?${params.toString()}`), { headers: authHeaders(apiKey), }) if (!response.ok) throw await parseBatchImageError(response) return response.json() } export async function listBatchImageModels(apiKey: string): Promise { const response = await fetch(buildGatewayUrl('/v1/images/batches/models'), { headers: authHeaders(apiKey), }) if (!response.ok) throw await parseBatchImageError(response) return response.json() } export async function listBatchImageItems( apiKey: string, batchId: string, status = '', ): Promise { const query = status ? `?status=${encodeURIComponent(status)}` : '' const response = await fetch(buildGatewayUrl(`/v1/images/batches/${encodeURIComponent(batchId)}/items${query}`), { headers: authHeaders(apiKey), }) if (!response.ok) throw await parseBatchImageError(response) return response.json() } export async function cancelBatchImageJob(apiKey: string, batchId: string): Promise { const response = await fetch(buildGatewayUrl(`/v1/images/batches/${encodeURIComponent(batchId)}/cancel`), { method: 'POST', headers: authHeaders(apiKey), }) if (!response.ok) throw await parseBatchImageError(response) return response.json() } export async function downloadBatchImageZip(apiKey: string, batchId: string): Promise { const response = await fetch(buildGatewayUrl(`/v1/images/batches/${encodeURIComponent(batchId)}/download`), { headers: authHeaders(apiKey), }) if (!response.ok) throw await parseBatchImageError(response) return response.blob() } export async function getBatchImageItemContent(apiKey: string, batchId: string, customId: string, imageIndex = 0): Promise { const response = await fetch(buildGatewayUrl(`/v1/images/batches/${encodeURIComponent(batchId)}/items/${encodeURIComponent(customId)}/content?image_index=${encodeURIComponent(String(imageIndex))}`), { headers: authHeaders(apiKey), }) if (!response.ok) throw await parseBatchImageError(response) return response.blob() } export async function deleteBatchImageJobRecord(apiKey: string, batchId: string): Promise { const response = await fetch(buildGatewayUrl(`/v1/images/batches/${encodeURIComponent(batchId)}`), { method: 'DELETE', headers: authHeaders(apiKey), }) if (!response.ok) throw await parseBatchImageError(response) } export function saveBlob(blob: Blob, filename: string) { const url = URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = filename document.body.appendChild(link) link.click() document.body.removeChild(link) URL.revokeObjectURL(url) }