Files
archived-ai-models-dev-plat…/DataLoader.php

134 lines
4.0 KiB
PHP

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\AI\Platform\Bridge\ModelsDev;
use Composer\InstalledVersions;
use Symfony\AI\Platform\Exception\RuntimeException;
/**
* Loads and caches models.dev data.
*
* @internal
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class DataLoader
{
/**
* @var array<string, array<string, mixed>>|null
*/
private static ?array $cachedData = null;
private static ?string $cachedPath = null;
/**
* @return array<string, array<string, mixed>>
*/
public static function load(?string $dataPath = null): array
{
$dataPath ??= self::resolveDefaultPath();
// Return cached data if path matches
if (null !== self::$cachedData && self::$cachedPath === $dataPath) {
return self::$cachedData;
}
if (!file_exists($dataPath)) {
throw new RuntimeException(\sprintf('The models.dev data file "%s" does not exist.', $dataPath));
}
$json = file_get_contents($dataPath);
if (false === $json) {
throw new RuntimeException(\sprintf('Failed to read the models.dev data file "%s".', $dataPath));
}
$data = json_decode($json, true, flags: \JSON_THROW_ON_ERROR);
if (!\is_array($data)) {
throw new RuntimeException('Invalid models.dev API data.');
}
// Sort providers alphabetically and sort models within each provider by release date
$sortedData = self::sortData($data);
self::$cachedData = $sortedData;
self::$cachedPath = $dataPath;
return $sortedData;
}
/**
* Clear cached data (useful for testing).
*
* @internal
*/
public static function clearCache(): void
{
self::$cachedData = null;
self::$cachedPath = null;
}
/**
* Resolves the default path to the models.dev JSON file.
*
* Looks for the "symfony/models-dev" Composer package and returns
* the path to its "models-dev.json" file.
*
* @throws RuntimeException if the package is not installed
*/
private static function resolveDefaultPath(): string
{
if (class_exists(InstalledVersions::class) && InstalledVersions::isInstalled('symfony/models-dev')) {
$installPath = InstalledVersions::getInstallPath('symfony/models-dev');
if (null !== $installPath) {
return $installPath.'/models-dev.json';
}
}
throw new RuntimeException('The "models.dev" data file could not be found; either pass an explicit JSON file path or run "composer require symfony/models-dev".');
}
/**
* Sort providers alphabetically and models by release date (newest first).
*
* @param array<string, array<string, mixed>> $data
*
* @return array<string, array<string, mixed>>
*/
private static function sortData(array $data): array
{
// Sort providers alphabetically
ksort($data);
// Sort models within each provider by release date (newest first)
foreach ($data as $providerId => &$provider) {
if (isset($provider['models']) && \is_array($provider['models'])) {
// Convert models to array with keys preserved
$models = $provider['models'];
// Sort models by release_date descending
uasort($models, static function ($a, $b) {
$dateA = $a['release_date'] ?? '1970-01-01';
$dateB = $b['release_date'] ?? '1970-01-01';
// Compare dates in descending order (newer dates first)
return strcmp($dateB, $dateA);
});
$provider['models'] = $models;
}
}
return $data;
}
}