-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* navbar cleanup * Added route and controller * Add RulesController index method, Rules page, nav href * Getting rules from GPT API * Fix Nav component import, fix guest route to rules, still 500 on /rules * Fix controller * Update RulesController and update route * Create migrations * Fix importer * Update query * Nav cleanup - delete rules tab * Update translations and add regulations section at city view * change to job * fix routes * Update app.css and Index.vue * added import rules button, changes in city view for fetching data, rules route * Refactor regulations fetching in City Index.vue * Translations for rules import button, route fix * lint * small fixes * regulations padding * translation rules * small fixes * translation fix * Refactor regulations display logic * rules are working * Lintf and remove unused code * avoid unnecessary api calls * Update import rules endpoint * added info about loading * fixed html displaying in rules * route fix * Lintf, replaced v-html with v-text * instead of v-html used v-if & v-else * fixed rules, now they are correctly displaying new line char * linter * added visual hins for loading * change border-[1px] to border Co-authored-by: Ewelina Skrzypacz <[email protected]> * Update lang/pl.json Co-authored-by: Ewelina Skrzypacz <[email protected]> * Update lang/pl.json Co-authored-by: Ewelina Skrzypacz <[email protected]> * Update app/Http/Controllers/RulesController.php Co-authored-by: Kamil Piech <[email protected]> * composer csf * comma fix * Changed ENG to EN where it was possible * Change ENG to EN * lint * Add type declarations and fix constructor * Used string interpolation, add error toast, polish translation. * lintf * small fixes * fetchRegulations fix * replace v-html with v-text * lintf * Add exception, fix variable naming * changes in exception handling * fix displaying import errors * typing * small fixes * fix api.php * small fixes * csf * Fix variable names * Update dependencies in composer.json * Update lang/pl.json Co-authored-by: Jakub Wójcik <[email protected]> * small changes * Modify functions in OpenAIService.php * small fixes * fix translation * change to config --------- Co-authored-by: JakubKermes <[email protected]> Co-authored-by: zmigroo <[email protected]> Co-authored-by: Patryk Żmigrodzki <[email protected]> Co-authored-by: Ewelina Skrzypacz <[email protected]> Co-authored-by: Kamil Piech <[email protected]> Co-authored-by: Jakub Kermes <[email protected]> Co-authored-by: Jakub Wójcik <[email protected]> Co-authored-by: Aleksandra Kozubal <[email protected]> Co-authored-by: Aleksandra Kozubal <[email protected]>
- Loading branch information
1 parent
293e2b6
commit 4916bec
Showing
22 changed files
with
792 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Exceptions; | ||
|
||
use Exception; | ||
use Symfony\Component\HttpFoundation\Response; | ||
|
||
class OpenAiException extends Exception | ||
{ | ||
protected $message = "OpenAI API connection error"; | ||
protected $code = Response::HTTP_INTERNAL_SERVER_ERROR; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Http\Controllers\Api; | ||
|
||
use App\Models\City; | ||
use App\Models\Country; | ||
use App\Models\Rules; | ||
use App\Services\OpenAIService; | ||
use Illuminate\Http\JsonResponse; | ||
use Illuminate\Http\Request; | ||
|
||
class RulesController | ||
{ | ||
public function getRules(Country $country, City $city): JsonResponse | ||
{ | ||
$rules = Rules::query() | ||
->where("city_id", $city->id) | ||
->first(); | ||
|
||
if (!$rules || $rules->rules_en === null || $rules->rules_pl === null) { | ||
$cityData = [ | ||
"cityId" => $city->id, | ||
"countryId" => $country->id, | ||
"cityName" => $city->name, | ||
"countryName" => $country->name, | ||
]; | ||
$importer = new OpenAIService(); | ||
$data = $importer->importRulesForCity($cityData, true); | ||
} else { | ||
$data = [ | ||
"country" => $country->name, | ||
"city" => $city->name, | ||
"rules_en" => $rules->rules_en, | ||
"rules_pl" => $rules->rules_pl, | ||
]; | ||
} | ||
|
||
return response()->json($data); | ||
} | ||
|
||
public function importRules(Request $request, OpenAIService $importer): JsonResponse | ||
{ | ||
$force = $request->input("force", false); | ||
$importer->importRulesForAllCities($force); | ||
|
||
return response()->json(["message" => "Rules import started"]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Http\Controllers; | ||
|
||
use App\Models\City; | ||
use App\Models\Country; | ||
use App\Models\Rules; | ||
use App\Services\OpenAIService; | ||
use Illuminate\Http\Request; | ||
|
||
class RulesController | ||
{ | ||
public function getRules(Country $country, City $city): array | ||
{ | ||
$rules = Rules::query() | ||
->where("city_id", $city->id) | ||
->first(); | ||
|
||
if (!$rules || $rules->rules_en === null || $rules->rules_pl === null) { | ||
$cityData = [ | ||
"cityId" => $city->id, | ||
"countryId" => $country->id, | ||
"cityName" => $city->name, | ||
"countryName" => $country->name, | ||
]; | ||
$importer = new OpenAIService(); | ||
$data = $importer->importRulesForCity($cityData, true); | ||
} else { | ||
$data = [ | ||
"country" => $country->name, | ||
"city" => $city->name, | ||
"rules_en" => $rules->rules_en, | ||
"rules_pl" => $rules->rules_pl, | ||
]; | ||
} | ||
|
||
return $data; | ||
} | ||
|
||
public function importRules(Request $request, OpenAIService $importer): void | ||
{ | ||
$force = $request->input("force", false); | ||
$importer->importRulesForAllCities($force); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Jobs; | ||
|
||
use App\Services\OpenAIService; | ||
use Illuminate\Bus\Batchable; | ||
use Illuminate\Contracts\Queue\ShouldQueue; | ||
use Illuminate\Foundation\Bus\Dispatchable; | ||
use Illuminate\Queue\InteractsWithQueue; | ||
use Illuminate\Queue\SerializesModels; | ||
|
||
class ImportCityRulesJob implements ShouldQueue | ||
{ | ||
use Dispatchable; | ||
use InteractsWithQueue; | ||
use SerializesModels; | ||
use Batchable; | ||
|
||
public function __construct( | ||
private array $cityData, | ||
private bool $force, | ||
) {} | ||
|
||
public function handle(OpenAIService $openAIService): array | ||
{ | ||
return $openAIService->importRulesForCity($this->cityData, $this->force); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Models; | ||
|
||
use Illuminate\Database\Eloquent\Model; | ||
use Illuminate\Database\Eloquent\Relations\BelongsTo; | ||
|
||
class Rules extends Model | ||
{ | ||
protected $table = "rules_for_cities"; | ||
protected $fillable = [ | ||
"city_id", | ||
"country_id", | ||
"rules_en", | ||
"rules_pl", | ||
]; | ||
|
||
public function city(): BelongsTo | ||
{ | ||
return $this->belongsTo(City::class); | ||
} | ||
|
||
public function country(): BelongsTo | ||
{ | ||
return $this->belongsTo(Country::class); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Services; | ||
|
||
use App\Exceptions\OpenAiException; | ||
use App\Jobs\ImportCityRulesJob; | ||
use App\Models\City; | ||
use App\Models\ImportInfo; | ||
use App\Models\ImportInfoDetail; | ||
use App\Models\Rules; | ||
use Illuminate\Contracts\Queue\ShouldQueue; | ||
use Illuminate\Support\Facades\Bus; | ||
use Illuminate\Support\Facades\Storage; | ||
use OpenAI; | ||
use Throwable; | ||
|
||
class OpenAIService implements ShouldQueue | ||
{ | ||
private OpenAI\Client $client; | ||
private array $countriesKnownToHaveUniformRules; | ||
|
||
public function __construct() | ||
{ | ||
try { | ||
$this->client = OpenAI::client(config("openai.token")); | ||
} catch (Throwable $e) { | ||
throw new OpenAiException(); | ||
} | ||
|
||
$this->countriesKnownToHaveUniformRules = Storage::disk("public")->json("citiesKnownToHaveUniformRules.json"); | ||
} | ||
|
||
public function importRulesForAllCities(bool $force): void | ||
{ | ||
$cities = City::query()->whereHas("cityProviders")->orderBy("country_id")->get(); | ||
|
||
$importInfo = ImportInfo::query()->create([ | ||
"who_runs_it" => "admin", | ||
"status" => "running", | ||
]); | ||
$jobs = []; | ||
|
||
foreach ($cities as $city) { | ||
$cityData = [ | ||
"cityId" => $city->id, | ||
"countryId" => $city->country_id, | ||
"cityName" => $city->name, | ||
"countryName" => $city->country->name, | ||
]; | ||
$jobs[] = new ImportCityRulesJob($cityData, $force); | ||
ImportCityRulesJob::dispatch($cityData, $force); | ||
} | ||
|
||
Bus::batch($jobs) | ||
->catch(fn() => ImportInfoDetail::query()->updateOrCreate([ | ||
"import_info_id" => $importInfo->id, | ||
"provider_name" => "OpenAI", | ||
"code" => 400, | ||
])) | ||
->finally(fn() => ImportInfo::query()->where("id", $importInfo->id)->update([ | ||
"status" => "finished", | ||
])) | ||
->dispatch(); | ||
} | ||
|
||
public function importRulesForCity(array $cityData, bool $force): array | ||
{ | ||
$cityId = $cityData["cityId"]; | ||
$countryId = $cityData["countryId"]; | ||
$cityName = $cityData["cityName"]; | ||
$countryName = $cityData["countryName"]; | ||
|
||
$promptEn = "Act as a helpful assistant. Explain what are the legal limitations for riding electric scooters in $cityName, $countryName? Contain information about: max speed, helmet requirements, allowed ABV, passengers, other relevant details. Be formal, speak English. Don't include city name in your response. If you don't have information answering the question, write 'null'."; | ||
$promptPl = "Translate to polish: "; | ||
$currentRulesInCountry = Rules::query()->where("country_id", $countryId)->first(); | ||
|
||
if ($this->checkIfRulesExist($countryName, $currentRulesInCountry) && !$force) { | ||
$rulesEn = $currentRulesInCountry->rules_en; | ||
$rulesPl = $currentRulesInCountry->rules_pl; | ||
} else { | ||
$rulesEn = $this->askGPT($promptEn); | ||
$rulesPl = $this->askGPT($promptPl . $rulesEn); | ||
} | ||
|
||
if (strlen($rulesEn) < 700 || strlen($rulesPl) < 700) { | ||
return [ | ||
"city" => $cityName, | ||
"country" => $countryName, | ||
"rules_en" => null, | ||
"rules_pl" => null, | ||
]; | ||
} | ||
|
||
Rules::query()->updateOrCreate([ | ||
"city_id" => $cityId, | ||
"country_id" => $countryId, | ||
"rules_en" => $rulesEn, | ||
"rules_pl" => $rulesPl, | ||
]); | ||
|
||
return [ | ||
"city" => $cityName, | ||
"country" => $countryName, | ||
"rules_en" => $rulesEn, | ||
"rules_pl" => $rulesPl, | ||
]; | ||
} | ||
|
||
private function askGPT(string $prompt): string | ||
{ | ||
$response = $this->client->chat()->create([ | ||
"model" => "gpt-3.5-turbo", | ||
"messages" => [ | ||
[ | ||
"role" => "user", | ||
"content" => $prompt, | ||
], | ||
], | ||
]); | ||
|
||
return $response["choices"][0]["message"]["content"]; | ||
} | ||
|
||
private function checkIfRulesExist(string $countryName, ?Rules $currentRulesInCountry): bool | ||
{ | ||
return in_array($countryName, $this->countriesKnownToHaveUniformRules, true) && $currentRulesInCountry !== null && $currentRulesInCountry->rules_en !== null && $currentRulesInCountry->rules_pl !== null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.