diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index c68765b..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: :vendor_name diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 96701be..6667b30 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,11 +1,11 @@ blank_issues_enabled: false contact_links: - name: Ask a question - url: https://github.com/:vendor_name/:package_name/discussions/new?category=q-a + url: https://github.com/halilcosdu/laravel-finetuner/discussions/new?category=q-a about: Ask the community for help - name: Request a feature - url: https://github.com/:vendor_name/:package_name/discussions/new?category=ideas + url: https://github.com/halilcosdu/laravel-finetuner/discussions/new?category=ideas about: Share ideas for new features - name: Report a security issue - url: https://github.com/:vendor_name/:package_name/security/policy + url: https://github.com/halilcosdu/laravel-finetuner/security/policy about: Learn how to notify us for sensitive bugs diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index f495e76..d5db2f1 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -18,7 +18,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: '8.2' coverage: none - name: Install composer dependencies diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index f7492c5..70268a3 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -16,14 +16,14 @@ jobs: strategy: fail-fast: true matrix: - os: [ubuntu-latest, windows-latest] - php: [8.3, 8.2, 8.1] - laravel: [10.*] - stability: [prefer-lowest, prefer-stable] + os: [ ubuntu-latest ] + php: [ 8.3, 8.2 ] + laravel: [ 11.*] + stability: [ prefer-lowest, prefer-stable ] include: - - laravel: 10.* - testbench: 8.* - carbon: ^2.63 + - laravel: 11.* + testbench: 9.* + carbon: ^3.0 name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 87b3242..e9a783e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,3 @@ # Changelog -All notable changes to `:package_name` will be documented in this file. +All notable changes to `laravel-finetuner` will be documented in this file. diff --git a/LICENSE.md b/LICENSE.md index 58c9ad4..bc181dc 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) :vendor_name +Copyright (c) HalilCosdu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 375da96..74b12b9 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,44 @@ -# :package_description - -[![Latest Version on Packagist](https://img.shields.io/packagist/v/:vendor_slug/:package_slug.svg?style=flat-square)](https://packagist.org/packages/:vendor_slug/:package_slug) -[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/:vendor_slug/:package_slug/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/:vendor_slug/:package_slug/actions?query=workflow%3Arun-tests+branch%3Amain) -[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/:vendor_slug/:package_slug/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/:vendor_slug/:package_slug/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) -[![Total Downloads](https://img.shields.io/packagist/dt/:vendor_slug/:package_slug.svg?style=flat-square)](https://packagist.org/packages/:vendor_slug/:package_slug) - ---- -This repo can be used to scaffold a Laravel package. Follow these steps to get started: - -1. Press the "Use this template" button at the top of this repo to create a new repo with the contents of this skeleton. -2. Run "php ./configure.php" to run a script that will replace all placeholders throughout all the files. -3. Have fun creating your package. -4. If you need help creating a package, consider picking up our Laravel Package Training video course. ---- - -This is where your description should go. Limit it to a paragraph or two. Consider adding a small example. - -## Support us - -[](https://spatie.be/github-ad-click/:package_name) +# Laravel Finetuner is a package designed for the Laravel framework that automates the fine-tuning of OpenAI models. It simplifies the process of adjusting model parameters to optimize performance, tailored specifically for Laravel applications. This tool is ideal for developers looking to enhance AI capabilities in their projects efficiently, with minimal manual intervention. -We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). +[![Latest Version on Packagist](https://img.shields.io/packagist/v/halilcosdu/laravel-finetuner.svg?style=flat-square)](https://packagist.org/packages/halilcosdu/laravel-finetuner) +[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/halilcosdu/laravel-finetuner/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/halilcosdu/laravel-finetuner/actions?query=workflow%3Arun-tests+branch%3Amain) +[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/halilcosdu/laravel-finetuner/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/halilcosdu/laravel-finetuner/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) +[![Total Downloads](https://img.shields.io/packagist/dt/halilcosdu/laravel-finetuner.svg?style=flat-square)](https://packagist.org/packages/halilcosdu/laravel-finetuner) -We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). +This is where your description should go. Limit it to a paragraph or two. Consider adding a small example. ## Installation You can install the package via composer: ```bash -composer require :vendor_slug/:package_slug -``` - -You can publish and run the migrations with: - -```bash -php artisan vendor:publish --tag=":package_slug-migrations" -php artisan migrate +composer require halilcosdu/laravel-finetuner ``` You can publish the config file with: ```bash -php artisan vendor:publish --tag=":package_slug-config" +php artisan vendor:publish --tag="finetuner-config" ``` This is the contents of the published config file: ```php return [ -]; -``` - -Optionally, you can publish the views using - -```bash -php artisan vendor:publish --tag=":package_slug-views" + 'api_key' => env('OPENAI_API_KEY'), + 'organization' => env('OPENAI_ORGANIZATION'), + 'request_timeout' => env('OPENAI_TIMEOUT'), + 'use_storage' => env('FINE_TUNER_USE_STORAGE', false), + 'storage' => [ + 'disk' => env('FINE_TUNER_STORAGE', 'local'), + ], ``` ## Usage ```php -$variable = new VendorName\Skeleton(); -echo $variable->echoPhrase('Hello, VendorName!'); +$fineTuner = new HalilCosdu\FineTuner(); +echo $fineTuner->echoPhrase('Hello, HalilCosdu!'); ``` ## Testing @@ -85,7 +61,7 @@ Please review [our security policy](../../security/policy) on how to report secu ## Credits -- [:author_name](https://github.com/:author_username) +- [Halil Cosdu](https://github.com/halilcosdu) - [All Contributors](../../contributors) ## License diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..2363bc1 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are currently being supported with security updates. + +| Version | Supported | +|---------| ------------------ | +| 1.0.x | :white_check_mark: | + +## Reporting a Vulnerability + +Use this section to tell people how to report a vulnerability. + +If you discover a security vulnerability within this project, please send an email to halilcosdu@gmail.com. All security vulnerabilities will be promptly addressed. + +Please do not publicly disclose the issue until it has been addressed by the team. + +## Security Updates + +Use this section to tell people where and how they will receive updates about security. + +We will push the updates for security vulnerabilities to the main branch of this repository. We recommend always using the latest stable version of the project. + +## More Information + +If you have any other questions, please contact us at halilcosdu@gmail.com. diff --git a/composer.json b/composer.json index 65e9908..ff1e70d 100644 --- a/composer.json +++ b/composer.json @@ -1,24 +1,25 @@ { - "name": ":vendor_slug/:package_slug", - "description": ":package_description", + "name": "halilcosdu/laravel-finetuner", + "description": "Laravel Fine tuner is a package designed for the Laravel framework that automates the fine-tuning of OpenAI models. It simplifies the process of adjusting model parameters to optimize performance, tailored specifically for Laravel applications. This tool is ideal for developers looking to enhance AI capabilities in their projects efficiently, with minimal manual intervention.", "keywords": [ - ":vendor_name", + "HalilCosdu", "laravel", - ":package_slug" + "laravel-finetuner" ], - "homepage": "https://github.com/:vendor_slug/:package_slug", + "homepage": "https://github.com/halilcosdu/laravel-finetuner", "license": "MIT", "authors": [ { - "name": ":author_name", - "email": "author@domain.com", + "name": "Halil Cosdu", + "email": "halilcosdu@gmail.com", "role": "Developer" } ], "require": { "php": "^8.2", - "spatie/laravel-package-tools": "^1.16", - "illuminate/contracts": "^10.0||^11.0" + "illuminate/contracts": "^10.0||^11.0", + "openai-php/laravel": "^0.8.1", + "spatie/laravel-package-tools": "^1.16" }, "require-dev": { "laravel/pint": "^1.14", @@ -35,19 +36,19 @@ }, "autoload": { "psr-4": { - "VendorName\\Skeleton\\": "src/", - "VendorName\\Skeleton\\Database\\Factories\\": "database/factories/" + "HalilCosdu\\FineTuner\\": "src/", + "HalilCosdu\\FineTuner\\Database\\Factories\\": "database/factories/" } }, "autoload-dev": { "psr-4": { - "VendorName\\Skeleton\\Tests\\": "tests/", + "HalilCosdu\\FineTuner\\Tests\\": "tests/", "Workbench\\App\\": "workbench/app/" } }, "scripts": { "post-autoload-dump": "@composer run prepare", - "clear": "@php vendor/bin/testbench package:purge-skeleton --ansi", + "clear": "@php vendor/bin/testbench package:purge-laravel-finetuner --ansi", "prepare": "@php vendor/bin/testbench package:discover --ansi", "build": [ "@composer run prepare", @@ -67,16 +68,17 @@ "sort-packages": true, "allow-plugins": { "pestphp/pest-plugin": true, - "phpstan/extension-installer": true + "phpstan/extension-installer": true, + "php-http/discovery": true } }, "extra": { "laravel": { "providers": [ - "VendorName\\Skeleton\\SkeletonServiceProvider" + "HalilCosdu\\FineTuner\\FineTunerServiceProvider" ], "aliases": { - "Skeleton": "VendorName\\Skeleton\\Facades\\Skeleton" + "FineTuner": "HalilCosdu\\FineTuner\\Facades\\FineTuner" } } }, diff --git a/config/finetuner.php b/config/finetuner.php new file mode 100644 index 0000000..111fffd --- /dev/null +++ b/config/finetuner.php @@ -0,0 +1,12 @@ + env('OPENAI_API_KEY'), + 'organization' => env('OPENAI_ORGANIZATION'), + 'request_timeout' => env('OPENAI_TIMEOUT'), + 'use_storage' => env('FINE_TUNER_USE_STORAGE', false), + 'storage' => [ + 'disk' => env('FINE_TUNER_STORAGE', 'local'), + ], +]; diff --git a/config/skeleton.php b/config/skeleton.php deleted file mode 100644 index 7e74186..0000000 --- a/config/skeleton.php +++ /dev/null @@ -1,6 +0,0 @@ - $version) { - if (in_array($name, $names, true)) { - unset($data['require-dev'][$name]); - } - } - - file_put_contents(__DIR__.'/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); -} - -function remove_composer_script($scriptName) -{ - $data = json_decode(file_get_contents(__DIR__.'/composer.json'), true); - - foreach ($data['scripts'] as $name => $script) { - if ($scriptName === $name) { - unset($data['scripts'][$name]); - break; - } - } - - file_put_contents(__DIR__.'/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); -} - -function remove_readme_paragraphs(string $file): void -{ - $contents = file_get_contents($file); - - file_put_contents( - $file, - preg_replace('/.*/s', '', $contents) ?: $contents - ); -} - -function safeUnlink(string $filename) -{ - if (file_exists($filename) && is_file($filename)) { - unlink($filename); - } -} - -function determineSeparator(string $path): string -{ - return str_replace('/', DIRECTORY_SEPARATOR, $path); -} - -function replaceForWindows(): array -{ - return preg_split('/\\r\\n|\\r|\\n/', run('dir /S /B * | findstr /v /i .git\ | findstr /v /i vendor | findstr /v /i '.basename(__FILE__).' | findstr /r /i /M /F:/ ":author :vendor :package VendorName skeleton migration_table_name vendor_name vendor_slug author@domain.com"')); -} - -function replaceForAllOtherOSes(): array -{ - return explode(PHP_EOL, run('grep -E -r -l -i ":author|:vendor|:package|VendorName|skeleton|migration_table_name|vendor_name|vendor_slug|author@domain.com" --exclude-dir=vendor ./* ./.github/* | grep -v '.basename(__FILE__))); -} - -function getGitHubApiEndpoint(string $endpoint): ?stdClass -{ - try { - $curl = curl_init("https://api.github.com/{$endpoint}"); - curl_setopt_array($curl, [ - CURLOPT_RETURNTRANSFER => true, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_HTTPGET => true, - CURLOPT_HTTPHEADER => [ - 'User-Agent: spatie-configure-script/1.0', - ], - ]); - - $response = curl_exec($curl); - $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); - - curl_close($curl); - - if ($statusCode === 200) { - return json_decode($response); - } - } catch (Exception $e) { - // ignore - } - - return null; -} - -function searchCommitsForGitHubUsername(): string -{ - $authorName = strtolower(trim(shell_exec('git config user.name'))); - - $committersRaw = shell_exec("git log --author='@users.noreply.github.com' --pretty='%an:%ae' --reverse"); - $committersLines = explode("\n", $committersRaw ?? ''); - $committers = array_filter(array_map(function ($line) use ($authorName) { - $line = trim($line); - [$name, $email] = explode(':', $line) + [null, null]; - - return [ - 'name' => $name, - 'email' => $email, - 'isMatch' => strtolower($name) === $authorName && ! str_contains($name, '[bot]'), - ]; - }, $committersLines), fn ($item) => $item['isMatch']); - - if (empty($committers)) { - return ''; - } - - $firstCommitter = reset($committers); - - return explode('@', $firstCommitter['email'])[0] ?? ''; -} - -function guessGitHubUsernameUsingCli() -{ - try { - if (preg_match('/ogged in to github\.com as ([a-zA-Z-_]+).+/', shell_exec('gh auth status -h github.com 2>&1'), $matches)) { - return $matches[1]; - } - } catch (Exception $e) { - // ignore - } - - return ''; -} - -function guessGitHubUsername(): string -{ - $username = searchCommitsForGitHubUsername(); - if (! empty($username)) { - return $username; - } - - $username = guessGitHubUsernameUsingCli(); - if (! empty($username)) { - return $username; - } - - // fall back to using the username from the git remote - $remoteUrl = shell_exec('git config remote.origin.url'); - $remoteUrlParts = explode('/', str_replace(':', '/', trim($remoteUrl))); - - return $remoteUrlParts[1] ?? ''; -} - -function guessGitHubVendorInfo($authorName, $username): array -{ - $remoteUrl = shell_exec('git config remote.origin.url'); - $remoteUrlParts = explode('/', str_replace(':', '/', trim($remoteUrl))); - - $response = getGitHubApiEndpoint("orgs/{$remoteUrlParts[1]}"); - - if ($response === null) { - return [$authorName, $username]; - } - - return [$response->name ?? $authorName, $response->login ?? $username]; -} - -$gitName = run('git config user.name'); -$authorName = ask('Author name', $gitName); - -$gitEmail = run('git config user.email'); -$authorEmail = ask('Author email', $gitEmail); -$authorUsername = ask('Author username', guessGitHubUsername()); - -$guessGitHubVendorInfo = guessGitHubVendorInfo($authorName, $authorUsername); - -$vendorName = ask('Vendor name', $guessGitHubVendorInfo[0]); -$vendorUsername = ask('Vendor username', $guessGitHubVendorInfo[1] ?? slugify($vendorName)); -$vendorSlug = slugify($vendorUsername); - -$vendorNamespace = str_replace('-', '', ucwords($vendorName)); -$vendorNamespace = ask('Vendor namespace', $vendorNamespace); - -$currentDirectory = getcwd(); -$folderName = basename($currentDirectory); - -$packageName = ask('Package name', $folderName); -$packageSlug = slugify($packageName); -$packageSlugWithoutPrefix = remove_prefix('laravel-', $packageSlug); - -$className = title_case($packageName); -$className = ask('Class name', $className); -$variableName = lcfirst($className); -$description = ask('Package description', "This is my package {$packageSlug}"); - -$usePhpStan = confirm('Enable PhpStan?', true); -$useLaravelPint = confirm('Enable Laravel Pint?', true); -$useDependabot = confirm('Enable Dependabot?', true); -$useLaravelRay = confirm('Use Ray for debugging?', true); -$useUpdateChangelogWorkflow = confirm('Use automatic changelog updater workflow?', true); - -writeln('------'); -writeln("Author : {$authorName} ({$authorUsername}, {$authorEmail})"); -writeln("Vendor : {$vendorName} ({$vendorSlug})"); -writeln("Package : {$packageSlug} <{$description}>"); -writeln("Namespace : {$vendorNamespace}\\{$className}"); -writeln("Class name : {$className}"); -writeln('---'); -writeln('Packages & Utilities'); -writeln('Use Laravel/Pint : '.($useLaravelPint ? 'yes' : 'no')); -writeln('Use Larastan/PhpStan : '.($usePhpStan ? 'yes' : 'no')); -writeln('Use Dependabot : '.($useDependabot ? 'yes' : 'no')); -writeln('Use Ray App : '.($useLaravelRay ? 'yes' : 'no')); -writeln('Use Auto-Changelog : '.($useUpdateChangelogWorkflow ? 'yes' : 'no')); -writeln('------'); - -writeln('This script will replace the above values in all relevant files in the project directory.'); - -if (! confirm('Modify files?', true)) { - exit(1); -} - -$files = (str_starts_with(strtoupper(PHP_OS), 'WIN') ? replaceForWindows() : replaceForAllOtherOSes()); - -foreach ($files as $file) { - replace_in_file($file, [ - ':author_name' => $authorName, - ':author_username' => $authorUsername, - 'author@domain.com' => $authorEmail, - ':vendor_name' => $vendorName, - ':vendor_slug' => $vendorSlug, - 'VendorName' => $vendorNamespace, - ':package_name' => $packageName, - ':package_slug' => $packageSlug, - ':package_slug_without_prefix' => $packageSlugWithoutPrefix, - 'Skeleton' => $className, - 'skeleton' => $packageSlug, - 'migration_table_name' => title_snake($packageSlug), - 'variable' => $variableName, - ':package_description' => $description, - ]); - - match (true) { - str_contains($file, determineSeparator('src/Skeleton.php')) => rename($file, determineSeparator('./src/'.$className.'.php')), - str_contains($file, determineSeparator('src/SkeletonServiceProvider.php')) => rename($file, determineSeparator('./src/'.$className.'ServiceProvider.php')), - str_contains($file, determineSeparator('src/Facades/Skeleton.php')) => rename($file, determineSeparator('./src/Facades/'.$className.'.php')), - str_contains($file, determineSeparator('src/Commands/SkeletonCommand.php')) => rename($file, determineSeparator('./src/Commands/'.$className.'Command.php')), - str_contains($file, determineSeparator('database/migrations/create_skeleton_table.php.stub')) => rename($file, determineSeparator('./database/migrations/create_'.title_snake($packageSlugWithoutPrefix).'_table.php.stub')), - str_contains($file, determineSeparator('config/skeleton.php')) => rename($file, determineSeparator('./config/'.$packageSlugWithoutPrefix.'.php')), - str_contains($file, 'README.md') => remove_readme_paragraphs($file), - default => [], - }; -} - -if (! $useLaravelPint) { - safeUnlink(__DIR__.'/.github/workflows/fix-php-code-style-issues.yml'); - safeUnlink(__DIR__.'/pint.json'); -} - -if (! $usePhpStan) { - safeUnlink(__DIR__.'/phpstan.neon.dist'); - safeUnlink(__DIR__.'/phpstan-baseline.neon'); - safeUnlink(__DIR__.'/.github/workflows/phpstan.yml'); - - remove_composer_deps([ - 'phpstan/extension-installer', - 'phpstan/phpstan-deprecation-rules', - 'phpstan/phpstan-phpunit', - 'larastan/larastan', - ]); - - remove_composer_script('phpstan'); -} - -if (! $useDependabot) { - safeUnlink(__DIR__.'/.github/dependabot.yml'); - safeUnlink(__DIR__.'/.github/workflows/dependabot-auto-merge.yml'); -} - -if (! $useLaravelRay) { - remove_composer_deps(['spatie/laravel-ray']); -} - -if (! $useUpdateChangelogWorkflow) { - safeUnlink(__DIR__.'/.github/workflows/update-changelog.yml'); -} - -confirm('Execute `composer install` and run tests?') && run('composer install && composer test'); - -confirm('Let this script delete itself?', true) && unlink(__FILE__); diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php deleted file mode 100644 index c51604f..0000000 --- a/database/factories/ModelFactory.php +++ /dev/null @@ -1,19 +0,0 @@ -id(); - - // add fields - - $table->timestamps(); - }); - } -}; diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 489fa4e..90a0254 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,9 +6,7 @@ parameters: paths: - src - config - - database tmpDir: build/phpstan checkOctaneCompatibility: true checkModelProperties: true checkMissingIterableValueType: false - diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4c61042..e4b2011 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -16,7 +16,7 @@ backupStaticProperties="false" > - + tests diff --git a/resources/views/.gitkeep b/resources/views/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/Commands/SkeletonCommand.php b/src/Commands/FineTunerCommand.php similarity index 61% rename from src/Commands/SkeletonCommand.php rename to src/Commands/FineTunerCommand.php index 3e5f628..94462c7 100644 --- a/src/Commands/SkeletonCommand.php +++ b/src/Commands/FineTunerCommand.php @@ -1,12 +1,12 @@ client = OpenAIFactory::factory() + ->withApiKey(config('finetuner.api_key')) + ->withOrganization(config('finetuner.organization')) + ->withHttpClient(new \GuzzleHttp\Client(['timeout' => config('finetuner.request_timeout', 600)])) + ->make(); + } + + private function example($prompt, $prevExamples, $temperature = .5): ?string + { + $messages = [ + [ + 'role' => 'system', + 'content' => "You are generating data which will be used to train a machine learning model.\n\nYou will be given a high-level description of the model we want to train, and from that, you will generate data samples, each with a prompt/response pair.\n\nYou will do so in this format:\n```\nprompt\n-----------\n\$prompt_goes_here\n-----------\n\nresponse\n-----------\n\$response_goes_here\n-----------\n```\n\nOnly one prompt/response pair should be generated per turn.\n\nFor each turn, make the example slightly more complex than the last, while ensuring diversity.\n\nMake sure your samples are unique and diverse, yet high-quality and complex enough to train a well-performing model.\n\nHere is the type of model we want to train:\n`{$prompt}`"], + ]; + + if (count($prevExamples) > 0) { + if (count($prevExamples) > 8) { + $prevExamples = array_rand($prevExamples, 8); + } + foreach ($prevExamples as $example) { + $messages[] = [ + 'role' => 'assistant', + 'content' => $example, + ]; + } + } + + $response = $this->client->chat()->create([ + 'model' => 'gpt-4', + 'messages' => $messages, + 'temperature' => $temperature, + ]); + + return $response->choices[0]->message->content; + } + + public function generateExamples($prompt, $temperature = .4, $numberOfExamples = 2): array + { + $prevExamples = []; + for ($i = 0; $i < $numberOfExamples; $i++) { + Sleep::sleep(0.1); + $example = $this->example($prompt, $prevExamples, $temperature); + $prevExamples[] = $example; + } + + return $this->saveTrainingExamples($prevExamples, $this->generateSystemMessage($prompt, $temperature)); + } + + private function generateSystemMessage($prompt, $temperature = .5): ?string + { + $response = $this->client->chat()->create([ + 'model' => 'gpt-4', + 'messages' => [ + [ + 'role' => 'system', + 'content' => "You will be given a high-level description of the model we are training, and from that, you will generate a simple system prompt for that model to use. Remember, you are not generating the system message for data generation -- you are generating the system message to use for inference. A good format to follow is `Given \$INPUT_DATA, you will \$WHAT_THE_MODEL_SHOULD_DO.`.\n\nMake it as concise as possible. Include nothing but the system prompt in your response.\n\nFor example, never write: `\"\$SYSTEM_PROMPT_HERE\"`.\n\nIt should be like: `\$SYSTEM_PROMPT_HERE`.", + ], + [ + 'role' => 'user', + 'content' => $prompt, + ], + ], + 'temperature' => $temperature, + ]); + + return $response->choices[0]->message->content; + } + + private function saveTrainingExamples($prevExamples, $systemMessage): array + { + $trainingExamples = []; + foreach ($prevExamples as $example) { + $splitExample = explode('-----------', $example); + if (count($splitExample) >= 4) { + $trainingExample = [ + 'messages' => [ + ['role' => 'system', 'content' => $systemMessage], + ['role' => 'user', 'content' => trim($splitExample[1])], + ['role' => 'assistant', 'content' => trim($splitExample[3])], + ], + ]; + $trainingExamples[] = $trainingExample; + } + } + + if (config('finetuner.use_storage')) { + Storage::disk(config('finetuner.storage.disk'))->put('training_data.jsonl', json_encode($trainingExamples)); + } + + return $trainingExamples; + } + + public function upload(string $file): string + { + $file = $this->client->files()->upload([ + 'file' => fopen($file, 'r'), + 'purpose' => 'fine-tune', + ]); + + return $file->id; + } + + public function fineTune(string $fileId, string $model = 'gpt-3.5-turbo'): string + { + $fineTune = $this->client->fineTuning()->createJob([ + 'model' => $model, + 'training_file' => $fileId, + ]); + + return $fineTune->id; + } +} diff --git a/src/SkeletonServiceProvider.php b/src/FineTunerServiceProvider.php similarity index 56% rename from src/SkeletonServiceProvider.php rename to src/FineTunerServiceProvider.php index 618b267..8630480 100644 --- a/src/SkeletonServiceProvider.php +++ b/src/FineTunerServiceProvider.php @@ -1,12 +1,12 @@ name('skeleton') + ->name('laravel-finetuner') ->hasConfigFile() - ->hasViews() - ->hasMigration('create_skeleton_table') - ->hasCommand(SkeletonCommand::class); + ->hasCommand(FineTunerCommand::class); } } diff --git a/src/Skeleton.php b/src/Skeleton.php deleted file mode 100755 index 66fab60..0000000 --- a/src/Skeleton.php +++ /dev/null @@ -1,7 +0,0 @@ -in(__DIR__); diff --git a/tests/TestCase.php b/tests/TestCase.php index d04fb0c..f03d5a6 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,10 +1,10 @@ 'VendorName\\Skeleton\\Database\\Factories\\'.class_basename($modelName).'Factory' + fn (string $modelName) => 'HalilCosdu\\FineTuner\\Database\\Factories\\'.class_basename($modelName).'Factory' ); } protected function getPackageProviders($app) { return [ - SkeletonServiceProvider::class, + FineTunerServiceProvider::class, ]; } @@ -29,7 +29,7 @@ public function getEnvironmentSetUp($app) config()->set('database.default', 'testing'); /* - $migration = include __DIR__.'/../database/migrations/create_skeleton_table.php.stub'; + $migration = include __DIR__.'/../database/migrations/create_laravel-finetuner_table.php.stub'; $migration->up(); */ } diff --git a/workbench/app/Providers/WorkbenchServiceProvider.php b/workbench/app/Providers/WorkbenchServiceProvider.php deleted file mode 100644 index 001d06d..0000000 --- a/workbench/app/Providers/WorkbenchServiceProvider.php +++ /dev/null @@ -1,25 +0,0 @@ -