schema([ Forms\Components\Section::make() ->schema([ Select::make('api_provider_id') ->label(__('filament.resource.ai_model.form.api_provider')) ->relationship('primaryApiProvider', 'name') ->live() ->afterStateUpdated(function (callable $set) { $set('model_search_result', null); }), Select::make('model_search_result') ->label(__('filament.resource.ai_model.form.search_model')) ->searchable() ->live() ->hidden(fn (callable $get) => !static::canSearchModels($get('api_provider_id'))) ->getSearchResultsUsing(function (string $search, callable $get) { $apiProviderId = $get('api_provider_id'); if (!$apiProviderId) { return []; } $pluginInstance = static::getPluginInstance($apiProviderId); if ($pluginInstance && method_exists($pluginInstance, 'searchModels')) { $models = $pluginInstance->searchModels($search); $options = []; foreach ($models as $model) { $options[json_encode(['name' => $model['name'], 'id' => $model['id'], 'type' => $model['type'] ?? null, 'api_provider_id' => $apiProviderId])] = $model['name'] . ' (' . $model['id'] . ')'; } return $options; } return []; }) ->getOptionLabelUsing(function ($value) { $decoded = json_decode($value, true); return $decoded['name'] . ' (' . $decoded['id'] . ')'; }) ->afterStateUpdated(function (callable $set, $state) { if ($state) { $selectedModel = json_decode($state, true); if (json_last_error() !== JSON_ERROR_NONE) { return; // Stop if JSON is invalid } $set('name', $selectedModel['name']); $set('model_id', $selectedModel['id']); $set('model_type', $selectedModel['type'] ?? null); } }), TextInput::make('name') ->label(__('filament.resource.ai_model.form.name')) ->required() ->maxLength(255) ->live(), TextInput::make('model_id') ->label(__('filament.resource.ai_model.form.model_id')) ->required() ->maxLength(255) ->live(), TextInput::make('model_type') ->nullable() ->maxLength(255) ->live(), Forms\Components\Toggle::make('enabled') ->label(__('filament.resource.ai_model.form.enabled')) ->default(true), Forms\Components\Textarea::make('parameters') ->label(__('filament.resource.ai_model.form.parameters')) ->nullable() ->rows(15) ->json(JSON_PRETTY_PRINT) ->helperText(__('filament.resource.ai_model.form.parameters_help')) ]) ]); } 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')->label(__('filament.resource.ai_model.table.name'))->searchable()->sortable(), TextColumn::make('model_id')->label(__('filament.resource.ai_model.table.model_id'))->searchable()->sortable(), TextColumn::make('model_type')->label(__('filament.resource.ai_model.table.model_type'))->searchable()->sortable(), Tables\Columns\IconColumn::make('enabled') ->label(__('filament.resource.ai_model.table.enabled')) ->boolean(), TextColumn::make('primaryApiProvider.name')->label(__('filament.resource.ai_model.table.api_provider'))->searchable()->sortable()->limit(50), ]) ->filters([ // ]) ->actions([ Tables\Actions\EditAction::make(), Action::make('duplicate') ->label(__('filament.resource.style.action.duplicate')) ->icon('heroicon-o-document-duplicate') ->action(function (AiModel $record, $livewire) { $livewire->redirect(AiModelResource::getUrl('create', ['sourceRecord' => $record->id])); }), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]) ->emptyStateActions([ Tables\Actions\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'), ]; } }