JSPM

  • Created
  • Published
  • Downloads 44
  • Score
    100M100P100Q92366F
  • License MIT

Pruna AI provider for React Native - implements IAIProvider interface for unified AI generation

Package Exports

  • @umituz/react-native-ai-pruna-provider
  • @umituz/react-native-ai-pruna-provider/package.json

Readme

@umituz/react-native-ai-pruna-provider

Pruna AI provider for React Native - Unified AI generation with IAIProvider interface implementation.

Supports text-to-image, image-to-image, and image-to-video generation via Pruna AI.

Documentation Strategy

Important: This documentation follows a code-example-free approach for implementation details.

  • No Code Examples: Documentation references file paths instead of showing internal code
  • Path-Based References: Always references actual file locations
  • Maintainable: Documentation stays valid when implementation changes

Features

  • Text-to-Image Generation - Generate images from text prompts (p-image model)
  • Image-to-Image Editing - Transform/edit images with prompts (p-image-edit model)
  • Image-to-Video Conversion - Convert static images to video with motion (p-video model)
  • Automatic File Upload - Base64 images auto-uploaded to Pruna CDN for video generation
  • Async Polling - Try-Sync with automatic fallback to async polling (~6 min max)
  • Request Deduplication - Identical requests return same promise (no duplicate API calls)
  • Retry with Backoff - Network/timeout/5xx errors retried (1 retry, 3s delay)
  • Session-Scoped Logging - Each generation has isolated log session for debugging
  • Cancellation Support - AbortController-based request cancellation
  • IAIProvider Compatible - Plug-and-play with @umituz/react-native-ai-generation-content

Supported Models

Model Type Input Output Key Features
p-image Text → Image Text prompt Image URL 7 aspect ratios, optional seed
p-image-edit Image → Image Image(s) + prompt Image URL Multi-image support, base64 or URL
p-video Image → Video Image + prompt Video URL 1-10s duration, 720p/1080p, draft mode

Aspect Ratios (All Models)

16:9 · 9:16 · 1:1 · 4:3 · 3:4 · 3:2 · 2:3

Video Options (p-video only)

  • Duration: 1-10 seconds (default: 5)
  • Resolution: 720p or 1080p (default: 720p)
  • FPS: 24 (fixed)
  • Draft mode: Fast 1-second preview generation
  • Prompt upsampling: Enabled by default

Installation

npm install @umituz/react-native-ai-pruna-provider

Peer Dependencies:

  • @umituz/react-native-ai-generation-content >= 1.70.0
  • expo >= 54.0.0
  • react >= 19.0.0
  • react-native >= 0.81.4

Note: No external AI SDK required — uses native fetch() for all API communication.


Quick Start

1. Initialize Provider

Location: src/init/initializePrunaProvider.ts

Import:

import { initializePrunaProvider } from '@umituz/react-native-ai-pruna-provider';

Usage: Call initializePrunaProvider() with your Pruna API key at app startup. This initializes the provider and registers it with the provider registry.

Alternative: Use createAiProviderInitModule() from src/init/createAiProviderInitModule.ts for integration with app initializer patterns.


2. Use Provider Directly

Location: src/infrastructure/services/pruna-provider.ts

Import:

import { prunaProvider } from '@umituz/react-native-ai-pruna-provider';

Key Methods:

  • subscribe() - Long-running generation with polling, retry, and cancellation
  • run() - Direct execution (no retry)
  • submitJob() - Submit to queue, get request ID
  • getJobStatus() - Poll job status
  • getJobResult() - Fetch completed result
  • cancelCurrentRequest() - Cancel active request
  • hasRunningRequest() - Check for running requests
  • getSessionLogs() - Get generation logs by session ID
  • endLogSession() - End and retrieve log session

3. Use React Hook

Location: src/presentation/hooks/use-pruna-generation.ts

Import:

import { usePrunaGeneration } from '@umituz/react-native-ai-pruna-provider';

Returns:

  • data - Generation result ({ url: string })
  • error - Typed error information (PrunaErrorInfo)
  • isLoading - Loading state
  • isRetryable - Whether error can be retried
  • requestId - Current request ID
  • isCancelling - Cancellation in progress
  • generate() - Start generation
  • retry() - Retry last failed generation
  • cancel() - Cancel current generation
  • reset() - Reset all state

Implementation: See src/presentation/hooks/use-pruna-generation.ts for options and callbacks.


Architecture

src/
├── domain/                              # Types & interfaces
│   ├── entities/
│   │   ├── pruna.types.ts              # PrunaModelId, PrunaAspectRatio, PrunaResolution, etc.
│   │   └── error.types.ts              # PrunaErrorType enum, PrunaErrorInfo
│   └── types/
│       └── index.ts                     # IAIProvider re-export from generation-content
│
├── infrastructure/                      # Implementation
│   ├── services/
│   │   ├── pruna-provider.ts           # Main PrunaProvider class (IAIProvider impl)
│   │   ├── pruna-provider.constants.ts # URLs, config, capabilities, defaults
│   │   ├── pruna-api-client.ts         # Low-level HTTP: upload, prediction, polling
│   │   ├── pruna-input-builder.ts      # Model-specific payload construction
│   │   ├── pruna-provider-subscription.ts # Subscribe/run with retry logic
│   │   ├── pruna-queue-operations.ts   # submitJob, getJobStatus, getJobResult
│   │   └── request-store.ts           # Promise deduplication (globalThis)
│   └── utils/
│       ├── log-collector.ts            # Session-scoped generation logging
│       ├── pruna-error-handler.util.ts # Error mapping & classification
│       ├── pruna-generation-state-manager.util.ts # React state management
│       ├── type-guards/                # Type validation utilities
│       └── helpers/                    # isDefined, sleep, generateUniqueId, etc.
│
├── presentation/
│   └── hooks/
│       └── use-pruna-generation.ts     # React hook for generation operations
│
├── init/
│   ├── createAiProviderInitModule.ts   # Factory for app initializer integration
│   └── initializePrunaProvider.ts      # Direct synchronous initialization
│
├── exports/                            # Barrel exports per layer
│   ├── domain.ts
│   ├── infrastructure.ts
│   └── presentation.ts
│
└── index.ts                            # Main entry point

API Reference

Pruna API Integration

Base URL: https://api.pruna.ai

Endpoints:

  • POST /v1/predictions - Submit generation (with Try-Sync header)
  • POST /v1/files - Upload images for video generation
  • GET {poll_url} - Poll async results

Authentication: apikey header

Implementation: See src/infrastructure/services/pruna-api-client.ts


Model Input Building

Location: src/infrastructure/services/pruna-input-builder.ts

Each model has strict schema requirements:

p-image (text-to-image):

  • Required: prompt
  • Optional: aspect_ratio, seed

p-image-edit (image-to-image):

  • Required: prompt, image input (image, images, image_url, or image_urls)
  • Optional: aspect_ratio, seed
  • Note: Images sent as raw base64 (prefix stripped automatically)

p-video (image-to-video):

  • Required: prompt, image input (image or image_url)
  • Optional: duration, resolution, draft, aspect_ratio
  • Note: Base64 images auto-uploaded to Pruna file storage (p-video requires HTTPS URL)
  • Fixed: fps: 24, prompt_upsampling: true

Error Handling

Location: src/infrastructure/utils/pruna-error-handler.util.ts

Error Types (PrunaErrorType):

  • NETWORK - Connection failures (retryable)
  • TIMEOUT - Request timeout (retryable)
  • API_ERROR - Server errors 5xx (retryable)
  • RATE_LIMIT - Too many requests 429 (retryable)
  • VALIDATION - Invalid input 400/422 (not retryable)
  • AUTHENTICATION - Invalid API key 401/403 (not retryable)
  • QUOTA_EXCEEDED - Billing issue 402 (not retryable)
  • MODEL_NOT_FOUND - Invalid model 404 (not retryable)
  • FILE_UPLOAD - Image upload failure (retryable)
  • POLLING_TIMEOUT - Async polling exceeded max attempts (retryable)
  • INVALID_IMAGE - Malformed image data (not retryable)
  • UNKNOWN - Unclassified error (not retryable)

Functions:

  • mapPrunaError() - Map raw error to PrunaErrorInfo
  • isPrunaErrorRetryable() - Check if error can be retried
  • getErrorMessage() - Extract error message string
  • formatErrorMessage() - Format error with context

Retry Strategy

┌──────────────────────────────────────────────────┐
│ FILE UPLOAD (Pruna /v1/files)                    │
│ Timeout: 30s / attempt                           │
│ Retries: 2 (3 total attempts)                    │
│ Backoff: 1s → 2s (exponential)                   │
│ Retries on: network, timeout                     │
├──────────────────────────────────────────────────┤
│ PREDICTION (Pruna /v1/predictions)               │
│ Timeout: caller-defined (default 360s)           │
│ Retries: 1 (2 total attempts)                    │
│ Backoff: 3s (fixed)                              │
│ Retries on: network, timeout, server (5xx)       │
│ NO retry: auth, validation, quota, cancel        │
├──────────────────────────────────────────────────┤
│ POLLING (async result polling)                   │
│ Interval: 3s                                     │
│ Max attempts: 120 (~6 min)                       │
│ Retries on: non-ok responses (skip & continue)   │
└──────────────────────────────────────────────────┘

Request Deduplication

Location: src/infrastructure/services/request-store.ts

  • Same model + same input = returns existing promise (no duplicate API call)
  • Uses globalThis storage — survives React Native hot reloads
  • Automatic cleanup: stale requests removed after 5 minutes
  • Deterministic key generation via recursive key sorting + hash

Session-Scoped Logging

Location: src/infrastructure/utils/log-collector.ts

Each generation creates an isolated log session:

  • Concurrent generations don't interfere
  • Logs attached to result via __providerSessionId property
  • Retrieve logs: prunaProvider.getSessionLogs(sessionId)
  • End session: prunaProvider.endLogSession(sessionId)

Type Definitions

Core Types

Location: src/domain/entities/pruna.types.ts

Types:

  • PrunaConfig - Provider configuration
  • PrunaModelId - Valid model IDs ('p-video' | 'p-image' | 'p-image-edit')
  • PrunaModelType - Model type classification
  • PrunaAspectRatio - Supported aspect ratios
  • PrunaResolution - Video resolution ('720p' | '1080p')
  • PrunaJobInput - Job input structure
  • PrunaJobResult - Job result structure
  • PrunaQueueStatus - Queue status structure
  • PrunaPredictionInput - Prediction request input
  • PrunaPredictionResponse - Raw API response
  • PrunaFileUploadResponse - File upload response

Import:

import type {
  PrunaModelId,
  PrunaAspectRatio,
  PrunaResolution,
  PrunaQueueStatus,
} from '@umituz/react-native-ai-pruna-provider';

Error Types

Location: src/domain/entities/error.types.ts

Types:

  • PrunaErrorType - Error type enumeration
  • PrunaErrorCategory - Error category with retryable flag
  • PrunaErrorInfo - Complete error information structure
  • PrunaErrorMessages - Custom error message overrides

Import:

import { PrunaErrorType } from '@umituz/react-native-ai-pruna-provider';
import type { PrunaErrorInfo } from '@umituz/react-native-ai-pruna-provider';

Constants

Provider Constants

Location: src/infrastructure/services/pruna-provider.constants.ts

Exports:

  • PRUNA_BASE_URL - API base URL
  • PRUNA_PREDICTIONS_URL - Predictions endpoint
  • PRUNA_FILES_URL - File upload endpoint
  • DEFAULT_PRUNA_CONFIG - Default retry/timeout/polling configuration
  • UPLOAD_CONFIG - File upload retry configuration
  • PRUNA_CAPABILITIES - Provider capability flags
  • VALID_PRUNA_MODELS - Array of valid model IDs
  • P_VIDEO_DEFAULTS - Default p-video parameters
  • DEFAULT_ASPECT_RATIO - Default aspect ratio ('16:9')

Utilities

Type Guards

Location: src/infrastructure/utils/type-guards/index.ts

Functions:

  • isPrunaModelId() - Validate Pruna model ID
  • isPrunaErrorType() - Validate error type
  • isValidApiKey() - Validate API key
  • isValidModelId() - Validate model ID format
  • isValidPrompt() - Validate prompt (max 5000 chars)
  • isValidTimeout() - Validate timeout value

Helper Functions

Location: src/infrastructure/utils/helpers/index.ts

Functions:

  • isDefined() - Type-safe null/undefined check
  • removeNullish() - Remove null/undefined from object
  • generateUniqueId() - Generate unique ID with prefix
  • sleep() - Promise-based delay

Integration with generation-content

This provider implements the IAIProvider interface from @umituz/react-native-ai-generation-content/core. Once initialized, it registers with the providerRegistry and can be used as the active provider for all generation operations.

Provider switching:

import { providerRegistry } from '@umituz/react-native-ai-generation-content';

// Switch to Pruna
providerRegistry.setActiveProvider('pruna');

// Switch back to FAL
providerRegistry.setActiveProvider('fal');

For AI Agents

When Working with This Codebase

DO:

  • Read the actual source files before writing code
  • Follow existing patterns in the codebase
  • Use types from src/domain/
  • Respect the architecture (domain/infrastructure/presentation)
  • Maintain type safety

DON'T:

  • Write code without reading existing implementations
  • Make assumptions about code structure
  • Skip type definitions
  • Create parallel implementations

Implementation Patterns

For New Features:

  1. Define types in src/domain/entities/ or src/domain/types/
  2. Implement in appropriate layer (infrastructure for services, presentation for hooks)
  3. Export from src/exports/ barrel files
  4. Re-export from src/index.ts

For Modifications:

  1. Read the complete file first
  2. Understand dependencies and the call chain
  3. Make changes while maintaining existing patterns
  4. Test type safety with npm run typecheck

Support

Documentation: See individual source files for inline documentation

Issues: Report issues at https://github.com/umituz/react-native-ai-pruna-provider/issues

Author: Umit UZ umit@umituz.com

License: MIT