From 3ec8e471bcb87b24c97afe3e0322decbf9e4346e Mon Sep 17 00:00:00 2001
From: soeren
Date: Tue, 2 Dec 2025 21:51:06 +0100
Subject: [PATCH] =?UTF-8?q?Verf=C3=BCgbarkeitstest=20f=C3=BCr=20API=20Prov?=
=?UTF-8?q?ider=20erg=C3=A4nzt.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.phpunit.result.cache | 2 +-
app/Api/Plugins/ApiPluginInterface.php | 1 +
app/Api/Plugins/ComfyUi.php | 54 +++++++
app/Api/Plugins/RunwareAi.php | 78 ++++++++++
.../Controllers/Api/AiStatusController.php | 79 ++++++++++
app/Models/AiModel.php | 1 +
app/Models/ApiProvider.php | 20 +++
database/factories/AiModelFactory.php | 29 ++++
database/factories/ApiProviderFactory.php | 24 +++
database/factories/StyleFactory.php | 30 ++++
resources/js/Components/ImageContextMenu.vue | 93 ++++++++++--
resources/js/Components/StyleSelector.vue | 39 +++--
routes/api.php | 4 +
tests/Feature/AiStatusTest.php | 137 ++++++++++++++++++
14 files changed, 565 insertions(+), 26 deletions(-)
create mode 100644 app/Http/Controllers/Api/AiStatusController.php
create mode 100644 database/factories/AiModelFactory.php
create mode 100644 database/factories/ApiProviderFactory.php
create mode 100644 database/factories/StyleFactory.php
create mode 100644 tests/Feature/AiStatusTest.php
diff --git a/.phpunit.result.cache b/.phpunit.result.cache
index 9db2e54..6ad8f07 100644
--- a/.phpunit.result.cache
+++ b/.phpunit.result.cache
@@ -1 +1 @@
-{"version":2,"defects":{"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_authenticate_using_the_login_screen":8,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_not_authenticate_with_invalid_password":8,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_logout":8,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_verification_screen_can_be_rendered":8,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_can_be_verified":8,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_is_not_verified_with_invalid_hash":8,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_confirm_password_screen_can_be_rendered":8,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_can_be_confirmed":8,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_is_not_confirmed_with_invalid_password":8,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_link_can_be_requested":8,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_screen_can_be_rendered":8,"Tests\\Feature\\Auth\\PasswordResetTest::test_password_can_be_reset_with_valid_token":8,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_password_can_be_updated":8,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_correct_password_must_be_provided_to_update_password":8,"Tests\\Feature\\Auth\\RegistrationTest::test_new_users_can_register":7,"Tests\\Feature\\ProfileTest::test_profile_page_is_displayed":8,"Tests\\Feature\\ProfileTest::test_profile_information_can_be_updated":8,"Tests\\Feature\\ProfileTest::test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged":8,"Tests\\Feature\\ProfileTest::test_user_can_delete_their_account":8,"Tests\\Feature\\ProfileTest::test_correct_password_must_be_provided_to_delete_account":8,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":7,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_index_pages_render":7,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_create_pages_render":7,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_edit_pages_render":7},"times":{"Tests\\Unit\\ExampleTest::test_that_true_is_true":0.001,"Tests\\Feature\\Auth\\AuthenticationTest::test_login_screen_can_be_rendered":2.652,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_authenticate_using_the_login_screen":0.844,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_not_authenticate_with_invalid_password":0.003,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_logout":0.003,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_verification_screen_can_be_rendered":0.004,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_can_be_verified":0.003,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_is_not_verified_with_invalid_hash":0.004,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_confirm_password_screen_can_be_rendered":0.003,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_can_be_confirmed":0.004,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_is_not_confirmed_with_invalid_password":0.011,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_link_screen_can_be_rendered":0.685,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_link_can_be_requested":0.079,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_screen_can_be_rendered":0.004,"Tests\\Feature\\Auth\\PasswordResetTest::test_password_can_be_reset_with_valid_token":0.003,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_password_can_be_updated":0.003,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_correct_password_must_be_provided_to_update_password":0.003,"Tests\\Feature\\Auth\\RegistrationTest::test_registration_screen_can_be_rendered":0.653,"Tests\\Feature\\Auth\\RegistrationTest::test_new_users_can_register":2.449,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":3.546,"Tests\\Feature\\ProfileTest::test_profile_page_is_displayed":0.003,"Tests\\Feature\\ProfileTest::test_profile_information_can_be_updated":0.008,"Tests\\Feature\\ProfileTest::test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged":0.005,"Tests\\Feature\\ProfileTest::test_user_can_delete_their_account":0.004,"Tests\\Feature\\ProfileTest::test_correct_password_must_be_provided_to_delete_account":0.004,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_index_pages_render":6.542,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_create_pages_render":3.055,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_edit_pages_render":3.132}}
\ No newline at end of file
+{"version":2,"defects":{"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_authenticate_using_the_login_screen":8,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_not_authenticate_with_invalid_password":8,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_logout":8,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_verification_screen_can_be_rendered":8,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_can_be_verified":8,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_is_not_verified_with_invalid_hash":8,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_confirm_password_screen_can_be_rendered":8,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_can_be_confirmed":8,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_is_not_confirmed_with_invalid_password":8,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_link_can_be_requested":8,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_screen_can_be_rendered":8,"Tests\\Feature\\Auth\\PasswordResetTest::test_password_can_be_reset_with_valid_token":8,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_password_can_be_updated":8,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_correct_password_must_be_provided_to_update_password":8,"Tests\\Feature\\Auth\\RegistrationTest::test_new_users_can_register":7,"Tests\\Feature\\ProfileTest::test_profile_page_is_displayed":8,"Tests\\Feature\\ProfileTest::test_profile_information_can_be_updated":8,"Tests\\Feature\\ProfileTest::test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged":8,"Tests\\Feature\\ProfileTest::test_user_can_delete_their_account":8,"Tests\\Feature\\ProfileTest::test_correct_password_must_be_provided_to_delete_account":8,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":7,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_index_pages_render":7,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_create_pages_render":7,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_edit_pages_render":7,"Tests\\Feature\\AiStatusTest::test_ai_status_endpoint_returns_correct_structure":8,"Tests\\Feature\\AiStatusTest::test_ai_status_update_disables_unavailable_providers":7,"Tests\\Feature\\AiStatusTest::test_comfyui_check_availability_method":8,"Tests\\Feature\\AiStatusTest::test_runwareai_check_availability_method":8},"times":{"Tests\\Unit\\ExampleTest::test_that_true_is_true":0.001,"Tests\\Feature\\Auth\\AuthenticationTest::test_login_screen_can_be_rendered":2.652,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_authenticate_using_the_login_screen":0.844,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_not_authenticate_with_invalid_password":0.003,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_logout":0.003,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_verification_screen_can_be_rendered":0.004,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_can_be_verified":0.003,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_is_not_verified_with_invalid_hash":0.004,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_confirm_password_screen_can_be_rendered":0.003,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_can_be_confirmed":0.004,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_is_not_confirmed_with_invalid_password":0.011,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_link_screen_can_be_rendered":0.685,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_link_can_be_requested":0.079,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_screen_can_be_rendered":0.004,"Tests\\Feature\\Auth\\PasswordResetTest::test_password_can_be_reset_with_valid_token":0.003,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_password_can_be_updated":0.003,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_correct_password_must_be_provided_to_update_password":0.003,"Tests\\Feature\\Auth\\RegistrationTest::test_registration_screen_can_be_rendered":0.653,"Tests\\Feature\\Auth\\RegistrationTest::test_new_users_can_register":2.449,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":3.546,"Tests\\Feature\\ProfileTest::test_profile_page_is_displayed":0.003,"Tests\\Feature\\ProfileTest::test_profile_information_can_be_updated":0.008,"Tests\\Feature\\ProfileTest::test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged":0.005,"Tests\\Feature\\ProfileTest::test_user_can_delete_their_account":0.004,"Tests\\Feature\\ProfileTest::test_correct_password_must_be_provided_to_delete_account":0.004,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_index_pages_render":6.542,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_create_pages_render":3.055,"Tests\\Feature\\Filament\\ResourcePagesTest::test_admin_resource_edit_pages_render":3.132,"Tests\\Feature\\AiStatusTest::test_ai_status_endpoint_returns_correct_structure":0.637,"Tests\\Feature\\AiStatusTest::test_ai_status_update_disables_unavailable_providers":1.569,"Tests\\Feature\\AiStatusTest::test_comfyui_check_availability_method":0.228,"Tests\\Feature\\AiStatusTest::test_runwareai_check_availability_method":0.233}}
\ No newline at end of file
diff --git a/app/Api/Plugins/ApiPluginInterface.php b/app/Api/Plugins/ApiPluginInterface.php
index 8bc8c42..bc734b1 100644
--- a/app/Api/Plugins/ApiPluginInterface.php
+++ b/app/Api/Plugins/ApiPluginInterface.php
@@ -15,4 +15,5 @@ interface ApiPluginInterface
public function getStyledImage(string $promptId): string;
public function testConnection(array $data): bool;
public function searchModels(string $searchTerm): array;
+ public function checkAvailability(): array;
}
\ No newline at end of file
diff --git a/app/Api/Plugins/ComfyUi.php b/app/Api/Plugins/ComfyUi.php
index aebdc78..30b6b9a 100644
--- a/app/Api/Plugins/ComfyUi.php
+++ b/app/Api/Plugins/ComfyUi.php
@@ -255,6 +255,60 @@ class ComfyUi implements ApiPluginInterface
}
}
+ public function checkAvailability(): array
+ {
+ $this->logInfo('Checking ComfyUI availability.');
+
+ if (!$this->apiProvider->enabled) {
+ $this->logDebug('ComfyUI provider is disabled.');
+ return [
+ 'available' => false,
+ 'reason' => 'Provider is disabled',
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ }
+
+ if (empty($this->apiProvider->api_url)) {
+ $this->logDebug('ComfyUI API URL is not configured.');
+ return [
+ 'available' => false,
+ 'reason' => 'API URL not configured',
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ }
+
+ try {
+ $response = Http::timeout(5)->get(rtrim($this->apiProvider->api_url, '/') . '/queue');
+ if ($response->successful()) {
+ $this->logInfo('ComfyUI is available.');
+ return [
+ 'available' => true,
+ 'reason' => 'Connection successful',
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ } else {
+ $this->logError('ComfyUI connection failed.', ['status' => $response->status()]);
+ return [
+ 'available' => false,
+ 'reason' => 'Connection failed: ' . $response->status(),
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ }
+ } catch (\Exception $e) {
+ $this->logError('ComfyUI availability check failed.', ['error' => $e->getMessage()]);
+ return [
+ 'available' => false,
+ 'reason' => 'Connection error: ' . $e->getMessage(),
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ }
+ }
+
public function searchModels(string $searchTerm): array
{
$this->logInfo('ComfyUI does not support model search. Returning empty list.', ['searchTerm' => $searchTerm]);
diff --git a/app/Api/Plugins/RunwareAi.php b/app/Api/Plugins/RunwareAi.php
index e15f831..cc32c97 100644
--- a/app/Api/Plugins/RunwareAi.php
+++ b/app/Api/Plugins/RunwareAi.php
@@ -139,6 +139,84 @@ class RunwareAi implements ApiPluginInterface
}
}
+ public function checkAvailability(): array
+ {
+ $this->logInfo('Checking RunwareAI availability.');
+
+ if (!$this->apiProvider->enabled) {
+ $this->logDebug('RunwareAI provider is disabled.');
+ return [
+ 'available' => false,
+ 'reason' => 'Provider is disabled',
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ }
+
+ if (empty($this->apiProvider->api_url)) {
+ $this->logDebug('RunwareAI API URL is not configured.');
+ return [
+ 'available' => false,
+ 'reason' => 'API URL not configured',
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ }
+
+ if (empty($this->apiProvider->token)) {
+ $this->logDebug('RunwareAI API token is not configured.');
+ return [
+ 'available' => false,
+ 'reason' => 'API token not configured',
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ }
+
+ try {
+ $response = Http::withHeaders([
+ 'Content-Type' => 'application/json',
+ 'Accept' => 'application/json',
+ ])->timeout(5)->post(rtrim($this->apiProvider->api_url, '/'), [
+ 'taskType' => 'authentication',
+ 'apiKey' => $this->apiProvider->token,
+ 'taskUUID' => (string) Str::uuid(),
+ ]);
+
+ $responseData = $response->json();
+
+ if ($response->successful() && isset($responseData['data']) && !isset($responseData['error'])) {
+ $this->logInfo('RunwareAI is available.');
+ return [
+ 'available' => true,
+ 'reason' => 'Connection successful',
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ } else {
+ $errorMessage = $responseData['error'] ?? 'Unknown error';
+ $this->logError('RunwareAI connection failed.', [
+ 'status' => $response->status(),
+ 'error_message' => $errorMessage
+ ]);
+ return [
+ 'available' => false,
+ 'reason' => 'Connection failed: ' . $errorMessage,
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ }
+ } catch (\Exception $e) {
+ $this->logError('RunwareAI availability check failed.', ['error' => $e->getMessage()]);
+ return [
+ 'available' => false,
+ 'reason' => 'Connection error: ' . $e->getMessage(),
+ 'provider_id' => $this->apiProvider->id,
+ 'provider_name' => $this->apiProvider->name
+ ];
+ }
+ }
+
public function searchModels(string $searchTerm): array
{
diff --git a/app/Http/Controllers/Api/AiStatusController.php b/app/Http/Controllers/Api/AiStatusController.php
new file mode 100644
index 0000000..11dad1a
--- /dev/null
+++ b/app/Http/Controllers/Api/AiStatusController.php
@@ -0,0 +1,79 @@
+get();
+ $results = [];
+
+ foreach ($providers as $provider) {
+ try {
+ $plugin = PluginLoader::getPlugin($provider->plugin, $provider);
+ $status = $plugin->checkAvailability();
+ $results[] = $status;
+ } catch (\Exception $e) {
+ $results[] = [
+ 'available' => false,
+ 'reason' => 'Plugin error: ' . $e->getMessage(),
+ 'provider_id' => $provider->id,
+ 'provider_name' => $provider->name
+ ];
+ }
+ }
+
+ return response()->json($results);
+ }
+
+ public function checkAndUpdateStatus(Request $request)
+ {
+ $providers = ApiProvider::all();
+ $anyAvailable = false;
+
+ foreach ($providers as $provider) {
+ try {
+ $plugin = PluginLoader::getPlugin($provider->plugin, $provider);
+ $status = $plugin->checkAvailability();
+
+ if (!$status['available']) {
+ // Deaktiviere den Provider, wenn nicht verfügbar
+ $provider->enabled = false;
+ $provider->save();
+
+ // Deaktiviere alle zugehörigen Modelle
+ foreach ($provider->aiModels as $model) {
+ $model->enabled = false;
+ $model->save();
+
+ // Deaktiviere alle zugehörigen Styles
+ foreach ($model->styles as $style) {
+ $style->enabled = false;
+ $style->save();
+ }
+ }
+ } else {
+ $anyAvailable = true;
+ // Stelle sicher, dass der Provider aktiviert ist, wenn er verfügbar ist
+ $provider->enabled = true;
+ $provider->save();
+ }
+ } catch (\Exception $e) {
+ $provider->enabled = false;
+ $provider->save();
+ }
+ }
+
+ return response()->json([
+ 'success' => true,
+ 'any_available' => $anyAvailable,
+ 'message' => 'AI status check and update completed'
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/app/Models/AiModel.php b/app/Models/AiModel.php
index 20c5dc4..6ed85f3 100644
--- a/app/Models/AiModel.php
+++ b/app/Models/AiModel.php
@@ -19,6 +19,7 @@ class AiModel extends Model
protected $casts = [
'parameters' => 'array',
+ 'enabled' => 'boolean',
];
public function primaryApiProvider()
diff --git a/app/Models/ApiProvider.php b/app/Models/ApiProvider.php
index 66b3d01..acf7afa 100644
--- a/app/Models/ApiProvider.php
+++ b/app/Models/ApiProvider.php
@@ -23,6 +23,26 @@ class ApiProvider extends Model
'enabled' => 'boolean',
];
+ public function disableWithDependencies()
+ {
+ $this->enabled = false;
+ $this->save();
+
+ // Deaktiviere alle zugehörigen Modelle
+ foreach ($this->aiModels as $model) {
+ $model->enabled = false;
+ $model->save();
+
+ // Deaktiviere alle zugehörigen Styles
+ foreach ($model->styles as $style) {
+ $style->enabled = false;
+ $style->save();
+ }
+ }
+
+ return true;
+ }
+
public function styles()
{
return $this->hasMany(Style::class);
diff --git a/database/factories/AiModelFactory.php b/database/factories/AiModelFactory.php
new file mode 100644
index 0000000..2354314
--- /dev/null
+++ b/database/factories/AiModelFactory.php
@@ -0,0 +1,29 @@
+ $this->faker->word() . ' Model',
+ 'model_id' => $this->faker->uuid(),
+ 'model_type' => $this->faker->randomElement(['text-to-image', 'image-to-image', 'inpainting']),
+ 'parameters' => json_encode([
+ 'steps' => 30,
+ 'cfg_scale' => 7.5,
+ 'sampler' => 'Euler a',
+ 'width' => 512,
+ 'height' => 512
+ ]),
+ 'api_provider_id' => ApiProvider::factory(),
+ ];
+ }
+}
\ No newline at end of file
diff --git a/database/factories/ApiProviderFactory.php b/database/factories/ApiProviderFactory.php
new file mode 100644
index 0000000..0cfa259
--- /dev/null
+++ b/database/factories/ApiProviderFactory.php
@@ -0,0 +1,24 @@
+ $this->faker->company(),
+ 'api_url' => $this->faker->url(),
+ 'username' => $this->faker->userName(),
+ 'password' => $this->faker->password(),
+ 'token' => $this->faker->sha256(),
+ 'plugin' => $this->faker->randomElement(['comfyui', 'runwareai']),
+ 'enabled' => $this->faker->boolean(),
+ ];
+ }
+}
\ No newline at end of file
diff --git a/database/factories/StyleFactory.php b/database/factories/StyleFactory.php
new file mode 100644
index 0000000..b9fa51d
--- /dev/null
+++ b/database/factories/StyleFactory.php
@@ -0,0 +1,30 @@
+ $this->faker->words(3, true),
+ 'prompt' => $this->faker->sentence(),
+ 'description' => $this->faker->paragraph(),
+ 'preview_image' => 'styles/preview.jpg',
+ 'parameters' => json_encode([
+ 'positive' => $this->faker->sentence(),
+ 'negative' => $this->faker->sentence(),
+ 'steps' => 30,
+ 'cfg_scale' => 7.5
+ ]),
+ 'ai_model_id' => AiModel::factory(),
+ 'enabled' => $this->faker->boolean(80),
+ ];
+ }
+}
\ No newline at end of file
diff --git a/resources/js/Components/ImageContextMenu.vue b/resources/js/Components/ImageContextMenu.vue
index c53f187..f98cf0d 100644
--- a/resources/js/Components/ImageContextMenu.vue
+++ b/resources/js/Components/ImageContextMenu.vue
@@ -33,25 +33,66 @@
{{ image?.path }}
-
+
+
+
+
+
+ AI {{ aiAvailable ? 'verfügbar' : 'nicht verfügbar' }}
+
+
+
+
+
+
+ API-Provider Status:
+
+ {{ aiAvailable ? 'Online' : 'Offline' }}
+
+
+
+ Einige Funktionen sind derzeit nicht verfügbar
+
+
+
+
+
+
+