Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 31 additions & 0 deletions app/Actions/ViewDataAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
namespace App\Actions;

use App\DTO\ContactDTO;
use App\Enums\AiModelCategoryEnum;
use App\Enums\ContactSectionEnum;
use App\Models\AiModel;
use App\Models\Configuration;
use App\Models\Contact;
use App\Models\News;
Expand Down Expand Up @@ -62,6 +64,35 @@ public function technologies(string $locale): Collection
});
}

public function aiModelGroups(): Collection
{
return Cache::rememberForever('ai_models_active', function () {
return $this->groupAiModelsByCategory(
AiModel::whereNull('archived_at')->orderBy('order')->get()
);
});
}

public function aiModelArchive(): Collection
{
return Cache::rememberForever('ai_models_archived', function () {
return $this->groupAiModelsByCategory(
AiModel::whereNotNull('archived_at')->with('replacedBy')->orderBy('order')->get()
);
});
}

private function groupAiModelsByCategory(Collection $models): Collection
{
return collect(AiModelCategoryEnum::cases())
->map(fn (AiModelCategoryEnum $category) => [
'category' => $category,
'models' => $models->where('category', $category)->values(),
])
->filter(fn (array $group) => $group['models']->isNotEmpty())
->values();
}

public function openSource(string $locale): Collection
{
$key = Str::slug("open_source_published_{$locale}");
Expand Down
20 changes: 20 additions & 0 deletions app/Enums/AiModelCategoryEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace App\Enums;

enum AiModelCategoryEnum: string
{
case REASONING_CODING = 'reasoning_coding';
case VISION_DOCUMENTS = 'vision_documents';
case RETRIEVAL_SEARCH = 'retrieval_search';

public function title(): string
{
return __('components.ai_llm.categories.'.$this->value.'.title');
}

public function description(): string
{
return __('components.ai_llm.categories.'.$this->value.'.description');
}
}
17 changes: 17 additions & 0 deletions app/Http/Controllers/Ai/AiIndexController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace App\Http\Controllers\Ai;

use App\Actions\PageAction;
use App\Http\Controllers\Controller;
use Illuminate\View\View;

class AiIndexController extends Controller
{
public function __invoke(): View
{
return view('app.ai.index')->with([
'page' => (new PageAction(locale: null, routeName: 'ai.index'))->default(),
]);
}
}
22 changes: 22 additions & 0 deletions app/Http/Controllers/Ai/AiLlmIndexController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace App\Http\Controllers\Ai;

use App\Actions\PageAction;
use App\Actions\ViewDataAction;
use App\Http\Controllers\Controller;
use Illuminate\View\View;

class AiLlmIndexController extends Controller
{
public function __invoke(): View
{
$viewData = new ViewDataAction;

return view('app.ai.llm.index')->with([
'page' => (new PageAction(locale: null, routeName: 'ai.llm.index'))->default(),
'groups' => $viewData->aiModelGroups(),
'archive' => $viewData->aiModelArchive(),
]);
}
}
2 changes: 2 additions & 0 deletions app/Http/Controllers/Sitemap/SitemapController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class SitemapController extends Controller
'media.index',
'legal.imprint.index',
'legal.privacy.index',
'ai.index',
'ai.llm.index',
];

protected const array DEFAULT_LOCALES = [
Expand Down
50 changes: 50 additions & 0 deletions app/Models/AiModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace App\Models;

use App\Enums\AiModelCategoryEnum;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class AiModel extends Model
{
protected $casts = [
'category' => AiModelCategoryEnum::class,
'role' => 'json',
'archived_at' => 'date',
];

public function replacedBy(): BelongsTo
{
return $this->belongsTo(AiModel::class, 'replaced_by_id');
}

public function localizedRole(): ?string
{
return $this->role[substr(app()->getLocale(), 0, 2)] ?? null;
}

public function licenseLabel(): ?string
{
$key = $this->licenseKey();

return $key ? __('components.ai_llm.licenses.'.$key.'.label') : $this->license;
}

public function licenseTooltip(): ?string
{
$key = $this->licenseKey();

return $key ? __('components.ai_llm.licenses.'.$key.'.tooltip') : null;
}

private function licenseKey(): ?string
{
return match ($this->license) {
'MIT' => 'mit',
'Apache-2.0' => 'apache',
'Gemma' => 'gemma',
default => null,
};
}
}
2 changes: 1 addition & 1 deletion app/Security/Presets/MyCspPreset.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class MyCspPreset implements Preset
{
public function configure(Policy $policy): void
{
$cdnHost = parse_url((string) env('AWS_CDN_ENDPOINT', ''), PHP_URL_HOST);
$cdnHost = parse_url((string) config('filesystems.disks.s3.cdn_endpoint', ''), PHP_URL_HOST);

$scriptSources = array_filter([
Keyword::SELF,
Expand Down
7 changes: 3 additions & 4 deletions app/Support/CloudinaryUrl.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

class CloudinaryUrl
{
private const CLOUDINARY_HOST = 'res.cloudinary.com';
private const string CLOUDINARY_HOST = 'res.cloudinary.com';

private const UPLOAD_MARKER = '/image/upload/';
private const string UPLOAD_MARKER = '/image/upload/';

public static function src(string $url, int $width): string
{
Expand Down Expand Up @@ -46,8 +46,7 @@ private static function stripExistingTransforms(string $path): string
$segments = explode('/', $path);

if (
isset($segments[0])
&& preg_match('/^[a-z0-9_,.-]+$/', $segments[0])
preg_match('/^[a-z0-9_,.-]+$/', $segments[0])
&& preg_match('/[whcfq]_/', $segments[0])
) {
array_shift($segments);
Expand Down
Loading
Loading