Skip to content

Commit e5b4554

Browse files
authored
Merge pull request #77 from openai-php/add-install-command
Add install command
2 parents a8b217d + 3d15ca2 commit e5b4554

File tree

8 files changed

+253
-4
lines changed

8 files changed

+253
-4
lines changed

README.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,19 @@ First, install OpenAI via the [Composer](https://getcomposer.org/) package manag
2525
composer require openai-php/laravel
2626
```
2727

28-
Next, publish the configuration file:
28+
Next, execute the install command:
2929

3030
```bash
31-
php artisan vendor:publish --provider="OpenAI\Laravel\ServiceProvider"
31+
php artisan openai:install
3232
```
3333

3434
This will create a `config/openai.php` configuration file in your project, which you can modify to your needs
35-
using environment variables:
35+
using environment variables.
36+
Blank environment variables for the OpenAI API key and organization id are already appended to your `.env` file.
3637

3738
```env
3839
OPENAI_API_KEY=sk-...
40+
OPENAI_ORGANIZATION=org-...
3941
```
4042

4143
Finally, you may use the `OpenAI` facade to access the OpenAI API:

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"openai-php/client": "^v0.8.0"
1717
},
1818
"require-dev": {
19-
"laravel/pint": "^1.10.3",
19+
"laravel/pint": "^1.13.6",
2020
"pestphp/pest": "^2.8.2",
2121
"pestphp/pest-plugin-arch": "^2.2.2",
2222
"pestphp/pest-plugin-mock": "^2.0.0",

resources/views/components/badge.php

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
/** @var string $type */
4+
/** @var string $content */
5+
[$bgBadgeColor, $bgBadgeText] = match ($type) {
6+
'INFO' => ['blue', 'INFO'],
7+
'ERROR' => ['red', 'ERROR'],
8+
};
9+
10+
?>
11+
12+
<div class="my-1">
13+
<span class="ml-2 px-1 bg-<?php echo $bgBadgeColor ?>-600 font-bold"><?php echo htmlspecialchars($bgBadgeText) ?></span>
14+
<span class="ml-1">
15+
<?php echo htmlspecialchars($content) ?>
16+
</span>
17+
</div>
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div></div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<div class="flex mx-2 max-w-150">
2+
<span>
3+
<?php echo htmlspecialchars($left) ?>
4+
</span>
5+
<span class="flex-1 content-repeat-[.] text-gray ml-1"></span>
6+
<?php if ($right !== '') { ?>
7+
<span class="ml-1 text-gray">
8+
<?php echo htmlspecialchars($right) ?>
9+
</span>
10+
<?php } ?>
11+
</div>
12+

src/Commands/InstallCommand.php

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?php
2+
3+
namespace OpenAI\Laravel\Commands;
4+
5+
use Illuminate\Console\Command;
6+
use OpenAI\Laravel\ServiceProvider;
7+
use OpenAI\Laravel\Support\View;
8+
9+
class InstallCommand extends Command
10+
{
11+
private const LINKS = [
12+
'Repository' => 'https://github.com/openai-php/laravel',
13+
'OpenAI PHP Docs' => 'https://github.com/openai-php/client#readme',
14+
'Join us on Telegram' => 'https://t.me/+66GDs6UM6RcxY2U8',
15+
];
16+
17+
private const FUNDING_LINKS = [
18+
'Sponsor Sandro' => 'https://github.com/sponsors/gehrisandro',
19+
'Sponsor Nuno' => 'https://github.com/sponsors/nunomaduro',
20+
];
21+
22+
protected $signature = 'openai:install';
23+
24+
protected $description = 'Prepares the OpenAI client for use.';
25+
26+
public function handle(): void
27+
{
28+
View::renderUsing($this->output);
29+
30+
View::render('components.badge', [
31+
'type' => 'INFO',
32+
'content' => 'Installing OpenAI for Laravel.',
33+
]);
34+
35+
$this->copyConfig();
36+
37+
View::render('components.new-line');
38+
39+
$this->addEnvKeys('.env');
40+
$this->addEnvKeys('.env.example');
41+
42+
View::render('components.new-line');
43+
44+
$wantsToSupport = $this->askToStarRepository();
45+
46+
$this->showLinks();
47+
48+
View::render('components.badge', [
49+
'type' => 'INFO',
50+
'content' => 'Open your .env and add your OpenAI API key and organization id.',
51+
]);
52+
53+
if ($wantsToSupport) {
54+
$this->openRepositoryInBrowser();
55+
}
56+
}
57+
58+
private function copyConfig(): void
59+
{
60+
if (file_exists(config_path('openai.php'))) {
61+
View::render('components.two-column-detail', [
62+
'left' => 'config/openai.php',
63+
'right' => 'File already exists.',
64+
]);
65+
66+
return;
67+
}
68+
69+
View::render('components.two-column-detail', [
70+
'left' => 'config/openai.php',
71+
'right' => 'File created.',
72+
]);
73+
74+
$this->callSilent('vendor:publish', [
75+
'--provider' => ServiceProvider::class,
76+
]);
77+
}
78+
79+
private function addEnvKeys(string $envFile): void
80+
{
81+
$fileContent = file_get_contents(base_path($envFile));
82+
83+
if ($fileContent === false) {
84+
return;
85+
}
86+
87+
if (str_contains($fileContent, 'OPENAI_API_KEY')) {
88+
View::render('components.two-column-detail', [
89+
'left' => $envFile,
90+
'right' => 'Variables already exists.',
91+
]);
92+
93+
return;
94+
}
95+
96+
file_put_contents(base_path($envFile), PHP_EOL.'OPENAI_API_KEY='.PHP_EOL.'OPENAI_ORGANIZATION='.PHP_EOL, FILE_APPEND);
97+
98+
View::render('components.two-column-detail', [
99+
'left' => $envFile,
100+
'right' => 'OPENAI_API_KEY and OPENAI_ORGANIZATION variables added.',
101+
]);
102+
}
103+
104+
private function askToStarRepository(): bool
105+
{
106+
if (! $this->input->isInteractive()) {
107+
return false;
108+
}
109+
110+
return $this->confirm(' <options=bold>Wanna show OpenAI for Laravel some love by starring it on GitHub?</>', false);
111+
}
112+
113+
private function openRepositoryInBrowser(): void
114+
{
115+
if (PHP_OS_FAMILY == 'Darwin') {
116+
exec('open https://github.com/openai-php/laravel');
117+
}
118+
if (PHP_OS_FAMILY == 'Windows') {
119+
exec('start https://github.com/openai-php/laravel');
120+
}
121+
if (PHP_OS_FAMILY == 'Linux') {
122+
exec('xdg-open https://github.com/openai-php/laravel');
123+
}
124+
}
125+
126+
private function showLinks(): void
127+
{
128+
$links = [
129+
...self::LINKS,
130+
...rand(0, 1) ? self::FUNDING_LINKS : array_reverse(self::FUNDING_LINKS, true),
131+
];
132+
133+
foreach ($links as $message => $link) {
134+
View::render('components.two-column-detail', [
135+
'left' => $message,
136+
'right' => $link,
137+
]);
138+
}
139+
}
140+
}

src/ServiceProvider.php

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use OpenAI;
1010
use OpenAI\Client;
1111
use OpenAI\Contracts\ClientContract;
12+
use OpenAI\Laravel\Commands\InstallCommand;
1213
use OpenAI\Laravel\Exceptions\ApiKeyIsMissing;
1314

1415
/**
@@ -50,6 +51,10 @@ public function boot(): void
5051
$this->publishes([
5152
__DIR__.'/../config/openai.php' => config_path('openai.php'),
5253
]);
54+
55+
$this->commands([
56+
InstallCommand::class,
57+
]);
5358
}
5459
}
5560

src/Support/View.php

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenAI\Laravel\Support;
6+
7+
use Symfony\Component\Console\Output\OutputInterface;
8+
use Termwind\Termwind;
9+
10+
use function Termwind\render;
11+
use function Termwind\renderUsing;
12+
13+
/**
14+
* @internal
15+
*/
16+
final class View
17+
{
18+
/**
19+
* The implementation of the output.
20+
*/
21+
private static OutputInterface $output;
22+
23+
/**
24+
* Renders views using the given Output instance.
25+
*/
26+
public static function renderUsing(OutputInterface $output): void
27+
{
28+
self::$output = $output;
29+
}
30+
31+
/**
32+
* Renders the given view.
33+
*
34+
* @param array<string, mixed> $data
35+
*/
36+
public static function render(string $path, array $data = []): void
37+
{
38+
$contents = self::compile($path, $data);
39+
40+
$existing = Termwind::getRenderer();
41+
42+
renderUsing(self::$output);
43+
44+
try {
45+
render($contents);
46+
} finally {
47+
renderUsing($existing);
48+
}
49+
}
50+
51+
/**
52+
* Compiles the given view.
53+
*
54+
* @param array<string, mixed> $data
55+
*/
56+
private static function compile(string $path, array $data): string
57+
{
58+
extract($data);
59+
60+
ob_start();
61+
62+
$path = str_replace('.', '/', $path);
63+
64+
include sprintf('%s/../../resources/views/%s.php', __DIR__, $path);
65+
66+
$contents = ob_get_contents();
67+
68+
ob_clean();
69+
70+
return (string) $contents;
71+
}
72+
}

0 commit comments

Comments
 (0)