components([ Section::make(__('filament.resource.ai_model.parameters_help_title')) ->description(__('filament.resource.ai_model.parameters_help_text')) ->columns(1) ->collapsible() ->schema([]), TextInput::make('name') ->label(__('filament.resource.ai_model.form.name')) ->required(), Select::make('model_id') ->label(__('filament.resource.ai_model.form.model_id')) ->searchable() ->required() ->getSearchResultsUsing(function (string $search, callable $get): array { $providerId = $get('api_provider_id'); if (! $providerId) { return []; } $provider = ApiProvider::find($providerId); if (! $provider || ! $provider->plugin) { return []; } $plugin = PluginLoader::getPlugin($provider->plugin, $provider); if (! method_exists($plugin, 'searchModels')) { return []; } $results = $plugin->searchModels($search); $options = []; foreach ($results as $result) { $id = $result['id'] ?? null; $name = $result['name'] ?? $id; if ($id) { $options[$id] = $name ? $name.' ('.$id.')' : $id; } } return $options; }) ->getOptionLabelUsing(fn ($value): ?string => $value), TextInput::make('model_type') ->label(__('filament.resource.ai_model.form.model_type')) ->nullable(), Select::make('api_provider_id') ->label(__('filament.resource.ai_model.form.api_provider')) ->relationship('primaryApiProvider', 'name') ->searchable() ->preload() ->required(), Toggle::make('enabled') ->label(__('filament.resource.ai_model.form.enabled')) ->default(true), Textarea::make('parameters') ->label(__('filament.resource.ai_model.form.parameters')) ->nullable() ->rows(15), ]); } protected static function canSearchModelsWithAnyProvider(?array $apiProviderIds): bool { if (empty($apiProviderIds)) { return false; } foreach ($apiProviderIds as $apiProviderId) { $apiProvider = ApiProvider::find($apiProviderId); if (! $apiProvider || ! $apiProvider->plugin) { continue; } try { $pluginInstance = PluginLoader::getPlugin($apiProvider->plugin, $apiProvider); if (method_exists($pluginInstance, 'searchModels')) { return true; } } catch (\Exception $e) { // Log the exception if needed continue; } } return false; } protected static function getPluginInstance(?int $apiProviderId): ?ApiPluginInterface { if (! $apiProviderId) { return null; } $apiProvider = ApiProvider::find($apiProviderId); if (! $apiProvider || ! $apiProvider->plugin) { return null; } try { return PluginLoader::getPlugin($apiProvider->plugin, $apiProvider); } catch (\Exception $e) { // Log the exception if needed return null; } } protected static function canSearchModels(?int $apiProviderId): bool { if (! $apiProviderId) { return false; } $apiProvider = ApiProvider::find($apiProviderId); if (! $apiProvider || ! $apiProvider->plugin) { return false; } try { $pluginInstance = PluginLoader::getPlugin($apiProvider->plugin, $apiProvider); return method_exists($pluginInstance, 'searchModels'); } catch (\Exception $e) { // Log the exception if needed return false; } } public static function table(Table $table): Table { return $table ->columns([ TextColumn::make('name')->searchable()->sortable(), TextColumn::make('model_id')->searchable()->sortable(), TextColumn::make('model_type')->searchable()->sortable(), IconColumn::make('enabled') ->boolean(), TextColumn::make('primaryApiProvider.name')->searchable()->sortable()->limit(50), ]) ->filters([ // ]) ->actions([ EditAction::make(), Action::make('duplicate') ->label(__('filament.resource.ai_model.action.duplicate')) ->icon('heroicon-o-document-duplicate') ->action(function (Model $record, $livewire) { $livewire->redirect(static::getUrl('create', ['sourceRecord' => $record->id])); }), ]) ->bulkActions([ BulkActionGroup::make([ DeleteBulkAction::make(), ]), ]) ->emptyStateActions([ CreateAction::make(), ]); } public static function getRelations(): array { return [ // ]; } public static function getPages(): array { return [ 'index' => Pages\ListAiModels::route('/'), 'create' => Pages\CreateAiModel::route('/create'), 'edit' => Pages\EditAiModel::route('/{record}/edit'), ]; } }