{"id":31378679,"url":"https://github.com/droath/prism-transformer","last_synced_at":"2026-01-20T16:43:42.313Z","repository":{"id":315530827,"uuid":"1056290799","full_name":"droath/prism-transformer","owner":"droath","description":"A powerful Laravel package for AI-powered content transformation using multiple LLM providers.","archived":false,"fork":false,"pushed_at":"2025-09-25T14:07:00.000Z","size":360,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-28T06:55:04.600Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/droath.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"droath"}},"created_at":"2025-09-13T19:22:07.000Z","updated_at":"2025-09-25T14:07:04.000Z","dependencies_parsed_at":"2025-09-19T21:32:17.891Z","dependency_job_id":null,"html_url":"https://github.com/droath/prism-transformer","commit_stats":null,"previous_names":["droath/prism-transformer"],"tags_count":0,"template":false,"template_full_name":"spatie/package-skeleton-laravel","purl":"pkg:github/droath/prism-transformer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/droath%2Fprism-transformer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/droath%2Fprism-transformer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/droath%2Fprism-transformer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/droath%2Fprism-transformer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/droath","download_url":"https://codeload.github.com/droath/prism-transformer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/droath%2Fprism-transformer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278391192,"owners_count":25978944,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-28T06:54:56.529Z","updated_at":"2026-01-20T16:43:42.305Z","avatar_url":"https://github.com/droath.png","language":"PHP","funding_links":["https://github.com/sponsors/droath"],"categories":[],"sub_categories":[],"readme":"# Prism Transformer\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/droath/prism-transformer.svg?style=flat-square)](https://packagist.org/packages/droath/prism-transformer)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/droath/prism-transformer/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/droath/prism-transformer/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/droath/prism-transformer/phpstan.yml?branch=main\u0026label=code%20style\u0026style=flat-square)](https://github.com/droath/prism-transformer/actions?query=workflow%3A\"Fix+PHP+code+style+issues\"+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/droath/prism-transformer.svg?style=flat-square)](https://packagist.org/packages/droath/prism-transformer)\n\nA powerful Laravel package for AI-powered content transformation using\nmultiple LLM providers with direct Laravel Eloquent model integration.\n\nTransform text content and web URLs into structured data or Laravel models\nusing providers such as OpenAI, Anthropic, Groq, and more, with intelligent\ncaching, automatic schema generation, and robust error handling.\n\n## Features\n\n- **🤖 Multi-Provider Support**: OpenAI, Anthropic, Groq, Ollama, Gemini,\n  Mistral, DeepSeek, xAI, OpenRouter, VoyageAI, ElevenLabs\n- **🚀 Fluent Interface**: Chainable methods for intuitive transformation\n  workflows\n- **📄 Content Sources**: Transform text, URLs, images, and documents\n- **🖼️ Media Input Support**: Native support for image and document\n  transformation with AI vision\n- **⚡ Intelligent Caching**: Two-layer caching system for content fetching and\n  transformation results\n- **🔄 Async Processing**: Queue transformations for background processing with\n  Laravel queues\n- **🛠️ Custom Transformers**: Create reusable transformation classes with\n  dependency injection\n- **🎯 Laravel Model Output**: Direct transformation to Laravel Eloquent models\n  with automatic schema generation\n- **🔧 Laravel Integration**: Service provider, facades, and configuration\n- **✅ Validation Support**: Built-in Laravel validation integration\n- **🛡️ Security Features**: Blocked domains protection for content fetching\n- **🏗️ Service-Oriented Architecture**: Clean separation of concerns with\n  dedicated services\n- **🎯 Error Handling**: Comprehensive Throwable-based exception system with\n  transformation context\n- **📊 Performance Optimized**: Efficient algorithms and configurable timeout\n  settings\n\n## Installation\n\nInstall the package via Composer:\n\n```bash\ncomposer require droath/prism-transformer\n```\n\nPublish the configuration file:\n\n```bash\nphp artisan vendor:publish --tag=\"prism-transformer-config\"\n```\n\n## Configuration\n\n### Requirements\n\n- PHP 8.3+\n- Laravel 11.0+ or 12.0+\n\n### Environment Variables\n\nSet up your AI provider API keys in your `.env` file:\n\n```env\n# Default provider\nPRISM_TRANSFORMER_DEFAULT_PROVIDER=openai\n\n# API Keys\nOPENAI_API_KEY=your-openai-api-key\nANTHROPIC_API_KEY=your-anthropic-api-key\nGROQ_API_KEY=your-groq-api-key\n\n# Caching (optional)\nPRISM_TRANSFORMER_CACHE_CONTENT_ENABLED=true\nPRISM_TRANSFORMER_CACHE_RESULTS_ENABLED=true\nPRISM_TRANSFORMER_CACHE_TTL_CONTENT=1800\nPRISM_TRANSFORMER_CACHE_TTL_RESULTS=3600\nPRISM_TRANSFORMER_CACHE_STORE=redis\n\n# Async Queue (optional)\nPRISM_TRANSFORMER_ASYNC_QUEUE=default\nPRISM_TRANSFORMER_QUEUE_CONNECTION=redis\nPRISM_TRANSFORMER_TIMEOUT=60\nPRISM_TRANSFORMER_TRIES=3\n```\n\n### Provider Configuration\n\nThe package supports multiple AI providers with customizable models and\nsettings:\n\n```php\n// config/prism-transformer.php\nreturn [\n    'default_provider' =\u003e Provider::OPENAI,\n\n    'providers' =\u003e [\n        'openai' =\u003e [\n            'default_model' =\u003e 'gpt-4o-mini',\n            'max_tokens' =\u003e 4096,\n            'temperature' =\u003e 0.7,\n        ],\n        'anthropic' =\u003e [\n            'default_model' =\u003e 'claude-3-5-haiku-20241022',\n            'max_tokens' =\u003e 4096,\n            'temperature' =\u003e 0.7,\n        ],\n        // ... more providers\n    ],\n];\n```\n\n## Quick Start\n\n### Basic Text Transformation\n\n```php\nuse Droath\\PrismTransformer\\PrismTransformer;\n\n// Create a simple transformer using a closure\n$transformer = new PrismTransformer();\n\n$result = $transformer\n    -\u003etext('Hello world!')\n    -\u003eusing(function($content) {\n        return TransformerResult::successful(\"Transformed: $content\");\n    })\n    -\u003etransform();\n\necho $result-\u003egetContent(); // \"Transformed: Hello world!\"\n```\n\n### Laravel Model Transformation\n\nTransform content directly into Laravel Eloquent models:\n\n```php\nuse Droath\\PrismTransformer\\PrismTransformer;\nuse Droath\\PrismTransformer\\Abstract\\BaseTransformer;\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass Contact extends Model\n{\n    protected $fillable = ['name', 'email', 'phone'];\n}\n\nclass ContactExtractor extends BaseTransformer\n{\n    public function prompt(): string\n    {\n        return 'Extract contact information from the text as JSON.';\n    }\n\n    protected function outputFormat(): Model\n    {\n        return new Contact();\n    }\n}\n\n$result = (new PrismTransformer())\n    -\u003etext('John Smith, email: john@example.com, phone: (555) 123-4567')\n    -\u003eusing(ContactExtractor::class)\n    -\u003etransform();\n\n// Convert directly to Laravel model\n$contact = $result-\u003etoModel(Contact::class);\n$contact-\u003esave(); // Save to database\n\necho $contact-\u003ename;  // \"John Smith\"\necho $contact-\u003eemail; // \"john@example.com\"\n```\n\n### URL Content Transformation\n\n```php\n$result = $transformer\n    -\u003eurl('https://example.com/article')\n    -\u003eusing($customTransformer)\n    -\u003etransform();\n```\n\n### Media Input Transformation\n\nTransform images and documents with AI vision and document analysis:\n\n```php\nuse Droath\\PrismTransformer\\PrismTransformer;\n\n// Image transformation\n$result = (new PrismTransformer())\n    -\u003eimage('/path/to/image.jpg')\n    -\u003eusing($imageAnalyzer)\n    -\u003etransform();\n\n// Document transformation\n$result = (new PrismTransformer())\n    -\u003edocument('/path/to/document.pdf')\n    -\u003eusing($documentExtractor)\n    -\u003etransform();\n\n// You can also pass metadata\n$result = (new PrismTransformer())\n    -\u003eimage('/path/to/photo.png', ['title' =\u003e 'Product Photo'])\n    -\u003eusing($productAnalyzer)\n    -\u003etransform();\n```\n\nThe media input methods automatically handle:\n\n- **File reading and encoding**: Converts files to base64 for AI processing\n- **Media type detection**: Automatically determines image vs document types\n- **Proper serialization**: Works with both sync and async transformations\n\n### Async Transformations\n\nQueue transformations for background processing using Laravel's queue system:\n\n```php\nuse Droath\\PrismTransformer\\PrismTransformer;\n\n// Async text transformation\n$pendingDispatch = (new PrismTransformer())\n    -\u003etext('Long content to process...')\n    -\u003easync()\n    -\u003eusing($summarizer)\n    -\u003etransform();\n\n// Async URL transformation\n$pendingDispatch = (new PrismTransformer())\n    -\u003eurl('https://example.com/article')\n    -\u003easync()\n    -\u003eusing($contentAnalyzer)\n    -\u003etransform();\n\n// Async image transformation\n$pendingDispatch = (new PrismTransformer())\n    -\u003eimage('/path/to/image.jpg')\n    -\u003easync()\n    -\u003eusing($imageDescriber)\n    -\u003etransform();\n\n// The transform() method returns a PendingDispatch instance\n// The job will be processed by your queue worker\n```\n\n**Async with Context:**\n\n```php\n$pendingDispatch = (new PrismTransformer())\n    -\u003esetContext(['user_id' =\u003e auth()-\u003eid(), 'tenant_id' =\u003e 123])\n    -\u003etext('Content to transform')\n    -\u003easync()\n    -\u003eusing($transformer)\n    -\u003etransform();\n```\n\n**Async with Closures:**\n\nClosures are automatically serialized for queue processing and properly handle\nMedia objects:\n\n```php\n// Works with both string and Media input\n$pendingDispatch = (new PrismTransformer())\n    -\u003eimage('/path/to/image.jpg')\n    -\u003easync()\n    -\u003eusing(function ($content) {\n        // $content will be a Media object (Image instance)\n        // Properly handle both types\n        $data = is_string($content) ? $content : $content-\u003ebase64();\n\n        return TransformerResult::successful(\"Processed: {$data}\");\n    })\n    -\u003etransform();\n```\n\n**Queue Configuration:**\n\n```php\n// config/prism-transformer.php\n'transformation' =\u003e [\n    'async_queue' =\u003e env('PRISM_TRANSFORMER_ASYNC_QUEUE', 'default'),\n    'queue_connection' =\u003e env('PRISM_TRANSFORMER_QUEUE_CONNECTION'),\n    'timeout' =\u003e env('PRISM_TRANSFORMER_TIMEOUT', 60),\n    'tries' =\u003e env('PRISM_TRANSFORMER_TRIES', 3),\n],\n```\n\n### Using the Facade\n\n```php\nuse Droath\\PrismTransformer\\Facades\\PrismTransformer;\n\n$result = PrismTransformer::text('Content to transform')\n    -\u003eusing($transformer)\n    -\u003etransform();\n\n// Async with facade\n$pendingDispatch = PrismTransformer::text('Content to transform')\n    -\u003easync()\n    -\u003eusing($transformer)\n    -\u003etransform();\n```\n\n## Custom Transformers\n\nCreate powerful, reusable transformers by extending `BaseTransformer`:\n\n### Simple Content Summarizer\n\n```php\n\u003c?php\n\nuse Droath\\PrismTransformer\\Abstract\\BaseTransformer;\nuse Droath\\PrismTransformer\\ValueObjects\\TransformerResult;\n\nclass ArticleSummarizer extends BaseTransformer\n{\n    public function prompt(): string\n    {\n        return 'Summarize the following article in 2-3 sentences, focusing on key points:';\n    }\n}\n```\n\nUsage:\n\n```php\n$summarizer = app(ArticleSummarizer::class);\n\n$result = PrismTransformer::url('https://techcrunch.com/article')\n    -\u003eusing($summarizer)\n    -\u003etransform();\n\nif ($result-\u003eisSuccessful()) {\n    echo $result-\u003egetContent();\n}\n```\n\n### Data Extraction with Laravel Model Output\n\nTransform content directly into Laravel Eloquent models with automatic schema\ngeneration:\n\n```php\n\u003c?php\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Droath\\PrismTransformer\\Abstract\\BaseTransformer;\n\nclass User extends Model\n{\n    protected $fillable = ['name', 'email', 'phone', 'company'];\n\n    protected $casts = [\n        'created_at' =\u003e 'datetime',\n    ];\n}\n\nclass ContactExtractor extends BaseTransformer\n{\n    public function prompt(): string\n    {\n        return 'Extract contact information from the provided text and structure it as user data.';\n    }\n\n    protected function outputFormat(): Model\n    {\n        return new User();\n    }\n}\n```\n\nUsage:\n\n```php\n$extractor = app(ContactExtractor::class);\n\n$businessCard = \"John Smith - Senior Developer at TechCorp Inc.\n                Email: john.smith@techcorp.com | Phone: (555) 123-4567\";\n\n$result = PrismTransformer::text($businessCard)\n    -\u003eusing($extractor)\n    -\u003etransform();\n\n// Convert result directly to Laravel model\n$user = $result-\u003etoModel(User::class);\n\necho $user-\u003ename;     // \"John Smith\"\necho $user-\u003eemail;    // \"john.smith@techcorp.com\"\necho $user-\u003ephone;    // \"(555) 123-4567\"\necho $user-\u003ecompany;  // \"TechCorp Inc.\"\n```\n\n### Traditional Structured Output (Still Supported)\n\n```php\n\u003c?php\n\nuse Prism\\Prism\\Schema\\ObjectSchema;\nuse Prism\\Prism\\Schema\\StringSchema;\nuse Droath\\PrismTransformer\\Abstract\\BaseTransformer;\n\nclass ContactExtractor extends BaseTransformer\n{\n    public function prompt(): string\n    {\n        return 'Extract contact information from the provided text.';\n    }\n\n    protected function outputFormat(): ?ObjectSchema\n    {\n        return ObjectSchema::create()\n            -\u003eproperties([\n                'name' =\u003e StringSchema::create()-\u003edescription('Full name'),\n                'email' =\u003e StringSchema::create()-\u003edescription('Email address'),\n                'phone' =\u003e StringSchema::create()-\u003edescription('Phone number'),\n                'company' =\u003e StringSchema::create()-\u003edescription('Company name'),\n            ])\n            -\u003erequired(['name']);\n    }\n}\n```\n\n## Real-World Examples\n\n### 1. Blog Post SEO Optimizer\n\n```php\nuse Droath\\PrismTransformer\\Abstract\\BaseTransformer;\nuse Droath\\PrismTransformer\\Enums\\Provider;\nuse Droath\\PrismTransformer\\Services\\ConfigurationService;\nuse Droath\\PrismTransformer\\Services\\ModelSchemaService;\nuse Droath\\PrismTransformer\\Facades\\PrismTransformer;\nuse Illuminate\\Cache\\CacheManager;\n\nclass SEOOptimizer extends BaseTransformer\n{\n    private array $keywords;\n\n    public function __construct(\n        CacheManager $cache,\n        ConfigurationService $configuration,\n        ModelSchemaService $modelSchemaService,\n        array $keywords = []\n    ) {\n        parent::__construct($cache, $configuration, $modelSchemaService);\n        $this-\u003ekeywords = $keywords;\n    }\n\n    public function prompt(): string\n    {\n        $keywordsList = implode(', ', $this-\u003ekeywords);\n        return \"Optimize the following blog post for SEO. Target keywords: {$keywordsList}.\n                Ensure natural keyword integration while maintaining readability.\n                Improve meta descriptions, headings, and overall content structure for better search engine ranking.\";\n    }\n\n    protected function provider(): Provider\n    {\n        return Provider::OPENAI; // Use OpenAI for content optimization\n    }\n\n    protected function model(): string\n    {\n        return 'gpt-4o-mini'; // Good balance of quality and cost for content work\n    }\n\n    protected function temperature(): ?float\n    {\n        return 0.3; // Lower temperature for more consistent, focused output\n    }\n}\n\n// Usage - Optimizing a blog post from a URL\n$result = PrismTransformer::url('https://blog.example.com/laravel-tips')\n    -\u003eusing(new SEOOptimizer(\n        app(CacheManager::class),\n        app(ConfigurationService::class),\n        app(ModelSchemaService::class),\n        ['Laravel', 'PHP', 'web development', 'framework']\n    ))\n    -\u003etransform();\n\nif ($result-\u003eisSuccessful()) {\n    $optimizedPost = $result-\u003egetContent();\n    $metadata = $result-\u003egetMetadata();\n\n    echo \"Optimization completed successfully!\\n\";\n    echo \"Provider: {$metadata?-\u003eprovider-\u003evalue}\\n\";\n    echo \"Model: {$metadata?-\u003emodel}\\n\";\n    echo \"Content length: \" . strlen($optimizedPost) . \" characters\\n\";\n\n    // Save the optimized content\n    file_put_contents('optimized-post.md', $optimizedPost);\n} else {\n    echo \"SEO optimization failed:\\n\";\n    foreach ($result-\u003egetErrors() as $error) {\n        echo \"- {$error}\\n\";\n    }\n}\n\n// Alternative: Direct text optimization\n$blogContent = \"Your existing blog post content here...\";\n\n$result = PrismTransformer::text($blogContent)\n    -\u003eusing(SEOOptimizer::class) // Can also use class name for auto-resolution\n    -\u003etransform();\n```\n\n### 2. Multi-Language Content Translator\n\n```php\nclass ContentTranslator extends BaseTransformer\n{\n    public function __construct(\n        CacheManager $cache,\n        ConfigurationService $configuration,\n        ModelSchemaService $modelSchemaService,\n        private string $targetLanguage = 'Spanish',\n        private bool $maintainFormatting = true\n    ) {\n        parent::__construct($cache, $configuration, $modelSchemaService);\n    }\n\n    public function prompt(): string\n    {\n        $formatInstruction = $this-\u003emaintainFormatting ?\n            'Maintain all HTML tags, markdown formatting, and structure.' : '';\n\n        return \"Translate the following content to {$this-\u003etargetLanguage}.\n                Ensure cultural appropriateness and natural language flow. {$formatInstruction}\";\n    }\n\n    protected function model(): string\n    {\n        // Use a more capable model for translation tasks\n        return 'gpt-4o';\n    }\n\n    protected function temperature(): ?float\n    {\n        // Lower temperature for more consistent translations\n        return 0.3;\n    }\n\n    private function detectLanguage(string $content): string\n    {\n        // Simple language detection - in practice, use a proper language detection library\n        return 'English'; // Simplified for example\n    }\n}\n\n// Usage with caching benefits - dependency injection handles constructor parameters\n$result = PrismTransformer::url('https://company.com/about')\n    -\u003eusing(ContentTranslator::class)\n    -\u003etransform();\n\n// Or create instance manually for custom parameters\n$translator = new ContentTranslator(\n    app(CacheManager::class),\n    app(ConfigurationService::class),\n    app(ModelSchemaService::class),\n    'French',\n    true\n);\n\n$result = PrismTransformer::text('Hello, how are you today?')\n    -\u003eusing($translator)\n    -\u003etransform();\n\nif ($result-\u003eisSuccessful()) {\n    echo $result-\u003egetContent(); // \"Bonjour, comment allez-vous aujourd'hui ?\"\n    $metadata = $result-\u003egetMetadata();\n    echo \"Model used: \" . $metadata-\u003emodel;\n    echo \"Provider: \" . $metadata-\u003eprovider-\u003evalue;\n}\n```\n\n### 3. Customer Feedback Analyzer with Laravel Models\n\nTransform customer feedback directly into Laravel models for seamless database\nintegration:\n\n```php\n\u003c?php\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Droath\\PrismTransformer\\Abstract\\BaseTransformer;\n\nclass FeedbackAnalysis extends Model\n{\n    protected $fillable = [\n        'sentiment',\n        'sentiment_score',\n        'key_issues',\n        'priority_level',\n        'recommended_actions',\n        'categories',\n        'confidence_level',\n    ];\n\n    protected $casts = [\n        'sentiment_score' =\u003e 'float',\n        'key_issues' =\u003e 'array',\n        'recommended_actions' =\u003e 'array',\n        'categories' =\u003e 'array',\n        'confidence_level' =\u003e 'float',\n    ];\n}\n\nclass FeedbackAnalyzer extends BaseTransformer\n{\n    public function prompt(): string\n    {\n        return 'Analyze customer feedback and provide structured insights including sentiment, key issues, and recommendations. Format the response as JSON.';\n    }\n\n    protected function outputFormat(): Model\n    {\n        return new FeedbackAnalysis();\n    }\n}\n\n// Usage - Process feedback and save to database\n$analyzer = app(FeedbackAnalyzer::class);\n$feedbackEntries = [\n    \"Product quality has declined significantly. Very disappointed!\",\n    \"Great customer service, quick response time. Very satisfied.\",\n    \"Website is hard to navigate, checkout process is confusing.\",\n];\n\nforeach ($feedbackEntries as $feedback) {\n    $result = PrismTransformer::text($feedback)\n        -\u003eusing($analyzer)\n        -\u003etransform();\n\n    if ($result-\u003eisSuccessful()) {\n        // Convert to model with validation\n        $validationRules = [\n            'sentiment' =\u003e 'required|in:positive,negative,neutral',\n            'sentiment_score' =\u003e 'required|numeric|between:-1,1',\n            'priority_level' =\u003e 'required|in:low,medium,high,urgent',\n        ];\n\n        $analysis = $result-\u003etoModel(FeedbackAnalysis::class, $validationRules);\n\n        // Save to database\n        $analysis-\u003esave();\n\n        echo \"Sentiment: {$analysis-\u003esentiment} (Score: {$analysis-\u003esentiment_score})\\n\";\n        echo \"Priority: {$analysis-\u003epriority_level}\\n\";\n        echo \"Saved analysis with ID: {$analysis-\u003eid}\\n\\n\";\n    }\n}\n```\n\n## Laravel Model Integration\n\nThe package provides first-class Laravel Eloquent model integration, allowing\nyou to transform AI responses directly into model instances with automatic\nschema generation and validation.\n\n### Model Output Format\n\nUse the `outputFormat()` method in your transformers to specify a Laravel model\nas the expected output:\n\n```php\n\u003c?php\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Droath\\PrismTransformer\\Abstract\\BaseTransformer;\n\nclass Product extends Model\n{\n    protected $fillable = ['name', 'price', 'category', 'description', 'in_stock'];\n\n    protected $casts = [\n        'price' =\u003e 'decimal:2',\n        'in_stock' =\u003e 'boolean',\n    ];\n}\n\nclass ProductExtractor extends BaseTransformer\n{\n    public function prompt(): string\n    {\n        return 'Extract product information from the text and format it as structured data.';\n    }\n\n    protected function outputFormat(): Model\n    {\n        return new Product();\n    }\n}\n```\n\n### Schema Generation\n\nThe `ModelSchemaService` automatically converts Laravel model definitions into\nPrism schemas:\n\n- **Fillable attributes** become schema properties\n- **Model casts** determine the appropriate schema types\n- **Type mapping** handles Laravel cast types to Prism schema types\n\nSupported Laravel cast types:\n\n- `string` → `StringSchema`\n- `integer`, `int` → `NumberSchema`\n- `float`, `double`, `decimal` → `NumberSchema`\n- `boolean`, `bool` → `BooleanSchema`\n- `array`, `json` → `ArraySchema`\n- `collection` → `ArraySchema`\n- `date`, `datetime`, `timestamp` → `StringSchema` (with ISO 8601 format)\n\n### Model Hydration\n\nTransform results can be converted directly to model instances using the\n`toModel()` method:\n\n```php\n$result = PrismTransformer::text($productDescription)\n    -\u003eusing(ProductExtractor::class)\n    -\u003etransform();\n\n// Convert to model with optional validation\n$product = $result-\u003etoModel(Product::class, [\n    'name' =\u003e 'required|string|max:255',\n    'price' =\u003e 'required|numeric|min:0',\n    'category' =\u003e 'required|string',\n    'in_stock' =\u003e 'required|boolean',\n]);\n\n// Save to database\n$product-\u003esave();\n```\n\n### Service-Oriented Architecture\n\nThe model integration uses a clean service-oriented approach:\n\n- **`ModelSchemaService`**: Handles model-to-schema conversion and data-to-model\n  hydration\n- **Separation of concerns**: Model logic is isolated from transformation logic\n- **Dependency injection**: Services are injected via Laravel's container\n- **Testability**: Services can be easily mocked and tested independently\n\n## Caching System\n\nThe package includes a sophisticated two-layer caching system to optimize\nperformance and reduce API costs:\n\n### Two-Layer Cache Architecture\n\n1. **Content Fetch Cache**: Caches raw content from URLs and files\n2. **Transformer Results Cache**: Caches AI transformation results\n\nThis separation allows you to:\n\n- Reuse fetched content across different transformers\n- Cache expensive AI transformations independently\n- Control cache TTL separately for each layer\n\n### Configuration\n\n```php\n// config/prism-transformer.php\n'cache' =\u003e [\n    'store' =\u003e env('PRISM_TRANSFORMER_CACHE_STORE', 'default'),\n    'prefix' =\u003e env('PRISM_TRANSFORMER_CACHE_PREFIX', 'prism_transformer'),\n\n    'content_fetch' =\u003e [\n        'enabled' =\u003e env('PRISM_TRANSFORMER_CACHE_CONTENT_ENABLED', false),\n        'ttl' =\u003e env('PRISM_TRANSFORMER_CACHE_TTL_CONTENT', 1800), // 30 minutes\n    ],\n\n    'transformer_results' =\u003e [\n        'enabled' =\u003e env('PRISM_TRANSFORMER_CACHE_RESULTS_ENABLED', false),\n        'ttl' =\u003e env('PRISM_TRANSFORMER_CACHE_TTL_RESULTS', 3600), // 1 hour\n    ],\n],\n```\n\n### Cache Keys\n\nCache keys are intelligently generated based on:\n\n- **Content fetch cache**: URL + fetch options\n- **Transformer results cache**: Content + context + transformer configuration\n\nThis ensures accurate cache hits while avoiding false positives.\n\n### Cache Usage Examples\n\n```php\n// First call - fetches content and performs transformation, caches both\n$result1 = PrismTransformer::url('https://news.site.com/article')\n    -\u003eusing($summarizer)\n    -\u003etransform();\n\n// Second call - uses both cached content AND cached transformation\n$result2 = PrismTransformer::url('https://news.site.com/article')\n    -\u003eusing($summarizer)\n    -\u003etransform(); // Much faster!\n\n// Different transformer, same URL - uses cached content, new transformation\n$result3 = PrismTransformer::url('https://news.site.com/article')\n    -\u003eusing($translator)\n    -\u003etransform(); // Skips HTTP fetch, performs new AI transformation\n\n// Different context invalidates transformer cache\n$result4 = PrismTransformer::url('https://news.site.com/article')\n    -\u003esetContext(['language' =\u003e 'es'])\n    -\u003eusing($summarizer)\n    -\u003etransform(); // Uses cached content, new transformation with context\n```\n\n### Environment Configuration\n\n```env\n# Enable/disable caching\nPRISM_TRANSFORMER_CACHE_CONTENT_ENABLED=true\nPRISM_TRANSFORMER_CACHE_RESULTS_ENABLED=true\n\n# Cache TTL in seconds\nPRISM_TRANSFORMER_CACHE_TTL_CONTENT=1800\nPRISM_TRANSFORMER_CACHE_TTL_RESULTS=3600\n\n# Use Redis for better performance (optional)\nPRISM_TRANSFORMER_CACHE_STORE=redis\n```\n\n## Content Fetchers\n\nCustomize how content is retrieved from URLs:\n\n```php\nuse Droath\\PrismTransformer\\ContentFetchers\\BasicHttpFetcher;\n\n$customFetcher = new BasicHttpFetcher([\n    'timeout' =\u003e 60,\n    'user_agent' =\u003e 'MyApp/1.0',\n    'headers' =\u003e [\n        'Authorization' =\u003e 'Bearer ' . $token,\n    ],\n]);\n\n$result = PrismTransformer::url('https://api.example.com/data', $customFetcher)\n    -\u003eusing($dataProcessor)\n    -\u003etransform();\n```\n\n### Blocked Domains\n\nProtect your application from fetching content from untrusted or malicious\ndomains:\n\n```php\n// config/prism-transformer.php\n'content_fetcher' =\u003e [\n    'validation' =\u003e [\n        'blocked_domains' =\u003e [\n            'malicious-site.com',\n            '*.spam-domain.net',  // Wildcard pattern\n            'internal.local',\n        ],\n        'allowed_schemes' =\u003e ['http', 'https'],\n    ],\n],\n```\n\nThe blocked domains feature supports:\n\n- **Exact domain matching**: `example.com` blocks only that specific domain\n- **Wildcard patterns**: `*.example.com` blocks all subdomains\n- **Automatic validation**: Blocked URLs will throw a `FetchException`\n\n```php\n// This will throw FetchException\n$result = PrismTransformer::url('https://malicious-site.com/content')\n    -\u003eusing($transformer)\n    -\u003etransform(); // Throws: FetchException\n```\n\n## Error Handling\n\nThe package provides comprehensive error handling with support for both\nexceptions and PHP errors using `\\Throwable`:\n\n```php\n$result = PrismTransformer::text('problematic content')\n    -\u003eusing($complexTransformer)\n    -\u003etransform();\n\nif ($result-\u003eisSuccessful()) {\n    $content = $result-\u003egetContent();\n    $metadata = $result-\u003egetMetadata();\n} else {\n    $error = $result-\u003egetError();\n    Log::error(\"Transformation failed: {$error}\");\n\n    // Handle different types of failures\n    if (str_contains($error, 'rate limit')) {\n        // Implement retry logic\n    } elseif (str_contains($error, 'timeout')) {\n        // Handle timeout\n    }\n}\n```\n\n### Exception Types\n\n- `TransformerException`: General transformation errors\n- `FetchException`: Content fetching failures (including blocked domains)\n- `ValidationException`: Input validation errors\n- `InvalidInputException`: Invalid input data\n- `RateLimitExceededException`: Rate limit exceeded errors\n\n### Throwable Support\n\nThe package uses `\\Throwable` instead of `\\Exception` in error handling to catch\nboth user-defined exceptions and PHP internal errors (like `TypeError`). This is\nparticularly important for:\n\n- **Queue job failure handlers**: Jobs can fail due to type errors in PHP 8.3+\n- **Event dispatching**: `TransformationFailed` event accepts any throwable\n- **Robust error handling**: Catches all error types, not just exceptions\n\n```php\nuse Droath\\PrismTransformer\\Events\\TransformationFailed;\n\n// Listen for transformation failures\nEvent::listen(TransformationFailed::class, function (TransformationFailed $event) {\n    // $event-\u003eexception is \\Throwable (catches both Exception and Error)\n    Log::error('Transformation failed', [\n        'error' =\u003e $event-\u003eexception-\u003egetMessage(),\n        'type' =\u003e get_class($event-\u003eexception),\n        'content' =\u003e $event-\u003econtent,\n        'context' =\u003e $event-\u003econtext,\n    ]);\n});\n```\n\n## Events\n\nThe package dispatches events throughout the transformation lifecycle, allowing\nyou to hook into the process for monitoring, logging, and custom handling:\n\n### Available Events\n\n#### TransformationStarted\n\nDispatched when a transformation begins (sync or async):\n\n```php\nuse Droath\\PrismTransformer\\Events\\TransformationStarted;\n\nEvent::listen(TransformationStarted::class, function (TransformationStarted $event) {\n    Log::info('Transformation started', [\n        'content_preview' =\u003e is_string($event-\u003econtent)\n            ? substr($event-\u003econtent, 0, 50)\n            : get_class($event-\u003econtent),\n        'context' =\u003e $event-\u003econtext,\n    ]);\n});\n```\n\n**Event Properties:**\n\n- `content` (string|Media|null): The content being transformed\n- `context` (array): Additional context data\n\n#### TransformationCompleted\n\nDispatched when a transformation completes successfully:\n\n```php\nuse Droath\\PrismTransformer\\Events\\TransformationCompleted;\n\nEvent::listen(TransformationCompleted::class, function (TransformationCompleted $event) {\n    Log::info('Transformation completed', [\n        'success' =\u003e $event-\u003eresult-\u003eisSuccessful(),\n        'provider' =\u003e $event-\u003eresult-\u003egetMetadata()?-\u003eprovider-\u003evalue,\n        'model' =\u003e $event-\u003eresult-\u003egetMetadata()?-\u003emodel,\n        'context' =\u003e $event-\u003econtext,\n    ]);\n\n    // Track metrics, send notifications, etc.\n    Metrics::increment('transformations.success');\n});\n```\n\n**Event Properties:**\n\n- `result` (TransformerResult): The transformation result\n- `context` (array): Additional context data\n\n#### TransformationFailed\n\nDispatched when a transformation fails:\n\n```php\nuse Droath\\PrismTransformer\\Events\\TransformationFailed;\n\nEvent::listen(TransformationFailed::class, function (TransformationFailed $event) {\n    Log::error('Transformation failed', [\n        'error' =\u003e $event-\u003eexception-\u003egetMessage(),\n        'error_type' =\u003e get_class($event-\u003eexception),\n        'content' =\u003e $event-\u003econtent,\n        'context' =\u003e $event-\u003econtext,\n    ]);\n\n    // Send alert, track metrics, etc.\n    if ($event-\u003econtext['user_id'] ?? null) {\n        Notification::send(\n            User::find($event-\u003econtext['user_id']),\n            new TransformationFailedNotification($event-\u003eexception)\n        );\n    }\n});\n```\n\n**Event Properties:**\n\n- `exception` (\\Throwable): The exception that caused the failure\n- `content` (string|Media|null): The content being transformed\n- `context` (array): Additional context data\n\n### Event Usage Examples\n\n**Monitor All Transformations:**\n\n```php\n// In EventServiceProvider\nprotected $listen = [\n    TransformationStarted::class =\u003e [\n        LogTransformationStart::class,\n        TrackTransformationMetrics::class,\n    ],\n    TransformationCompleted::class =\u003e [\n        LogTransformationComplete::class,\n        UpdateUserCredits::class,\n    ],\n    TransformationFailed::class =\u003e [\n        LogTransformationFailure::class,\n        SendAdminAlert::class,\n    ],\n];\n```\n\n**Context-Aware Event Handling:**\n\n```php\n// Pass context for better tracking\n$result = PrismTransformer::text($content)\n    -\u003esetContext([\n        'user_id' =\u003e auth()-\u003eid(),\n        'request_id' =\u003e request()-\u003eid(),\n        'feature' =\u003e 'article_summarization',\n    ])\n    -\u003eusing($summarizer)\n    -\u003etransform();\n\n// Event listener can use context\nEvent::listen(TransformationCompleted::class, function ($event) {\n    if ($event-\u003econtext['feature'] === 'article_summarization') {\n        // Feature-specific handling\n    }\n});\n```\n\n## Testing\n\nRun the test suite:\n\n```bash\ncomposer test\n\n# Run specific test files\nvendor/bin/pest tests/Feature/TransformationPipelineIntegrationTest.php\n\n# Run with coverage\nvendor/bin/pest --coverage\n```\n\n### Testing Your Transformers\n\n```php\nuse Droath\\PrismTransformer\\PrismTransformer;\nuse Prism\\Prism\\Prism;\nuse Prism\\Prism\\Testing\\StructuredResponseFake;\nuse Prism\\Prism\\ValueObjects\\Usage;\nuse Tests\\TestCase;\n\nclass ArticleSummarizerTest extends TestCase\n{\n    public function test_summarizes_article_successfully()\n    {\n        $summarizer = app(ArticleSummarizer::class);\n\n        $content = \"Long article content here...\";\n\n        $result = (new PrismTransformer())\n            -\u003etext($content)\n            -\u003eusing($summarizer)\n            -\u003etransform();\n\n        expect($result-\u003eisSuccessful())-\u003etoBeTrue();\n        expect($result-\u003egetContent())-\u003etoBeString();\n        expect(strlen($result-\u003egetContent()))-\u003etoBeLessThan(strlen($content));\n    }\n\n    public function test_transforms_to_model_with_validation()\n    {\n        // Mock the AI response\n        $fakeResponse = StructuredResponseFake::make()\n            -\u003ewithStructured([\n                'name' =\u003e 'John Doe',\n                'email' =\u003e 'john@example.com',\n                'age' =\u003e 30,\n                'is_active' =\u003e true\n            ])\n            -\u003ewithUsage(new Usage(10, 20));\n\n        Prism::fake([$fakeResponse]);\n\n        $transformer = app(UserExtractor::class);\n\n        $result = (new PrismTransformer())\n            -\u003etext('Extract user: John Doe, email john@example.com, age 30, active')\n            -\u003eusing($transformer)\n            -\u003etransform();\n\n        expect($result-\u003eisSuccessful())-\u003etoBeTrue();\n\n        // Test model conversion with validation\n        $user = $result-\u003etoModel(User::class, [\n            'name' =\u003e 'required|string',\n            'email' =\u003e 'required|email',\n            'age' =\u003e 'required|integer|min:18'\n        ]);\n\n        expect($user)-\u003etoBeInstanceOf(User::class);\n        expect($user-\u003ename)-\u003etoBe('John Doe');\n        expect($user-\u003eemail)-\u003etoBe('john@example.com');\n        expect($user-\u003eage)-\u003etoBe(30);\n        expect($user-\u003eis_active)-\u003etoBeTrue();\n    }\n}\n```\n\n## Performance Optimization\n\n### Best Practices\n\n1. **Use Caching**: Enable caching for repeated transformations\n2. **Choose Appropriate Models**: Use smaller models for simple tasks\n3. **Batch Processing**: Process multiple items efficiently\n4. **Set Reasonable Timeouts**: Configure appropriate timeout values\n\n```php\n// Efficient batch processing\n$transformer = app(ContentClassifier::class);\n$items = collect($largeDataSet)\n    -\u003echunk(10) // Process in chunks\n    -\u003emap(function ($chunk) use ($transformer) {\n        return $chunk-\u003emap(function ($item) use ($transformer) {\n            return PrismTransformer::text($item)\n                -\u003eusing($transformer)\n                -\u003etransform();\n        });\n    })\n    -\u003eflatten();\n```\n\n## Advanced Configuration\n\n### Multiple Provider Setup\n\n```php\n// Use different providers for different tasks\nclass MultiProviderTransformer extends BaseTransformer\n{\n    public function provider(): Provider\n    {\n        // Use Anthropic for analysis, OpenAI for generation\n        return $this-\u003eisAnalysisTask ? Provider::ANTHROPIC : Provider::OPENAI;\n    }\n}\n```\n\n### Custom Cache Stores\n\n```php\n// config/prism-transformer.php\n'cache' =\u003e [\n    'store' =\u003e 'redis', // Use Redis for better performance\n    'prefix' =\u003e 'prism_v2',\n],\n```\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) for details on how to contribute to\nthis package.\n\n## Security\n\nIf you discover any security-related issues, please contact us directly\ninstead of using the issue tracker.\n\n## Credits\n\n- [Travis Tomka](https://github.com/droath)\n- [All Contributors](../../contributors)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more\ninformation.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdroath%2Fprism-transformer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdroath%2Fprism-transformer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdroath%2Fprism-transformer/lists"}