Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#10 - regulations for escooters #194

Merged
merged 87 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from 79 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
c9a5dab
navbar cleanup
Lee0z Jan 6, 2024
180d27d
Added route and controller
JakubKermes Jan 6, 2024
b642a84
Add RulesController index method, Rules page, nav href
Lee0z Jan 6, 2024
707e620
Getting rules from GPT API
JakubKermes Jan 6, 2024
62871c3
Merge branch '#10-regulations-for-escooters' of https://github.com/bl…
Lee0z Jan 6, 2024
9f0df70
Fix Nav component import, fix guest route to rules, still 500 on /rules
Lee0z Jan 7, 2024
bc5075e
Fix controller
JakubKermes Jan 7, 2024
7a08f13
Update RulesController and update route
Lee0z Jan 7, 2024
f6ab32e
Create migrations
JakubKermes Jan 7, 2024
642ad0d
Fix importer
JakubKermes Jan 9, 2024
9e0446d
Update query
JakubKermes Jan 10, 2024
c21f4a8
Nav cleanup - delete rules tab
Lee0z Jan 12, 2024
e55bf36
Update translations and add regulations section at city view
Lee0z Jan 12, 2024
c59bdb3
change to job
JakubKermes Jan 13, 2024
ca4c6ac
fix routes
JakubKermes Jan 13, 2024
b89f8c1
Update app.css and Index.vue
Jan 13, 2024
1e2f4b8
Merge branch '#10-regulations-for-escooters' of https://github.com/bl…
Jan 13, 2024
afeb0b3
added import rules button, changes in city view for fetching data, ru…
Lee0z Jan 13, 2024
866960f
Merge branch '#10-regulations-for-escooters' of https://github.com/bl…
Lee0z Jan 13, 2024
c346d20
Refactor regulations fetching in City Index.vue
Jan 13, 2024
1f6a0fd
Translations for rules import button, route fix
Lee0z Jan 13, 2024
ac00cfb
Merge branch '#10-regulations-for-escooters' of https://github.com/bl…
Lee0z Jan 13, 2024
1c80b11
lint
Lee0z Jan 13, 2024
b47758e
small fixes
JakubKermes Jan 13, 2024
553ebcc
regulations padding
Jan 13, 2024
e7af739
translation rules
Lee0z Jan 13, 2024
ab0f5fc
Merge remote-tracking branch 'origin/#10-regulations-for-escooters' i…
JakubKermes Jan 13, 2024
817aa03
small fixes
JakubKermes Jan 13, 2024
f434879
Merge branch 'main' into #10-regulations-for-escooters
Lee0z Jan 13, 2024
15af93e
translation fix
Lee0z Jan 13, 2024
0d53f75
Refactor regulations display logic
Jan 13, 2024
6195273
Merge branch '#10-regulations-for-escooters' of https://github.com/bl…
Jan 13, 2024
bfc4490
rules are working
Jan 13, 2024
7523ecf
Lintf and remove unused code
Lee0z Jan 13, 2024
37d1f55
avoid unnecessary api calls
JakubKermes Jan 13, 2024
5018ddb
Update import rules endpoint
Lee0z Jan 13, 2024
fe552fb
added info about loading
Jan 13, 2024
e577862
Merge branch '#10-regulations-for-escooters' of https://github.com/bl…
Jan 13, 2024
b1c67b5
fixed html displaying in rules
Jan 13, 2024
a69e750
route fix
Lee0z Jan 13, 2024
d6a83a9
Merge branch '#10-regulations-for-escooters' of https://github.com/bl…
Lee0z Jan 13, 2024
afad700
Lintf, replaced v-html with v-text
Lee0z Jan 13, 2024
9c8e316
instead of v-html used v-if & v-else
Jan 14, 2024
7e33fa4
fixed rules, now they are correctly displaying new line char
Jan 14, 2024
ddc5c7b
linter
Jan 14, 2024
2658039
added visual hins for loading
Jan 14, 2024
f6c69da
change border-[1px] to border
zmigrOO Jan 15, 2024
db3024c
Update lang/pl.json
zmigrOO Jan 15, 2024
b17ca35
Update lang/pl.json
zmigrOO Jan 15, 2024
ab1c2b2
Update app/Http/Controllers/RulesController.php
zmigrOO Jan 15, 2024
5c30a59
Merge branch 'main' into #10-regulations-for-escooters
zmigrOO Jan 15, 2024
1c8931c
composer csf
Lee0z Jan 15, 2024
badf1a3
comma fix
Lee0z Jan 15, 2024
d8536f0
Changed ENG to EN where it was possible
zmigrOO Jan 15, 2024
0899313
Change ENG to EN
JakubKermes Feb 6, 2024
adb1b67
lint
JakubKermes Feb 6, 2024
ebafb4e
Add type declarations and fix constructor
JakubKermes Feb 6, 2024
31947c8
Used string interpolation, add error toast, polish translation.
Lee0z Mar 18, 2024
0e7d1e7
lintf
Lee0z Mar 18, 2024
f9fe3d6
small fixes
JakubKermes Mar 21, 2024
e3948ee
fetchRegulations fix
Lee0z Mar 24, 2024
802afc8
replace v-html with v-text
Lee0z Mar 25, 2024
e012bf8
lintf
Lee0z Mar 25, 2024
295e5f2
Add exception, fix variable naming
JakubKermes Mar 29, 2024
e130971
changes in exception handling
JakubKermes Apr 4, 2024
4a2a310
fix displaying import errors
JakubKermes Apr 6, 2024
4947285
Merge remote-tracking branch 'origin/#10-regulations-for-escooters' i…
JakubKermes Apr 6, 2024
d46f1e3
typing
JakubKermes Apr 6, 2024
a94e7f0
Merge branch 'main' into #10-regulations-for-escooters
JakubKermes Apr 8, 2024
86dd53b
small fixes
JakubKermes Apr 8, 2024
4bc6d2e
Merge remote-tracking branch 'origin/#10-regulations-for-escooters' i…
JakubKermes Apr 17, 2024
2390999
fix api.php
JakubKermes Apr 17, 2024
23722a6
small fixes
JakubKermes Apr 17, 2024
f50cd74
csf
JakubKermes Apr 17, 2024
0360e5e
Fix variable names
JakubKermes Apr 27, 2024
30a9b44
Update dependencies in composer.json
Lee0z May 6, 2024
638c09c
Merge branch 'main' into #10-regulations-for-escooters
Lee0z May 6, 2024
f31e189
Update lang/pl.json
JakubKermes May 7, 2024
7e5a24e
small changes
JakubKermes May 7, 2024
f28c1d1
Modify functions in OpenAIService.php
JakubKermes May 8, 2024
8ed2d61
Merge branch 'refs/heads/main' into #10-regulations-for-escooters
JakubKermes May 8, 2024
280b621
Merge branch 'main' into #10-regulations-for-escooters
JakubKermes May 8, 2024
73b8515
Merge remote-tracking branch 'origin/#10-regulations-for-escooters' i…
JakubKermes May 8, 2024
771c87d
small fixes
JakubKermes May 8, 2024
b5d5716
fix translation
JakubKermes May 8, 2024
b69d017
Merge branch 'main' into #10-regulations-for-escooters
AleksandraKozubal May 13, 2024
3b63c5d
change to config
AleksandraKozubal May 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ GOOGLE_REDIRECT_URI=http://escooters.blumilk.localhost/login/google/redirect
FACEBOOK_CLIENT_ID=
FACEBOOK_CLIENT_SECRET=
FACEBOOK_REDIRECT_URI=http://escooters.blumilk.localhost/login/facebook/redirect

OPENAI_API_KEY=
4 changes: 4 additions & 0 deletions app/Exceptions/ExceptionHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public function render($request, Throwable $exception)
return back()->withErrors($exception->errors());
}

if ($exception instanceof OpenAiException) {
return response()->json(["error" => $exception->getMessage()], $exception->getCode());
}

$response = parent::render($request, $exception);
$statusCode = $response->status();

Expand Down
14 changes: 14 additions & 0 deletions app/Exceptions/OpenAiException.php
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;
}
47 changes: 47 additions & 0 deletions app/Http/Controllers/RulesController.php
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);
}
}
30 changes: 30 additions & 0 deletions app/Jobs/ImportCityRulesJob.php
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
vojcc marked this conversation as resolved.
Show resolved Hide resolved
{
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);
}
}
29 changes: 29 additions & 0 deletions app/Models/Rules.php
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);
}
}
133 changes: 133 additions & 0 deletions app/Services/OpenAIService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?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(env("OPENAI_API_KEY"));
kamilpiech97 marked this conversation as resolved.
Show resolved Hide resolved
} 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();
vojcc marked this conversation as resolved.
Show resolved Hide resolved

$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(function () use ($importInfo): void {
ImportInfoDetail::query()->updateOrCreate([
"import_info_id" => $importInfo->id,
"provider_name" => "OpenAI",
"code" => 400,
]);
kamilpiech97 marked this conversation as resolved.
Show resolved Hide resolved
})->finally(function () use ($importInfo): void {
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, object $currentRulesInCountry): bool
{
return in_array($countryName, $this->countriesKnownToHaveUniformRules, true) && $currentRulesInCountry !== null && $currentRulesInCountry->rules_en !== null && $currentRulesInCountry->rules_pl !== null;
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
"php": "^8.2",
"ext-dom": "*",
"ext-pdo": "*",
"dedoc/scramble": "^0.9.0",
"guzzlehttp/guzzle": "^7.7",
"dedoc/scramble": "^0.9.0",
"inertiajs/inertia-laravel": "^1.0.0",
"laravel/framework": "^10.13.0",
"laravel/sanctum": "^3.2.5",
"laravel/socialite": "^5.10",
"laravel/tinker": "^2.8.1",
"openai-php/client": "^0.8.1",
"sentry/sentry-laravel": "^3.7",
"spatie/laravel-permission": "^6.1",
"stichoza/google-translate-php": "^5.1",
Expand Down
Loading
Loading