diff --git a/app/Filament/Resources/AiModels/AiModelResource.php b/app/Filament/Resources/AiModels/AiModelResource.php index a40386d..871c5fb 100644 --- a/app/Filament/Resources/AiModels/AiModelResource.php +++ b/app/Filament/Resources/AiModels/AiModelResource.php @@ -2,29 +2,24 @@ namespace App\Filament\Resources\AiModels; -use BackedEnum; -use App\Filament\Resources\AiModels\Pages; -use App\Filament\Resources\AiModels\RelationManagers; -use App\Models\AiModel; -use Filament\Schemas\Schema; -use Filament\Resources\Resource; -use Filament\Tables; -use Filament\Tables\Table; -use Filament\Tables\Columns\TextColumn; -use Filament\Tables\Columns\IconColumn; -use Illuminate\Database\Eloquent\SoftDeletingScope; -use Illuminate\Database\Eloquent\Model; -use App\Models\ApiProvider; -use App\Api\Plugins\PluginLoader; use App\Api\Plugins\ApiPluginInterface; +use App\Api\Plugins\PluginLoader; +use App\Models\AiModel; +use App\Models\ApiProvider; use Filament\Actions\Action; use Filament\Actions\BulkActionGroup; use Filament\Actions\CreateAction; use Filament\Actions\DeleteBulkAction; use Filament\Actions\EditAction; +use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; -use Filament\Forms\Components\Textarea; +use Filament\Resources\Resource; +use Filament\Schemas\Schema; +use Filament\Tables\Columns\IconColumn; +use Filament\Tables\Columns\TextColumn; +use Filament\Tables\Table; +use Illuminate\Database\Eloquent\Model; class AiModelResource extends Resource { @@ -32,6 +27,13 @@ class AiModelResource extends Resource // protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; + protected static ?int $navigationSort = -100; + + public static function getNavigationGroup(): ?string + { + return __('filament.navigation.groups.ai_models'); + } + public static function form(Schema $schema): Schema { return $schema @@ -49,16 +51,16 @@ class AiModelResource extends Resource ->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) { + if (! $apiProvider || ! $apiProvider->plugin) { continue; } try { @@ -71,16 +73,17 @@ class AiModelResource extends Resource continue; } } + return false; } protected static function getPluginInstance(?int $apiProviderId): ?ApiPluginInterface { - if (!$apiProviderId) { + if (! $apiProviderId) { return null; } $apiProvider = ApiProvider::find($apiProviderId); - if (!$apiProvider || !$apiProvider->plugin) { + if (! $apiProvider || ! $apiProvider->plugin) { return null; } try { @@ -93,15 +96,16 @@ class AiModelResource extends Resource protected static function canSearchModels(?int $apiProviderId): bool { - if (!$apiProviderId) { + if (! $apiProviderId) { return false; } $apiProvider = ApiProvider::find($apiProviderId); - if (!$apiProvider || !$apiProvider->plugin) { + 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 @@ -141,14 +145,14 @@ class AiModelResource extends Resource CreateAction::make(), ]); } - + public static function getRelations(): array { return [ // ]; } - + public static function getPages(): array { return [ @@ -156,5 +160,5 @@ class AiModelResource extends Resource 'create' => Pages\CreateAiModel::route('/create'), 'edit' => Pages\EditAiModel::route('/{record}/edit'), ]; - } + } } diff --git a/app/Filament/Resources/ApiProviders/ApiProviderResource.php b/app/Filament/Resources/ApiProviders/ApiProviderResource.php index 2a29221..6b0890a 100644 --- a/app/Filament/Resources/ApiProviders/ApiProviderResource.php +++ b/app/Filament/Resources/ApiProviders/ApiProviderResource.php @@ -2,28 +2,22 @@ namespace App\Filament\Resources\ApiProviders; -use App\Filament\Resources\ApiProviders\Pages; -use App\Filament\Resources\ApiProviders\RelationManagers; +use App\Api\Plugins\ApiPluginInterface; use App\Models\ApiProvider; -use Filament\Schemas; -use Filament\Schemas\Schema; -use Filament\Resources\Resource; -use Filament\Tables; +use BackedEnum; use Filament\Actions\BulkActionGroup; use Filament\Actions\CreateAction; use Filament\Actions\DeleteBulkAction; use Filament\Actions\EditAction; -use Filament\Tables\Table; -use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\SoftDeletingScope; -use Filament\Forms\Components\TextInput; -use Filament\Tables\Columns\TextColumn; use Filament\Forms\Components\Select; -use Illuminate\Support\Facades\File; -use App\Api\Plugins\ApiPluginInterface; +use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; +use Filament\Resources\Resource; +use Filament\Schemas\Schema; use Filament\Tables\Columns\IconColumn; -use BackedEnum; +use Filament\Tables\Columns\TextColumn; +use Filament\Tables\Table; +use Illuminate\Support\Facades\File; class ApiProviderResource extends Resource { @@ -31,9 +25,17 @@ class ApiProviderResource extends Resource protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-rectangle-stack'; + protected static ?int $navigationSort = -90; + + public static function getNavigationGroup(): ?string + { + return __('filament.navigation.groups.ai_models'); + } + public static function form(Schema $schema): Schema { $plugins = self::getAvailablePlugins(); + return $schema ->components([ TextInput::make('name') @@ -86,14 +88,14 @@ class ApiProviderResource extends Resource CreateAction::make(), ]); } - + public static function getRelations(): array { return [ // ]; } - + public static function getPages(): array { return [ @@ -102,23 +104,24 @@ class ApiProviderResource extends Resource 'edit' => Pages\EditApiProvider::route('/{record}/edit'), ]; } - + protected static function getAvailablePlugins(): array { $plugins = []; $path = app_path('Api/Plugins'); $files = File::files($path); - + foreach ($files as $file) { $filename = $file->getFilenameWithoutExtension(); if (in_array($filename, ['ApiPluginInterface', 'PluginLoader'])) { continue; } - $class = "App\Api\Plugins\\" . $filename; + $class = "App\Api\Plugins\\".$filename; if (class_exists($class) && in_array(ApiPluginInterface::class, class_implements($class))) { $plugins[$filename] = $filename; } } + return $plugins; } } diff --git a/app/Filament/Resources/Images/ImageResource.php b/app/Filament/Resources/Images/ImageResource.php index 2b65048..5ba0273 100644 --- a/app/Filament/Resources/Images/ImageResource.php +++ b/app/Filament/Resources/Images/ImageResource.php @@ -2,25 +2,19 @@ namespace App\Filament\Resources\Images; -use BackedEnum; -use App\Filament\Resources\Images\Pages; -use App\Filament\Resources\Images\RelationManagers; use App\Models\Image; -use Filament\Schemas; -use Filament\Schemas\Schema; -use Filament\Resources\Resource; -use Filament\Tables; -use Filament\Tables\Table; -use Illuminate\Database\Eloquent\SoftDeletingScope; -use Filament\Forms\Components\TextInput; -use Filament\Tables\Columns\TextColumn; -use Filament\Tables\Columns\ImageColumn; -use Filament\Forms\Components\FileUpload; -use Filament\Forms\Components\Toggle; +use BackedEnum; use Filament\Actions\BulkActionGroup; use Filament\Actions\CreateAction; use Filament\Actions\DeleteBulkAction; use Filament\Actions\EditAction; +use Filament\Forms\Components\FileUpload; +use Filament\Forms\Components\Toggle; +use Filament\Resources\Resource; +use Filament\Schemas\Schema; +use Filament\Tables\Columns\ImageColumn; +use Filament\Tables\Columns\TextColumn; +use Filament\Tables\Table; class ImageResource extends Resource { @@ -28,6 +22,11 @@ class ImageResource extends Resource protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-rectangle-stack'; + public static function getNavigationGroup(): ?string + { + return __('filament.navigation.groups.content'); + } + public static function form(Schema $schema): Schema { return $schema @@ -65,14 +64,14 @@ class ImageResource extends Resource CreateAction::make(), ]); } - + public static function getRelations(): array { return [ // ]; } - + public static function getPages(): array { return [ diff --git a/app/Filament/Resources/Roles/RoleResource.php b/app/Filament/Resources/Roles/RoleResource.php index b435b81..3f8c84c 100644 --- a/app/Filament/Resources/Roles/RoleResource.php +++ b/app/Filament/Resources/Roles/RoleResource.php @@ -2,30 +2,28 @@ namespace App\Filament\Resources\Roles; -use UnitEnum; -use App\Filament\Resources\Roles\Pages; -use App\Filament\Resources\Roles\RelationManagers; use App\Models\Role; -use Filament\Schemas; -use Filament\Schemas\Schema; -use Filament\Resources\Resource; -use Filament\Tables; -use Filament\Tables\Table; -use Illuminate\Database\Eloquent\SoftDeletingScope; -use Filament\Forms\Components\TextInput; -use Filament\Tables\Columns\TextColumn; use Filament\Actions\BulkActionGroup; use Filament\Actions\CreateAction; use Filament\Actions\DeleteBulkAction; use Filament\Actions\EditAction; +use Filament\Forms\Components\TextInput; +use Filament\Resources\Resource; +use Filament\Schemas\Schema; +use Filament\Tables\Columns\TextColumn; +use Filament\Tables\Table; +use UnitEnum; class RoleResource extends Resource { protected static ?string $model = Role::class; protected static UnitEnum|string|null $navigationGroup = 'User Management'; + protected static ?string $navigationLabel = 'User Roles'; + protected static bool $shouldRegisterNavigation = false; + public static function form(Schema $schema): Schema { return $schema @@ -57,14 +55,14 @@ class RoleResource extends Resource CreateAction::make(), ]); } - + public static function getRelations(): array { return [ // ]; } - + public static function getPages(): array { return [ @@ -72,5 +70,5 @@ class RoleResource extends Resource 'create' => Pages\CreateRole::route('/create'), 'edit' => Pages\EditRole::route('/{record}/edit'), ]; - } + } } diff --git a/app/Filament/Resources/Styles/StyleResource.php b/app/Filament/Resources/Styles/StyleResource.php index cb73c76..e89f870 100644 --- a/app/Filament/Resources/Styles/StyleResource.php +++ b/app/Filament/Resources/Styles/StyleResource.php @@ -1,38 +1,43 @@ icon('heroicon-o-document-duplicate') ->action(function (\App\Models\Style $record) { $newStyle = $record->replicate(); - $newStyle->title = $record->title . ' (Kopie)'; + $newStyle->title = $record->title.' (Kopie)'; $newStyle->save(); + return redirect()->to(\App\Filament\Resources\Styles\StyleResource::getUrl('edit', ['record' => $newStyle->id])); }), ]) @@ -135,14 +141,14 @@ class StyleResource extends Resource CreateAction::make(), ]); } - + public static function getRelations(): array { return [ // ]; } - + public static function getPages(): array { return [ @@ -150,5 +156,5 @@ class StyleResource extends Resource 'create' => Pages\CreateStyle::route('/create'), 'edit' => Pages\EditStyle::route('/{record}/edit'), ]; - } + } } diff --git a/app/Filament/Resources/Users/UserResource.php b/app/Filament/Resources/Users/UserResource.php index afb8690..ec31f7c 100644 --- a/app/Filament/Resources/Users/UserResource.php +++ b/app/Filament/Resources/Users/UserResource.php @@ -2,31 +2,27 @@ namespace App\Filament\Resources\Users; -use UnitEnum; -use App\Filament\Resources\Users\Pages; -use App\Filament\Resources\Users\RelationManagers; use App\Models\User; -use Filament\Schemas; -use Filament\Schemas\Schema; -use Filament\Resources\Resource; -use Filament\Tables; -use Filament\Tables\Table; -use Illuminate\Database\Eloquent\SoftDeletingScope; -use Filament\Forms\Components\TextInput; -use Filament\Tables\Columns\TextColumn; -use Filament\Forms\Components\Select; -use Filament\Schemas\Components\Section; -use Filament\Forms\Components\Toggle; use Filament\Actions\BulkActionGroup; use Filament\Actions\CreateAction; use Filament\Actions\DeleteBulkAction; use Filament\Actions\EditAction; +use Filament\Forms\Components\Select; +use Filament\Forms\Components\TextInput; +use Filament\Forms\Components\Toggle; +use Filament\Resources\Resource; +use Filament\Schemas\Components\Section; +use Filament\Schemas\Schema; +use Filament\Tables\Columns\TextColumn; +use Filament\Tables\Table; +use UnitEnum; class UserResource extends Resource { protected static ?string $model = User::class; protected static string|UnitEnum|null $navigationGroup = 'User Management'; + protected static ?string $navigationLabel = 'Users'; public static function form(Schema $schema): Schema @@ -98,14 +94,14 @@ class UserResource extends Resource CreateAction::make(), ]); } - + public static function getRelations(): array { return [ // ]; } - + public static function getPages(): array { return [ @@ -122,6 +118,6 @@ class UserResource extends Resource public static function getNavigationLabel(): string { - return __('filament.navigation.user_roles'); - } + return __('filament.navigation.users'); + } } diff --git a/database/seeders/AiModelSeeder.php b/database/seeders/AiModelSeeder.php index 8612ee2..3d4003d 100644 --- a/database/seeders/AiModelSeeder.php +++ b/database/seeders/AiModelSeeder.php @@ -58,7 +58,251 @@ class AiModelSeeder extends Seeder 'model_id' => 'flux1-kontext-dev', 'api_provider_id' => null, 'enabled' => 1, - 'parameters' => json_encode(['example' => 'parameter']), + 'parameters' => '{ + "1": { + "inputs": { + "vae_name": "ae.safetensors" + }, + "class_type": "VAELoader", + "_meta": { + "title": "Load VAE" + } + }, + "2": { + "inputs": { + "clip_name1": "clip_l.safetensors", + "clip_name2": "t5xxl_fp8_e4m3fn_scaled.safetensors", + "type": "flux", + "device": "default" + }, + "class_type": "DualCLIPLoader", + "_meta": { + "title": "DualCLIPLoader" + } + }, + "3": { + "inputs": { + "conditioning": [ + "25", + 0 + ] + }, + "class_type": "ConditioningZeroOut", + "_meta": { + "title": "ConditioningZeroOut" + } + }, + "4": { + "inputs": { + "images": [ + "9", + 0 + ] + }, + "class_type": "PreviewImage", + "_meta": { + "title": "Preview Image" + } + }, + "5": { + "inputs": { + "filename_prefix": "ComfyUI", + "images": [ + "7", + 0 + ] + }, + "class_type": "SaveImage", + "_meta": { + "title": "Save Image" + } + }, + "7": { + "inputs": { + "samples": [ + "20", + 0 + ], + "vae": [ + "1", + 0 + ] + }, + "class_type": "VAEDecode", + "_meta": { + "title": "VAE Decode" + } + }, + "8": { + "inputs": { + "pixels": [ + "9", + 0 + ], + "vae": [ + "1", + 0 + ] + }, + "class_type": "VAEEncode", + "_meta": { + "title": "VAE Encode" + } + }, + "9": { + "inputs": { + "image": [ + "27", + 0 + ] + }, + "class_type": "FluxKontextImageScale", + "_meta": { + "title": "FluxKontextImageScale" + } + }, + "11": { + "inputs": { + "direction": "right", + "match_image_size": true, + "spacing_width": 0, + "spacing_color": "white", + "image1": [ + "24", + 0 + ] + }, + "class_type": "ImageStitch", + "_meta": { + "title": "Image Stitch" + } + }, + "12": { + "inputs": { + "guidance": 2.5, + "conditioning": [ + "17", + 0 + ] + }, + "class_type": "FluxGuidance", + "_meta": { + "title": "FluxGuidance" + } + }, + "17": { + "inputs": { + "conditioning": [ + "25", + 0 + ], + "latent": [ + "8", + 0 + ] + }, + "class_type": "ReferenceLatent", + "_meta": { + "title": "ReferenceLatent" + } + }, + "20": { + "inputs": { + "seed": 71319103185943, + "steps": 8, + "cfg": 1, + "sampler_name": "euler", + "scheduler": "simple", + "denoise": 1, + "model": [ + "26", + 0 + ], + "positive": [ + "12", + 0 + ], + "negative": [ + "3", + 0 + ], + "latent_image": [ + "8", + 0 + ] + }, + "class_type": "KSampler", + "_meta": { + "title": "KSampler" + } + }, + "22": { + "inputs": { + "model_path": "svdq-int4_r32-flux.1-kontext-dev.safetensors", + "cache_threshold": 0, + "attention": "nunchaku-fp16", + "cpu_offload": "auto", + "device_id": 0, + "data_type": "bfloat16", + "i2f_mode": "enabled" + }, + "class_type": "NunchakuFluxDiTLoader", + "_meta": { + "title": "Nunchaku FLUX DiT Loader" + } + }, + "24": { + "inputs": { + "image": "__FILENAME__", + "refresh": "refresh" + }, + "class_type": "LoadImageOutput", + "_meta": { + "title": "Load Image (from Outputs)" + } + }, + "25": { + "inputs": { + "text": "__PROMPT__", + "clip": [ + "2", + 0 + ] + }, + "class_type": "CLIPTextEncode", + "_meta": { + "title": "CLIP Text Encode (Positive Prompt)" + } + }, + "26": { + "inputs": { + "lora_name": "flux.1-kontext-dev-turbo_lora.safetensors", + "lora_strength": 1, + "model": [ + "22", + 0 + ] + }, + "class_type": "NunchakuFluxLoraLoader", + "_meta": { + "title": "Nunchaku FLUX.1 LoRA Loader" + } + }, + "27": { + "inputs": { + "upscale_method": "nearest-exact", + "megapixels": 1.2000000000000002, + "image": [ + "11", + 0 + ] + }, + "class_type": "ImageScaleToTotalPixels", + "_meta": { + "title": "Scale Image to Total Pixels" + } + } + }', ], [ 'id' => 8, diff --git a/resources/js/Components/ImageContextMenu.vue b/resources/js/Components/ImageContextMenu.vue index 4aeb43b..c53f187 100644 --- a/resources/js/Components/ImageContextMenu.vue +++ b/resources/js/Components/ImageContextMenu.vue @@ -1,8 +1,11 @@ @@ -101,28 +90,10 @@ function handleTouchEnd(event) { @click="showingNavigationDropdown = !showingNavigationDropdown" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-hidden focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out" > - - - - + diff --git a/resources/js/Pages/Home.vue b/resources/js/Pages/Home.vue index af1047a..a19edf1 100644 --- a/resources/js/Pages/Home.vue +++ b/resources/js/Pages/Home.vue @@ -17,20 +17,7 @@ @click="handleManualRefresh" :disabled="isRefreshing" > - - - + {{ isRefreshing ? 'Aktualisiere…' : 'Jetzt aktualisieren' }} @@ -62,9 +43,7 @@ Letzte Synchronisierung: {{ formattedLastRefresh }}
- - - + Einfach über die Galerie wischen, um Seiten zu wechseln.
diff --git a/resources/js/Pages/Welcome.vue b/resources/js/Pages/Welcome.vue index 9313a00..b3ad1be 100644 --- a/resources/js/Pages/Welcome.vue +++ b/resources/js/Pages/Welcome.vue @@ -51,17 +51,10 @@ defineProps({
- - - +
diff --git a/resources/js/app.js b/resources/js/app.js index 8f340d0..b0f9c7b 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -9,10 +9,38 @@ import { ZiggyVue } from '../../vendor/tightenco/ziggy'; /* Font Awesome imports */ import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; -import { faPrint, faMagicWandSparkles, faXmark } from '@fortawesome/free-solid-svg-icons'; +import { + faPrint, + faMagicWandSparkles, + faXmark, + faArrowLeft, + faArrowRight, + faSun, + faMoon, + faArrowsRotate, + faMinus, + faPlus, + faBars, + faChevronDown, + faDownload, +} from '@fortawesome/free-solid-svg-icons'; // Add icons to the library -library.add(faPrint, faMagicWandSparkles, faXmark); +library.add( + faPrint, + faMagicWandSparkles, + faXmark, + faArrowLeft, + faArrowRight, + faSun, + faMoon, + faArrowsRotate, + faMinus, + faPlus, + faBars, + faChevronDown, + faDownload, +); const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; diff --git a/resources/lang/de/filament.php b/resources/lang/de/filament.php index f618f79..a0831bb 100644 --- a/resources/lang/de/filament.php +++ b/resources/lang/de/filament.php @@ -2,7 +2,7 @@ return [ 'resource' => [ - 'ai_model' => [ + 'ai_model' => [ 'form' => [ 'name' => 'Name', 'model_id' => 'Modell ID', @@ -146,13 +146,15 @@ return [ ], 'navigation' => [ 'groups' => [ + 'ai_models' => 'AI-Modelle', + 'content' => 'Inhalte', 'plugins' => 'Plugins', 'settings' => 'Einstellungen', 'user_management' => 'Benutzerverwaltung', ], 'install_plugin' => 'Plugin installieren', 'plugin_list' => 'Plugin-Liste', - 'user_roles' => 'Benutzerrollen', + 'users' => 'Benutzer', ], 'styled_image_display' => [ 'title' => 'Neu gestyltes Bild', @@ -160,6 +162,6 @@ return [ 'delete_button' => 'Löschen', ], 'loading_spinner' => [ - 'processing_image' => 'Bild wird verarbeitet...', + 'processing_image' => 'Bild wird verarbeitet...', ], ]; diff --git a/resources/lang/en/filament.php b/resources/lang/en/filament.php index 5a61423..f710005 100644 --- a/resources/lang/en/filament.php +++ b/resources/lang/en/filament.php @@ -102,8 +102,8 @@ return [ 'image_refresh_interval' => 'Image Refresh Interval (seconds)', 'new_image_timespan_minutes' => 'New Image Timespan (minutes)', 'gallery_heading' => 'Gallery Heading', - "max_number_of_copies" => "Max Number of Copies", - "show_print_button" => "Show 'Print' button on image", + 'max_number_of_copies' => 'Max Number of Copies', + 'show_print_button' => "Show 'Print' button on image", ], ], 'user' => [ @@ -125,15 +125,17 @@ return [ ], 'navigation' => [ 'groups' => [ + 'ai_models' => 'AI models', + 'content' => 'Content', 'plugins' => 'Plugins', 'settings' => 'Settings', 'user_management' => 'User Management', ], 'install_plugin' => 'Install Plugin', 'plugin_list' => 'Plugin List', - 'user_roles' => 'User Roles', + 'users' => 'Users', ], 'loading_spinner' => [ 'processing_image' => 'Processing image...', ], -]; \ No newline at end of file +];