tabelle ai_model_api_provider entfernt

This commit is contained in:
2025-08-29 14:09:01 +02:00
parent 9b1f6a479f
commit d271f256b7
11 changed files with 47 additions and 103 deletions

2
PRP.md
View File

@@ -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`**

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -57,6 +57,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
{
$this->logDebug('Getting status for image.', ['image_uuid' => $imageUUID]);
@@ -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) {

View File

@@ -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([
//

View File

@@ -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();
}
}
}

View File

@@ -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);
});
})

View File

@@ -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');
}
}

View File

@@ -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');
}
}

View File

@@ -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');

View File

@@ -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']]);
}
}
}