Skip to content

Commit 7f14144

Browse files
authored
feat: adding ai based generated solutions (#534)
* feat: adding ai based generated solutions * Fix styling * fix: docs * fix: wip * Fix styling --------- Co-authored-by: binaryk <[email protected]>
1 parent b2e00b6 commit 7f14144

File tree

8 files changed

+194
-0
lines changed

8 files changed

+194
-0
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"brianium/paratest": "^6.2",
3030
"doctrine/dbal": "^3.0",
3131
"nunomaduro/collision": "^6.0",
32+
"openai-php/laravel": "^0.3.1",
3233
"orchestra/testbench": "^7.0",
3334
"phpstan/extension-installer": "^1.1",
3435
"phpstan/phpstan-deprecation-rules": "^1.0",

config/restify.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,11 @@
157157
'ttl' => 5 * 60, // seconds
158158
],
159159
],
160+
161+
/*
162+
| Specify if restify can call OpenAI for solution generation.
163+
|
164+
| By default this feature is enabled, but you still have to extend the Exception handler with the Restify one and set the API key.
165+
*/
166+
'ai_solutions' => true,
160167
];
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
title: AI Solution
3+
menuTitle: AI Solution
4+
description: AI Solution
5+
category: Advanced
6+
position: 14
7+
---
8+
9+
## Generate solution
10+
11+
Restify can generate an AI based solution to your problem. In order to enable that you need to extend the `App\Exceptions\Handler` with the `Binaryk\LaravelRestify\Exceptions\RestifyHandler`:
12+
13+
```php
14+
use Binaryk\LaravelRestify\Exceptions\RestifyHandler;
15+
use Throwable;
16+
17+
class Handler extends RestifyHandler
18+
{
19+
//...
20+
}
21+
```
22+
23+
<alert type="warning">
24+
This feature is only enabled when the `app.debug` is set to `true`.
25+
</alert>
26+
27+
28+
This feature is using the [openai-php/laravel](https://github.com/openai-php/laravel#get-started), you should also publish the config file:
29+
30+
```
31+
php artisan vendor:publish --provider="OpenAI\Laravel\ServiceProvider"
32+
```
33+
34+
and set the `OPENAI_API_KEY` in the `.env` file.
35+
36+
The OpenAI key can be obtained from [here](https://platform.openai.com/account/api-keys).
37+
38+
39+
Now the solution to your problems will automatically appear in the response:
40+
41+
```json
42+
{
43+
"restify-solution": "Line 67 in DocumentRepository.php file has an error because the method `resolveUsingFullPath()` is not defined. The code should look like this:\n```\n->resolveUsingTemporaryUrl($request->boolean('temporary'))\n```\n",
44+
"message": "Call to undefined method Binaryk\\LaravelRestify\\Fields\\File::resolveUsingFullPath()",
45+
"exception": "Error",
46+
"file": "/Users/eduardlupacescu/Sites/binarcode/erp/app/Restify/DocumentRepository.php",
47+
"line": 67,
48+
"trace": [
49+
...
50+
}
51+
```
52+
53+
## Disable solution
54+
55+
56+
If you want to disable the solution feature you can set the `restify.ai_solution` to `false` in the `config/restify.php` file so Restify will not call the OpenAI API even you extended the exception handler. This might be useful in automated tests or other environments:
57+
58+
```php
59+
// config/restify.php
60+
'ai_solutions' => true,
61+
```
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
You are a very good PHP developer. Use the following context to find a possible fix for the exception message at the end.
2+
3+
File: /Users/binarcode/Code/ai-errors/app/Documentation.php
4+
Exception: syntax error, unexpected token "{", expecting variable
5+
Line: 193
6+
7+
Snippet including line numbers:
8+
192 public static function getDocVersions(
9+
193 {
10+
194 return [
11+
195 'master' => 'Master',
12+
196 '9.x' => '9.x',
13+
14+
Possible Fix:
15+
Line 192 in Documentation.php file has a syntax error (missing a closing parenthesis). The code should look like this: `public static function getDocVersions()`
16+
17+
File: {!! $file !!}
18+
Exception: {!! $exception !!}
19+
Line: {!! $line !!}
20+
21+
Snippet including line numbers:
22+
{!! $snippet !!}
23+
24+
Possible Fix:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{!! $solution !!}

src/Exceptions/RestifyHandler.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\Exceptions;
4+
5+
use Binaryk\LaravelRestify\Exceptions\Solutions\OpenAiSolution;
6+
use Illuminate\Foundation\Exceptions\Handler;
7+
use Throwable;
8+
9+
class RestifyHandler extends Handler
10+
{
11+
protected function convertExceptionToArray(Throwable $e): array
12+
{
13+
$response = parent::convertExceptionToArray($e);
14+
15+
if (! config('restify.ai_solutions')) {
16+
return $response;
17+
}
18+
19+
if (! config('app.debug')) {
20+
return $response;
21+
}
22+
23+
if (! config('openai.api_key')) {
24+
return $response;
25+
}
26+
27+
$solution = (new OpenAiSolution($e))->getSolutionDescription();
28+
29+
return array_merge([
30+
'restify-solution' => $solution,
31+
], $response);
32+
}
33+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\Exceptions\Solutions;
4+
5+
use Illuminate\Support\Facades\Cache;
6+
use OpenAI\Laravel\Facades\OpenAI;
7+
use Spatie\Backtrace\Backtrace;
8+
use Spatie\Backtrace\Frame;
9+
use Throwable;
10+
11+
class OpenAiSolution
12+
{
13+
protected string $solution;
14+
15+
public function __construct(protected Throwable $throwable)
16+
{
17+
$this->solution = Cache::remember('restify-solution-'.sha1($this->throwable->getTraceAsString()),
18+
now()->addHour(),
19+
fn () => OpenAI::completions()->create([
20+
'model' => 'text-davinci-003',
21+
'prompt' => $this->generatePrompt($this->throwable),
22+
'max_tokens' => 100,
23+
'temperature' => 0,
24+
])->choices[0]->text
25+
);
26+
}
27+
28+
public function getSolutionTitle(): string
29+
{
30+
return 'AI Generated Solution';
31+
}
32+
33+
public function getSolutionDescription(): string
34+
{
35+
return view('restify::prompts.solution', [
36+
'solution' => $this->solution,
37+
])->render();
38+
}
39+
40+
public function getDocumentationLinks(): array
41+
{
42+
return [];
43+
}
44+
45+
protected function getApplicationFrame(Throwable $throwable): ?Frame
46+
{
47+
$backtrace = Backtrace::createForThrowable($throwable)->applicationPath(base_path());
48+
$frames = $backtrace->frames();
49+
50+
return $frames[$backtrace->firstApplicationFrameIndex()] ?? null;
51+
}
52+
53+
protected function generatePrompt(Throwable $throwable): string
54+
{
55+
$applicationFrame = $this->getApplicationFrame($throwable);
56+
57+
$snippet = $applicationFrame->getSnippet(15);
58+
59+
return (string) view('restify::prompts.prompt', [
60+
'snippet' => collect($snippet)->map(fn ($line, $number) => $number.' '.$line)->join(PHP_EOL),
61+
'file' => $applicationFrame->file,
62+
'line' => $applicationFrame->lineNumber,
63+
'exception' => $throwable->getMessage(),
64+
]);
65+
}
66+
}

src/LaravelRestifyServiceProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public function configurePackage(Package $package): void
2727
->hasConfigFile()
2828
->hasMigration('create_action_logs_table')
2929
->runsMigrations()
30+
->hasViews('restify')
3031
->hasCommands([
3132
RepositoryCommand::class,
3233
ActionCommand::class,

0 commit comments

Comments
 (0)