tabelle ai_model_api_provider entfernt
This commit is contained in:
2
PRP.md
2
PRP.md
@@ -258,8 +258,6 @@ Key tables and their relevant columns:
|
|||||||
- `created_at`: `timestamp null`
|
- `created_at`: `timestamp null`
|
||||||
- `updated_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`)
|
- `api_provider_id`: `bigint unsigned` (FK to `api_providers.id`)
|
||||||
|
|
||||||
- **`settings`**
|
- **`settings`**
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ interface ApiPluginInterface
|
|||||||
public function getStatus(string $imageUUID): array;
|
public function getStatus(string $imageUUID): array;
|
||||||
public function getProgress(string $imageUUID): array;
|
public function getProgress(string $imageUUID): array;
|
||||||
public function processImageStyleChange(\App\Models\Image $image, \App\Models\Style $style): 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 testConnection(array $data): bool;
|
||||||
public function searchModels(string $searchTerm): array;
|
public function searchModels(string $searchTerm): array;
|
||||||
}
|
}
|
||||||
@@ -260,4 +260,9 @@ class ComfyUi implements ApiPluginInterface
|
|||||||
$this->logInfo('ComfyUI does not support model search. Returning empty list.', ['searchTerm' => $searchTerm]);
|
$this->logInfo('ComfyUI does not support model search. Returning empty list.', ['searchTerm' => $searchTerm]);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getStyledImage(string $promptId): string
|
||||||
|
{
|
||||||
|
return $this->waitForResult($promptId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,11 @@ class RunwareAi implements ApiPluginInterface
|
|||||||
}
|
}
|
||||||
return $result;
|
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
|
public function getStatus(string $imageUUID): array
|
||||||
{
|
{
|
||||||
@@ -248,7 +253,7 @@ class RunwareAi implements ApiPluginInterface
|
|||||||
'positivePrompt' => $style->prompt,
|
'positivePrompt' => $style->prompt,
|
||||||
'seedImage' => $seedImageUUID,
|
'seedImage' => $seedImageUUID,
|
||||||
'outputType' => 'base64Data',
|
'outputType' => 'base64Data',
|
||||||
'model' => $style->aiModel->model_id,
|
'model' => $style->aiModel->model_id
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($mergedParams as $key => $value) {
|
foreach ($mergedParams as $key => $value) {
|
||||||
|
|||||||
@@ -32,10 +32,9 @@ class AiModelResource extends Resource
|
|||||||
->schema([
|
->schema([
|
||||||
Forms\Components\Section::make()
|
Forms\Components\Section::make()
|
||||||
->schema([
|
->schema([
|
||||||
Select::make('apiProviders')
|
Select::make('api_provider_id')
|
||||||
->label(__('filament.resource.ai_model.form.api_providers'))
|
->label(__('filament.resource.ai_model.form.api_provider'))
|
||||||
->relationship('apiProviders', 'name')
|
->relationship('primaryApiProvider', 'name')
|
||||||
->multiple()
|
|
||||||
->live()
|
->live()
|
||||||
->afterStateUpdated(function (callable $set) {
|
->afterStateUpdated(function (callable $set) {
|
||||||
$set('model_search_result', null);
|
$set('model_search_result', null);
|
||||||
@@ -44,24 +43,21 @@ class AiModelResource extends Resource
|
|||||||
->label(__('filament.resource.ai_model.form.search_model'))
|
->label(__('filament.resource.ai_model.form.search_model'))
|
||||||
->searchable()
|
->searchable()
|
||||||
->live()
|
->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) {
|
->getSearchResultsUsing(function (string $search, callable $get) {
|
||||||
$apiProviderIds = $get('apiProviders');
|
$apiProviderId = $get('api_provider_id');
|
||||||
if (empty($apiProviderIds)) {
|
if (!$apiProviderId) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try each API provider until we find one that works
|
$pluginInstance = static::getPluginInstance($apiProviderId);
|
||||||
foreach ($apiProviderIds as $apiProviderId) {
|
if ($pluginInstance && method_exists($pluginInstance, 'searchModels')) {
|
||||||
$pluginInstance = static::getPluginInstance($apiProviderId);
|
$models = $pluginInstance->searchModels($search);
|
||||||
if ($pluginInstance && method_exists($pluginInstance, 'searchModels')) {
|
$options = [];
|
||||||
$models = $pluginInstance->searchModels($search);
|
foreach ($models as $model) {
|
||||||
$options = [];
|
$options[json_encode(['name' => $model['name'], 'id' => $model['id'], 'type' => $model['type'] ?? null, 'api_provider_id' => $apiProviderId])] = $model['name'] . ' (' . $model['id'] . ')';
|
||||||
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 $options;
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
})
|
})
|
||||||
@@ -176,7 +172,7 @@ class AiModelResource extends Resource
|
|||||||
Tables\Columns\IconColumn::make('enabled')
|
Tables\Columns\IconColumn::make('enabled')
|
||||||
->label(__('filament.resource.ai_model.table.enabled'))
|
->label(__('filament.resource.ai_model.table.enabled'))
|
||||||
->boolean(),
|
->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([
|
->filters([
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -138,23 +138,19 @@ class ImageController extends Controller
|
|||||||
|
|
||||||
if ($request->style_id) {
|
if ($request->style_id) {
|
||||||
$style = Style::with(['aiModel' => function ($query) {
|
$style = Style::with(['aiModel' => function ($query) {
|
||||||
$query->where('enabled', true)->with(['primaryApiProvider', 'apiProviders' => function ($query) {
|
$query->where('enabled', true)->with('primaryApiProvider');
|
||||||
$query->where('enabled', true);
|
|
||||||
}]);
|
|
||||||
}])->find($request->style_id);
|
}])->find($request->style_id);
|
||||||
} else {
|
} else {
|
||||||
// Attempt to get default style from settings
|
// Attempt to get default style from settings
|
||||||
$defaultStyleSetting = \App\Models\Setting::where('key', 'default_style_id')->first();
|
$defaultStyleSetting = \App\Models\Setting::where('key', 'default_style_id')->first();
|
||||||
if ($defaultStyleSetting && $defaultStyleSetting->value) {
|
if ($defaultStyleSetting && $defaultStyleSetting->value) {
|
||||||
$style = Style::with(['aiModel' => function ($query) {
|
$style = Style::with(['aiModel' => function ($query) {
|
||||||
$query->where('enabled', true)->with(['primaryApiProvider', 'apiProviders' => function ($query) {
|
$query->where('enabled', true)->with('primaryApiProvider');
|
||||||
$query->where('enabled', true);
|
|
||||||
}]);
|
|
||||||
}])->find($defaultStyleSetting->value);
|
}])->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', [
|
\Illuminate\Support\Facades\Log::warning('Style or provider not found', [
|
||||||
'style' => $style ? $style->toArray() : null,
|
'style' => $style ? $style->toArray() : null,
|
||||||
'ai_model' => $style && $style->aiModel ? $style->aiModel->toArray() : null
|
'ai_model' => $style && $style->aiModel ? $style->aiModel->toArray() : null
|
||||||
@@ -163,16 +159,8 @@ class ImageController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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;
|
$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) {
|
if (!$apiProvider) {
|
||||||
\Illuminate\Support\Facades\Log::error('No API provider found for style', [
|
\Illuminate\Support\Facades\Log::error('No API provider found for style', [
|
||||||
'style_id' => $style->id,
|
'style_id' => $style->id,
|
||||||
@@ -276,9 +264,7 @@ class ImageController extends Controller
|
|||||||
try {
|
try {
|
||||||
// Find the image associated with the prompt_id, eagerly loading relationships
|
// Find the image associated with the prompt_id, eagerly loading relationships
|
||||||
$image = Image::with(['style.aiModel' => function ($query) {
|
$image = Image::with(['style.aiModel' => function ($query) {
|
||||||
$query->with(['primaryApiProvider', 'apiProviders' => function ($query) {
|
$query->with('primaryApiProvider');
|
||||||
$query->where('enabled', true);
|
|
||||||
}]);
|
|
||||||
}])->where('comfyui_prompt_id', $promptId)->first();
|
}])->where('comfyui_prompt_id', $promptId)->first();
|
||||||
|
|
||||||
if (!$image) {
|
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]);
|
Log::info('fetchStyledImage: AI Model found.', ['ai_model_id' => $style->aiModel->id, 'ai_model_name' => $style->aiModel->name]);
|
||||||
|
|
||||||
if ($style->aiModel->apiProviders->isEmpty()) {
|
// Use the primary API provider for this AI model
|
||||||
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
|
|
||||||
$apiProvider = $style->aiModel->primaryApiProvider;
|
$apiProvider = $style->aiModel->primaryApiProvider;
|
||||||
if (!$apiProvider) {
|
if (!$apiProvider) {
|
||||||
// Fallback to the first enabled API provider from the many-to-many relationship
|
Log::warning('fetchStyledImage: No API Provider found for AI Model.', ['ai_model_id' => $style->aiModel->id]);
|
||||||
$apiProvider = $style->aiModel->apiProviders->where('enabled', true)->first();
|
return response()->json(['error' => __('api.style_or_provider_not_found')], 404);
|
||||||
}
|
|
||||||
if (!$apiProvider) {
|
|
||||||
// If no enabled provider found, try any provider
|
|
||||||
$apiProvider = $style->aiModel->apiProviders->first();
|
|
||||||
}
|
}
|
||||||
Log::info('fetchStyledImage: API Provider found.', ['api_provider_id' => $apiProvider->id, 'api_provider_name' => $apiProvider->name]);
|
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]);
|
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)
|
// Use the plugin to get the final image data (e.g., from ComfyUI's history/view)
|
||||||
$plugin = PluginLoader::getPlugin($apiProvider->plugin, $apiProvider);
|
$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)) {
|
if (empty($base64Image)) {
|
||||||
Log::error('Received empty base64 image from plugin.', ['prompt_id' => $promptId]);
|
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 style_id is provided, get the API provider for that style
|
||||||
if ($styleId) {
|
if ($styleId) {
|
||||||
$style = Style::with(['aiModel' => function ($query) {
|
$style = Style::with(['aiModel' => function ($query) {
|
||||||
$query->where('enabled', true)->with(['primaryApiProvider', 'apiProviders' => function ($query) {
|
$query->where('enabled', true)->with('primaryApiProvider');
|
||||||
$query->where('enabled', true);
|
|
||||||
}]);
|
|
||||||
}])->find($styleId);
|
}])->find($styleId);
|
||||||
|
|
||||||
if ($style && $style->aiModel) {
|
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;
|
$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
|
// If image_uuid is provided, get the API provider for that image's style
|
||||||
elseif ($imageUuid) {
|
elseif ($imageUuid) {
|
||||||
$image = Image::with(['style.aiModel' => function ($query) {
|
$image = Image::with(['style.aiModel' => function ($query) {
|
||||||
$query->with(['primaryApiProvider', 'apiProviders' => function ($query) {
|
$query->with('primaryApiProvider');
|
||||||
$query->where('enabled', true);
|
|
||||||
}]);
|
|
||||||
}])->where('uuid', $imageUuid)->first();
|
}])->where('uuid', $imageUuid)->first();
|
||||||
|
|
||||||
if ($image && $image->style && $image->style->aiModel) {
|
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;
|
$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
|
// 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();
|
$defaultStyleSetting = \App\Models\Setting::where('key', 'default_style_id')->first();
|
||||||
if ($defaultStyleSetting && $defaultStyleSetting->value) {
|
if ($defaultStyleSetting && $defaultStyleSetting->value) {
|
||||||
$style = Style::with(['aiModel' => function ($query) {
|
$style = Style::with(['aiModel' => function ($query) {
|
||||||
$query->where('enabled', true)->with(['primaryApiProvider', 'apiProviders' => function ($query) {
|
$query->where('enabled', true)->with('primaryApiProvider');
|
||||||
$query->where('enabled', true);
|
|
||||||
}]);
|
|
||||||
}])->find($defaultStyleSetting->value);
|
}])->find($defaultStyleSetting->value);
|
||||||
|
|
||||||
if ($style && $style->aiModel) {
|
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;
|
$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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ class StyleController extends Controller
|
|||||||
{
|
{
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$styles = Style::with(['aiModel.apiProviders'])
|
$styles = Style::with(['aiModel.primaryApiProvider'])
|
||||||
->where('enabled', true)
|
->where('enabled', true)
|
||||||
->whereHas('aiModel', function ($query) {
|
->whereHas('aiModel', function ($query) {
|
||||||
$query->where('enabled', true);
|
$query->where('enabled', true);
|
||||||
$query->whereHas('apiProviders', function ($query) {
|
$query->whereHas('primaryApiProvider', function ($query) {
|
||||||
$query->where('enabled', true);
|
$query->where('enabled', true);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class AiModel extends Model
|
|||||||
'model_id',
|
'model_id',
|
||||||
'model_type',
|
'model_type',
|
||||||
'parameters',
|
'parameters',
|
||||||
|
'api_provider_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
@@ -24,9 +25,4 @@ class AiModel extends Model
|
|||||||
{
|
{
|
||||||
return $this->belongsTo(ApiProvider::class, 'api_provider_id');
|
return $this->belongsTo(ApiProvider::class, 'api_provider_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function apiProviders()
|
|
||||||
{
|
|
||||||
return $this->belongsToMany(ApiProvider::class, 'ai_model_api_provider');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,6 @@ class ApiProvider extends Model
|
|||||||
|
|
||||||
public function aiModels()
|
public function aiModels()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(AiModel::class, 'ai_model_api_provider');
|
return $this->hasMany(AiModel::class, 'api_provider_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,11 +91,6 @@ return new class extends Migration
|
|||||||
$table->timestamps();
|
$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) {
|
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||||
$table->string('email')->primary();
|
$table->string('email')->primary();
|
||||||
@@ -133,7 +128,6 @@ return new class extends Migration
|
|||||||
Schema::dropIfExists('personal_access_tokens');
|
Schema::dropIfExists('personal_access_tokens');
|
||||||
Schema::dropIfExists('failed_jobs');
|
Schema::dropIfExists('failed_jobs');
|
||||||
Schema::dropIfExists('password_reset_tokens');
|
Schema::dropIfExists('password_reset_tokens');
|
||||||
Schema::dropIfExists('ai_model_api_provider');
|
|
||||||
Schema::dropIfExists('settings');
|
Schema::dropIfExists('settings');
|
||||||
Schema::dropIfExists('images');
|
Schema::dropIfExists('images');
|
||||||
Schema::dropIfExists('styles');
|
Schema::dropIfExists('styles');
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ class AiModelApiProviderSeeder extends Seeder
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Update existing AI models with their API provider IDs
|
||||||
foreach ($data as $row) {
|
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']]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user