├── .github └── workflows │ ├── format.yml │ └── test.yml ├── .gitignore ├── README.md ├── composer.json ├── image └── usage.gif ├── phpunit.xml.dist ├── pint.json ├── src ├── FakerOpenAIServiceProvider.php ├── Providers │ └── FakerOpenAIPromptProvider.php └── config.php ├── testbench.yaml └── tests └── FakerOpenAITest.php /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | name: Format Code 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | format: 11 | runs-on: ubuntu-24.04 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Setup PHP 17 | uses: shivammathur/setup-php@v2 18 | with: 19 | php-version: '8.2' 20 | coverage: none 21 | 22 | - name: Install Dependencies 23 | run: composer install --no-interaction --prefer-dist 24 | 25 | - name: Run Laravel Pint 26 | run: composer format -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Run Tests 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-24.04 12 | strategy: 13 | matrix: 14 | php: ['8.2', '8.3', '8.4'] 15 | fail-fast: false 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: Setup PHP 21 | uses: shivammathur/setup-php@v2 22 | with: 23 | php-version: ${{ matrix.php }} 24 | coverage: xdebug 25 | 26 | - name: Install Dependencies 27 | run: composer install --no-interaction --prefer-dist 28 | 29 | - name: Run PHPUnit Tests 30 | run: composer test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | build 3 | composer.lock 4 | vendor 5 | .phpunit.result.cache 6 | .php-cs-fixer.cache 7 | .phpunit.cache 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Faker OpenAI Provider 2 | 3 | ![Tests](https://github.com/jpcaparas/laravel-faker-openai/actions/workflows/test.yml/badge.svg) 4 | 5 |

6 | Usage 7 |

8 | 9 | A Laravel package that extends FakerPHP by adding an AI-powered data generator using OpenAI. This allows you to generate more realistic and context-aware fake data in your Laravel applications. 10 | 11 | ## Installation 12 | 13 | Install the package via Composer: 14 | 15 | ```bash 16 | composer require jpcaparas/laravel-faker-openai 17 | ``` 18 | 19 | The package will automatically register its service provider if you're using Laravel's package auto-discovery. 20 | 21 | ## Configuration 22 | 23 | 1. Next, execute the install command: 24 | 25 | ```bash 26 | php artisan openai:install 27 | ``` 28 | 29 | This will create a `config/openai.php` configuration file in your project, which you can modify to your needs using environment variables. 30 | 31 | 2. Make sure you have your OpenAI API key set in your `.env` file: 32 | 33 | ```env 34 | OPENAI_API_KEY=your-api-key-here 35 | ``` 36 | 37 | 3. The package uses `gpt-3.5-turbo` model by default. 38 | 39 | ## Usage 40 | 41 | The package adds a new `promptAI()` method to the Faker generator. You can use it in several ways: 42 | 43 | ### Basic Usage 44 | 45 | ```php 46 | $faker = app(\Faker\Generator::class); 47 | 48 | // Generate a fake name using AI 49 | $name = $faker->promptAI('name'); 50 | 51 | // Generate a movie review 52 | $review = $faker->promptAI('movieReview'); 53 | 54 | // Generate a movie description 55 | $description = $faker->promptAI('movieDescription'); 56 | ``` 57 | 58 | ... you can also use the built-in `fake()` helper: 59 | 60 | ```php 61 | $name = fake('name'); 62 | ``` 63 | 64 | ### With Fallback Values 65 | 66 | You can provide fallback values that will be used if the AI request fails: 67 | 68 | ```php 69 | // String fallback 70 | $name = $faker->promptAI('name', 'John Doe'); 71 | 72 | // Closure fallback 73 | $name = $faker->promptAI('name', fn() => 'John Doe'); 74 | ``` 75 | 76 | ### Error Handling 77 | 78 | By default, errors are logged and the fallback value is returned. You can make it throw exceptions instead: 79 | 80 | ```php 81 | try { 82 | $name = $faker->promptAI('name', null, true); // Set throwOnError to true 83 | } catch (\Exception $e) { 84 | // Handle the error 85 | } 86 | ``` 87 | 88 | ## How It Works 89 | 90 | The package works by: 91 | 1. Intercepting FakerPHP method calls through a prompt 92 | 2. Sending them to OpenAI's GPT model 93 | 3. Returning AI-generated responses that match FakerPHP's expected output format 94 | 95 | ## Testing 96 | 97 | Run the test suite: 98 | 99 | ```bash 100 | composer test 101 | ``` 102 | 103 | ## License 104 | MIT 105 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jpcaparas/laravel-faker-openai", 3 | "description": "An opinionated Laravel package that modifies the service container Faker behaviour to allow prompts to be generated with OpenAI", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "JP Caparas", 8 | "email": "jp@jpcaparas.com" 9 | } 10 | ], 11 | "type": "library", 12 | "autoload": { 13 | "psr-4": { 14 | "JPCaparas\\FakerOpenAI\\": "src/" 15 | } 16 | }, 17 | "autoload-dev": { 18 | "psr-4": { 19 | "JPCaparas\\FakerOpenAI\\Tests\\": "tests/" 20 | } 21 | }, 22 | "require": { 23 | "php": "^8.2", 24 | "fakerphp/faker": "^1.24", 25 | "laravel/framework": "^10.0 || ^11.0", 26 | "nyholm/psr7": "^1.8", 27 | "openai-php/laravel": "^0.10.2", 28 | "symfony/http-client": "^7.2" 29 | }, 30 | "config": { 31 | "sort-packages": true, 32 | "allow-plugins": { 33 | "php-http/discovery": true 34 | } 35 | }, 36 | "require-dev": { 37 | "laravel/pint": "^1.19", 38 | "orchestra/testbench": "*" 39 | }, 40 | "extra": { 41 | "laravel": { 42 | "providers": [ 43 | "JPCaparas\\FakerOpenAI\\FakerOpenAIServiceProvider" 44 | ] 45 | } 46 | }, 47 | "scripts": { 48 | "format": "pint", 49 | "tests": "phpunit", 50 | "tinker": "testbench tinker" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /image/usage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpcaparas/laravel-faker-openai/ba31fafe707c0139ffd5d78920bd4fe5fadbfcae/image/usage.gif -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | tests 10 | 11 | 12 | 13 | 14 | src 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "laravel" 3 | } -------------------------------------------------------------------------------- /src/FakerOpenAIServiceProvider.php: -------------------------------------------------------------------------------- 1 | registerFakerGenerator(); 22 | } 23 | 24 | public function boot() 25 | { 26 | // 27 | } 28 | 29 | /** 30 | * Overridden the default Faker generator to include custom providers. 31 | * 32 | * @see \Illuminate\Database\DatabaseServiceProvider::registerFakerGenerator() 33 | */ 34 | protected function registerFakerGenerator(): void 35 | { 36 | $this->app->singleton(FakerGenerator::class, function ($app, $parameters) { 37 | $locale = $parameters['locale'] ?? $app['config']->get('app.faker_locale', 'en_US'); 38 | 39 | if (! isset(static::$fakers[$locale])) { 40 | $fakerFactory = FakerFactory::create($locale); 41 | 42 | $fakerFactory->addProvider(new FakerOpenAIPromptProvider); 43 | 44 | static::$fakers[$locale] = $fakerFactory; 45 | } 46 | 47 | static::$fakers[$locale]->unique(true); 48 | 49 | return static::$fakers[$locale]; 50 | }); 51 | 52 | // For usage on the `faker()` helper, which requires the locale to be set. 53 | $fakerLocale = $this->app['config']->get('app.faker_locale', 'en_US'); 54 | $this->app->alias(FakerGenerator::class, FakerGenerator::class.':'.$fakerLocale); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Providers/FakerOpenAIPromptProvider.php: -------------------------------------------------------------------------------- 1 | promptAI('name') 23 | * @example $faker->promptAI('movieReview') // This will return a movie review 24 | * @example $faker->promptAI('movieDescription') // This will return a movie description 25 | * @example $faker->promptAI('name', 'John Doe') // This defaults to 'John Doe' if an error occurs 26 | * @example $faker->promptAI('name', fn() => 'John Doe') // This defaults to 'John Doe' if an error occurs 27 | * @example $faker->promptAI('randomNumber', fn() => 99) // This defaults to 99 if an error occurs (but why would you do this?) 28 | */ 29 | public function promptAI(string $term, null|string|callable $fallback = null, $throwOnError = false): mixed 30 | { 31 | try { 32 | $result = OpenAI::chat()->create([ 33 | 'model' => 'gpt-3.5-turbo', 34 | 'messages' => [ 35 | [ 36 | 'role' => 'user', 37 | 'content' => 'Return only the output value of \Faker\Factory::create()->'.Str::camel($term).'() without any explanation or formatting. A simple string, please.', 38 | ], 39 | ], 40 | ]); 41 | 42 | return $result->choices[0]->message->content; 43 | } catch (ErrorException|TransporterException $e) { 44 | if ($throwOnError) { 45 | throw $e; 46 | } 47 | 48 | Log::error($e->getMessage()); 49 | 50 | if (is_string($fallback)) { 51 | return $fallback; 52 | } 53 | 54 | if (is_callable($fallback)) { 55 | return $fallback(); 56 | } 57 | 58 | return null; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/config.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'model' => env('OPENAI_MODEL', 'text-davinci-003'), 6 | 'default_prompt' => env('OPENAI_DEFAULT_PROMPT', 'Generate fake data'), 7 | ], 8 | ]; 9 | -------------------------------------------------------------------------------- /testbench.yaml: -------------------------------------------------------------------------------- 1 | providers: 2 | - OpenAI\Laravel\ServiceProvider 3 | - JPCaparas\FakerOpenAI\FakerOpenAIServiceProvider 4 | -------------------------------------------------------------------------------- /tests/FakerOpenAITest.php: -------------------------------------------------------------------------------- 1 | app->make(FakerGenerator::class); 28 | 29 | $this->assertInstanceOf(FakerGenerator::class, $faker); 30 | } 31 | 32 | public function test_it_registers_ai_prompt_provider() 33 | { 34 | $faker = $this->app->make(FakerGenerator::class); 35 | 36 | $providers = array_map(fn($provider) => get_class($provider), $faker->getProviders()); 37 | 38 | $this->assertContains(FakerOpenAIPromptProvider::class, $providers); 39 | } 40 | 41 | public function test_prompt_ai_returns_generated_content() 42 | { 43 | OpenAI::fake([ 44 | CreateResponse::fake(), 45 | ]); 46 | 47 | $faker = $this->app->make(FakerGenerator::class); 48 | $response = $faker->promptAI('test prompt'); 49 | $this->assertNotEmpty($response, 'No response from OpenAI API'); 50 | } 51 | } 52 | --------------------------------------------------------------------------------