From d271f256b706fac90096f1b9176142ad73de9254 Mon Sep 17 00:00:00 2001 From: SEB Fotografie - soeren Date: Fri, 29 Aug 2025 14:09:01 +0200 Subject: [PATCH] tabelle ai_model_api_provider entfernt --- PRP.md | 2 - app/Api/Plugins/ApiPluginInterface.php | 1 + app/Api/Plugins/ComfyUi.php | 5 ++ app/Api/Plugins/RunwareAi.php | 7 +- app/Filament/Resources/AiModelResource.php | 32 ++++---- app/Http/Controllers/Api/ImageController.php | 82 ++++--------------- app/Http/Controllers/Api/StyleController.php | 4 +- app/Models/AiModel.php | 6 +- app/Models/ApiProvider.php | 2 +- ...025_08_22_123016_create_initial_schema.php | 6 -- database/seeders/AiModelApiProviderSeeder.php | 3 +- 11 files changed, 47 insertions(+), 103 deletions(-) diff --git a/PRP.md b/PRP.md index 054ccf8..1c6c54b 100644 --- a/PRP.md +++ b/PRP.md @@ -258,8 +258,6 @@ Key tables and their relevant columns: - `created_at`: `timestamp null` - `updated_at`: `timestamp null` -- **`ai_model_api_provider`** (Pivot table for many-to-many relationship) - - `ai_model_id`: `bigint unsigned` (FK to `ai_models.id`) - `api_provider_id`: `bigint unsigned` (FK to `api_providers.id`) - **`settings`** diff --git a/app/Api/Plugins/ApiPluginInterface.php b/app/Api/Plugins/ApiPluginInterface.php index dd0cbdd..8bc8c42 100644 --- a/app/Api/Plugins/ApiPluginInterface.php +++ b/app/Api/Plugins/ApiPluginInterface.php @@ -12,6 +12,7 @@ interface ApiPluginInterface public function getStatus(string $imageUUID): array; public function getProgress(string $imageUUID): array; public function processImageStyleChange(\App\Models\Image $image, \App\Models\Style $style): array; + public function getStyledImage(string $promptId): string; public function testConnection(array $data): bool; public function searchModels(string $searchTerm): array; } \ No newline at end of file diff --git a/app/Api/Plugins/ComfyUi.php b/app/Api/Plugins/ComfyUi.php index fdb59ec..aebdc78 100644 --- a/app/Api/Plugins/ComfyUi.php +++ b/app/Api/Plugins/ComfyUi.php @@ -260,4 +260,9 @@ class ComfyUi implements ApiPluginInterface $this->logInfo('ComfyUI does not support model search. Returning empty list.', ['searchTerm' => $searchTerm]); return []; } + + public function getStyledImage(string $promptId): string + { + return $this->waitForResult($promptId); + } } \ No newline at end of file diff --git a/app/Api/Plugins/RunwareAi.php b/app/Api/Plugins/RunwareAi.php index c0f584e..e15f831 100644 --- a/app/Api/Plugins/RunwareAi.php +++ b/app/Api/Plugins/RunwareAi.php @@ -56,6 +56,11 @@ class RunwareAi implements ApiPluginInterface } return $result; } + + public function getStyledImage(string $promptId): string + { + throw new \Exception('RunwareAi does not support fetching styled images by prompt ID.'); + } public function getStatus(string $imageUUID): array { @@ -248,7 +253,7 @@ class RunwareAi implements ApiPluginInterface 'positivePrompt' => $style->prompt, 'seedImage' => $seedImageUUID, 'outputType' => 'base64Data', - 'model' => $style->aiModel->model_id, + 'model' => $style->aiModel->model_id ]; foreach ($mergedParams as $key => $value) { diff --git a/app/Filament/Resources/AiModelResource.php b/app/Filament/Resources/AiModelResource.php index 4b49bb7..695e799 100644 --- a/app/Filament/Resources/AiModelResource.php +++ b/app/Filament/Resources/AiModelResource.php @@ -32,10 +32,9 @@ class AiModelResource extends Resource ->schema([ Forms\Components\Section::make() ->schema([ - Select::make('apiProviders') - ->label(__('filament.resource.ai_model.form.api_providers')) - ->relationship('apiProviders', 'name') - ->multiple() + 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); @@ -44,24 +43,21 @@ class AiModelResource extends Resource ->label(__('filament.resource.ai_model.form.search_model')) ->searchable() ->live() - ->hidden(fn (callable $get) => !static::canSearchModelsWithAnyProvider($get('apiProviders'))) + ->hidden(fn (callable $get) => !static::canSearchModels($get('api_provider_id'))) ->getSearchResultsUsing(function (string $search, callable $get) { - $apiProviderIds = $get('apiProviders'); - if (empty($apiProviderIds)) { + $apiProviderId = $get('api_provider_id'); + if (!$apiProviderId) { return []; } - // Try each API provider until we find one that works - foreach ($apiProviderIds as $apiProviderId) { - $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; + $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 []; }) @@ -176,7 +172,7 @@ class AiModelResource extends Resource Tables\Columns\IconColumn::make('enabled') ->label(__('filament.resource.ai_model.table.enabled')) ->boolean(), - TextColumn::make('apiProviders.name')->label(__('filament.resource.ai_model.table.api_providers'))->searchable()->sortable()->limit(50), + TextColumn::make('primaryApiProvider.name')->label(__('filament.resource.ai_model.table.api_provider'))->searchable()->sortable()->limit(50), ]) ->filters([ // diff --git a/app/Http/Controllers/Api/ImageController.php b/app/Http/Controllers/Api/ImageController.php index 296d7d5..c186e1c 100644 --- a/app/Http/Controllers/Api/ImageController.php +++ b/app/Http/Controllers/Api/ImageController.php @@ -138,23 +138,19 @@ class ImageController extends Controller if ($request->style_id) { $style = Style::with(['aiModel' => function ($query) { - $query->where('enabled', true)->with(['primaryApiProvider', 'apiProviders' => function ($query) { - $query->where('enabled', true); - }]); + $query->where('enabled', true)->with('primaryApiProvider'); }])->find($request->style_id); } else { // Attempt to get default style from settings $defaultStyleSetting = \App\Models\Setting::where('key', 'default_style_id')->first(); if ($defaultStyleSetting && $defaultStyleSetting->value) { $style = Style::with(['aiModel' => function ($query) { - $query->where('enabled', true)->with(['primaryApiProvider', 'apiProviders' => function ($query) { - $query->where('enabled', true); - }]); + $query->where('enabled', true)->with('primaryApiProvider'); }])->find($defaultStyleSetting->value); } } - if (!$style || !$style->aiModel || $style->aiModel->apiProviders->isEmpty()) { + if (!$style || !$style->aiModel || !$style->aiModel->primaryApiProvider) { \Illuminate\Support\Facades\Log::warning('Style or provider not found', [ 'style' => $style ? $style->toArray() : null, 'ai_model' => $style && $style->aiModel ? $style->aiModel->toArray() : null @@ -163,16 +159,8 @@ class ImageController extends Controller } try { - // Use the primary API provider for this AI model if available + // Use the primary API provider for this AI model $apiProvider = $style->aiModel->primaryApiProvider; - if (!$apiProvider) { - // Fallback to the first enabled API provider from the many-to-many relationship - $apiProvider = $style->aiModel->apiProviders->where('enabled', true)->first(); - } - if (!$apiProvider) { - // If no enabled provider found, try any provider - $apiProvider = $style->aiModel->apiProviders->first(); - } if (!$apiProvider) { \Illuminate\Support\Facades\Log::error('No API provider found for style', [ 'style_id' => $style->id, @@ -276,9 +264,7 @@ class ImageController extends Controller try { // Find the image associated with the prompt_id, eagerly loading relationships $image = Image::with(['style.aiModel' => function ($query) { - $query->with(['primaryApiProvider', 'apiProviders' => function ($query) { - $query->where('enabled', true); - }]); + $query->with('primaryApiProvider'); }])->where('comfyui_prompt_id', $promptId)->first(); if (!$image) { @@ -302,26 +288,18 @@ class ImageController extends Controller } Log::info('fetchStyledImage: AI Model found.', ['ai_model_id' => $style->aiModel->id, 'ai_model_name' => $style->aiModel->name]); - if ($style->aiModel->apiProviders->isEmpty()) { - Log::warning('fetchStyledImage: No enabled API Providers found for AI Model.', ['ai_model_id' => $style->aiModel->id]); - return response()->json(['error' => __('api.style_or_provider_not_found')], 404); - } - // Use the primary API provider for this AI model if available + // Use the primary API provider for this AI model $apiProvider = $style->aiModel->primaryApiProvider; if (!$apiProvider) { - // Fallback to the first enabled API provider from the many-to-many relationship - $apiProvider = $style->aiModel->apiProviders->where('enabled', true)->first(); - } - if (!$apiProvider) { - // If no enabled provider found, try any provider - $apiProvider = $style->aiModel->apiProviders->first(); + Log::warning('fetchStyledImage: No API Provider found for AI Model.', ['ai_model_id' => $style->aiModel->id]); + return response()->json(['error' => __('api.style_or_provider_not_found')], 404); } Log::info('fetchStyledImage: API Provider found.', ['api_provider_id' => $apiProvider->id, 'api_provider_name' => $apiProvider->name]); Log::info('Fetching base64 image from plugin.', ['prompt_id' => $promptId, 'api_provider' => $apiProvider->name]); // Use the plugin to get the final image data (e.g., from ComfyUI's history/view) $plugin = PluginLoader::getPlugin($apiProvider->plugin, $apiProvider); - $base64Image = $plugin->waitForResult($promptId); // Re-purpose waitForResult for final fetch + $base64Image = $plugin->getStyledImage($promptId); // Use the new method if (empty($base64Image)) { Log::error('Received empty base64 image from plugin.', ['prompt_id' => $promptId]); @@ -376,43 +354,23 @@ class ImageController extends Controller // If style_id is provided, get the API provider for that style if ($styleId) { $style = Style::with(['aiModel' => function ($query) { - $query->where('enabled', true)->with(['primaryApiProvider', 'apiProviders' => function ($query) { - $query->where('enabled', true); - }]); + $query->where('enabled', true)->with('primaryApiProvider'); }])->find($styleId); if ($style && $style->aiModel) { - // Use the primary API provider for this AI model if available + // Use the primary API provider for this AI model $apiProvider = $style->aiModel->primaryApiProvider; - if (!$apiProvider) { - // Fallback to the first enabled API provider from the many-to-many relationship - $apiProvider = $style->aiModel->apiProviders->where('enabled', true)->first(); - } - if (!$apiProvider) { - // If no enabled provider found, try any provider - $apiProvider = $style->aiModel->apiProviders->first(); - } } } // If image_uuid is provided, get the API provider for that image's style elseif ($imageUuid) { $image = Image::with(['style.aiModel' => function ($query) { - $query->with(['primaryApiProvider', 'apiProviders' => function ($query) { - $query->where('enabled', true); - }]); + $query->with('primaryApiProvider'); }])->where('uuid', $imageUuid)->first(); if ($image && $image->style && $image->style->aiModel) { - // Use the primary API provider for this AI model if available + // Use the primary API provider for this AI model $apiProvider = $image->style->aiModel->primaryApiProvider; - if (!$apiProvider) { - // Fallback to the first enabled API provider from the many-to-many relationship - $apiProvider = $image->style->aiModel->apiProviders->where('enabled', true)->first(); - } - if (!$apiProvider) { - // If no enabled provider found, try any provider - $apiProvider = $image->style->aiModel->apiProviders->first(); - } } } // Fallback to the old behavior if no style_id or image_uuid is provided @@ -421,22 +379,12 @@ class ImageController extends Controller $defaultStyleSetting = \App\Models\Setting::where('key', 'default_style_id')->first(); if ($defaultStyleSetting && $defaultStyleSetting->value) { $style = Style::with(['aiModel' => function ($query) { - $query->where('enabled', true)->with(['primaryApiProvider', 'apiProviders' => function ($query) { - $query->where('enabled', true); - }]); + $query->where('enabled', true)->with('primaryApiProvider'); }])->find($defaultStyleSetting->value); if ($style && $style->aiModel) { - // Use the primary API provider for this AI model if available + // Use the primary API provider for this AI model $apiProvider = $style->aiModel->primaryApiProvider; - if (!$apiProvider) { - // Fallback to the first enabled API provider from the many-to-many relationship - $apiProvider = $style->aiModel->apiProviders->where('enabled', true)->first(); - } - if (!$apiProvider) { - // If no enabled provider found, try any provider - $apiProvider = $style->aiModel->apiProviders->first(); - } } } diff --git a/app/Http/Controllers/Api/StyleController.php b/app/Http/Controllers/Api/StyleController.php index 3b6fe71..3054137 100644 --- a/app/Http/Controllers/Api/StyleController.php +++ b/app/Http/Controllers/Api/StyleController.php @@ -11,11 +11,11 @@ class StyleController extends Controller { public function index() { - $styles = Style::with(['aiModel.apiProviders']) + $styles = Style::with(['aiModel.primaryApiProvider']) ->where('enabled', true) ->whereHas('aiModel', function ($query) { $query->where('enabled', true); - $query->whereHas('apiProviders', function ($query) { + $query->whereHas('primaryApiProvider', function ($query) { $query->where('enabled', true); }); }) diff --git a/app/Models/AiModel.php b/app/Models/AiModel.php index 85eda30..20c5dc4 100644 --- a/app/Models/AiModel.php +++ b/app/Models/AiModel.php @@ -14,6 +14,7 @@ class AiModel extends Model 'model_id', 'model_type', 'parameters', + 'api_provider_id', ]; protected $casts = [ @@ -24,9 +25,4 @@ class AiModel extends Model { return $this->belongsTo(ApiProvider::class, 'api_provider_id'); } - - public function apiProviders() - { - return $this->belongsToMany(ApiProvider::class, 'ai_model_api_provider'); - } } \ No newline at end of file diff --git a/app/Models/ApiProvider.php b/app/Models/ApiProvider.php index 183ee35..66b3d01 100644 --- a/app/Models/ApiProvider.php +++ b/app/Models/ApiProvider.php @@ -30,6 +30,6 @@ class ApiProvider extends Model public function aiModels() { - return $this->belongsToMany(AiModel::class, 'ai_model_api_provider'); + return $this->hasMany(AiModel::class, 'api_provider_id'); } } \ No newline at end of file diff --git a/database/migrations/2025_08_22_123016_create_initial_schema.php b/database/migrations/2025_08_22_123016_create_initial_schema.php index 0687410..5b45715 100644 --- a/database/migrations/2025_08_22_123016_create_initial_schema.php +++ b/database/migrations/2025_08_22_123016_create_initial_schema.php @@ -91,11 +91,6 @@ return new class extends Migration $table->timestamps(); }); - Schema::create('ai_model_api_provider', function (Blueprint $table) { - $table->foreignId('ai_model_id')->constrained()->onDelete('cascade'); - $table->foreignId('api_provider_id')->constrained()->onDelete('cascade'); - $table->primary(['ai_model_id', 'api_provider_id']); - }); Schema::create('password_reset_tokens', function (Blueprint $table) { $table->string('email')->primary(); @@ -133,7 +128,6 @@ return new class extends Migration Schema::dropIfExists('personal_access_tokens'); Schema::dropIfExists('failed_jobs'); Schema::dropIfExists('password_reset_tokens'); - Schema::dropIfExists('ai_model_api_provider'); Schema::dropIfExists('settings'); Schema::dropIfExists('images'); Schema::dropIfExists('styles'); diff --git a/database/seeders/AiModelApiProviderSeeder.php b/database/seeders/AiModelApiProviderSeeder.php index fc9f149..83d5c22 100644 --- a/database/seeders/AiModelApiProviderSeeder.php +++ b/database/seeders/AiModelApiProviderSeeder.php @@ -23,8 +23,9 @@ class AiModelApiProviderSeeder extends Seeder ] ]; + // Update existing AI models with their API provider IDs foreach ($data as $row) { - DB::table('ai_model_api_provider')->insert($row); + \App\Models\AiModel::where('id', $row['ai_model_id'])->update(['api_provider_id' => $row['api_provider_id']]); } } } \ No newline at end of file