parameter für Modelle eingeführt, Beschreibung aktualisiert

This commit is contained in:
2025-08-06 09:08:07 +02:00
parent 4a45738b9b
commit 57f3dbc402
16 changed files with 581 additions and 34 deletions

406
PRP.md Normal file
View File

@@ -0,0 +1,406 @@
# Project Reconstruction Plan (PRP) for AI StyleGallery
This document outlines the architecture, functionality, and implementation details of the "AI StyleGallery" web application. It is intended to serve as a comprehensive guide for another AI agent or LLM to understand and potentially reconstruct a similar system.
## 1. Application Overview
**Primary Goal:** AI StyleGallery is a web application designed to allow users to transform their uploaded images by applying various AI-generated artistic styles. Users can manage their image gallery, apply styles via external AI services, and save or discard the results.
**Core Functionality:**
- **Image Upload:** Users can upload their own images to the gallery.
- **Style Application:** Users can select an image and choose from a predefined set of AI styles to apply.
- **AI Processing Integration:** The application interacts with external AI web services (e.g., ComfyUI, RunwareAI) to perform image transformations.
- **Gallery Management:** Users can view their original and styled images, and decide to keep (make permanent) or discard (delete) styled images.
- **Admin Panel:** An administrative interface for managing AI models, API providers, styles, users, and roles.
## 2. Core Technologies & Stack
* **Languages:** PHP 8.1, JavaScript
* **Frameworks & Runtimes:** Laravel 12.21.0, Vue.js 3.5.18, Inertia.js 1.3.0, Livewire 3.6.4, Vite 5.4.19
* **Databases:** MySQL (default), with configurations for PostgreSQL, SQLite, and SQL Server. Redis is used for caching.
* **Key PHP Libraries/Dependencies:**
* Filament 3.3.34 (for the admin panel)
* Guzzle 7.9.3 (for HTTP requests)
* Laravel Sanctum 4.2.0 (for API authentication)
* Laravel Breeze 2.3.8 (authentication scaffolding)
* Laravel Pint 1.24.0 (code formatter)
* Laravel Prompts 0.3.6 (CLI prompts)
* Laravel Sail 1.44.0 (Docker development environment)
* Laravel Serializable Closure 2.0.4
* Laravel Tinker 2.10.1
* nesbot/carbon 3.10.2 (date/time library)
* predis/predis 3.1.0 (Redis client)
* phpunit/php-code-coverage 12.3.2
* phpunit/php-file-iterator 6.0.0
* phpunit/php-invoker 6.0.0
* phpunit/php-text-template 5.0.0
* phpunit/php-timer 8.0.0
* phpunit/phpunit 12.3.0
* ramsey/uuid 4.9.0 (UUID generation)
* spatie/laravel-package-tools 1.92.7
* tightenco/ziggy 2.5.3 (Laravel routes in JS)
* symfony/clock 7.3.0
* symfony/console 7.3.2
* symfony/css-selector 7.3.0
* symfony/deprecation-contracts 3.6.0
* symfony/error-handler 7.3.2
* symfony/event-dispatcher 7.3.0
* symfony/event-dispatcher-contracts 3.6.0
* symfony/finder 7.3.2
* symfony/html-sanitizer 7.3.2
* symfony/http-foundation 7.3.2
* symfony/http-kernel 7.3.2
* symfony/mailer 7.3.2
* symfony/mime 7.3.2
* symfony/polyfill-ctype 1.32.0
* symfony/polyfill-intl-grapheme 1.32.0
* symfony/polyfill-intl-idn 1.32.0
* symfony/polyfill-intl-normalizer 1.32.0
* symfony/polyfill-mbstring 1.32.0
* symfony/polyfill-php80 1.32.0
* symfony/polyfill-php83 1.32.0
* symfony/polyfill-uuid 1.32.0
* symfony/process 7.3.0
* symfony/routing 7.3.2
* symfony/service-contracts 3.6.0
* symfony/string 7.3.2
* symfony/translation 7.3.2
* symfony/translation-contracts 3.6.0
* symfony/uid 7.3.1
* symfony/var-dumper 7.3.2
* symfony/yaml 7.3.2
* **Key JavaScript Libraries/Dependencies:**
* axios 1.11.0 (for frontend HTTP requests)
* tailwindcss 3.4.17 (for styling)
* @inertiajs/vue3 1.3.0
* @vitejs/plugin-vue 5.2.4
* @tailwindcss/forms 0.5.10
* autoprefixer 10.4.21
* postcss 8.5.6
* laravel-echo 2.1.7 (WebSocket client)
* pusher-js 8.4.0 (Pusher client for WebSockets)
* @fortawesome/fontawesome-svg-core 7.0.0
* @fortawesome/free-solid-svg-icons 7.0.0
* @fortawesome/vue-fontawesome 3.1.1
* vanilla-lazyload 19.1.3 (lazy loading images)
* **Package Manager(s):** Composer for PHP, npm for JavaScript.
## 2. UI Structure (Frontend / Backend)
### 2.1. Frontend (Vue.js 3 with Inertia.js)
The frontend is a Single Page Application (SPA) built with Vue.js and Inertia.js, providing a dynamic user experience.
- **Gallery View (`resources/js/Pages/Home.vue`):**
- Displays a grid of images (both original and styled).
- Images are fetched from `/api/images`.
- Includes pagination for large galleries.
- Periodically polls `/api/images` to refresh the gallery and show newly styled images.
- **Image Context Menu (`resources/js/Components/ImageContextMenu.vue`):**
- Appears when a user taps on an image in the gallery.
- Provides options: "Drucken" (Print), "Stil ändern" (Change Style), "Schließen" (Close).
- Dynamically adjusts its position based on the tap location.
- Layout: Image preview (60% width) and options list (40% width).
- **Style Selector (`resources/js/Components/StyleSelector.vue`):**
- Displayed when "Stil ändern" is selected from the context menu.
- Fetches and lists available AI styles from `/api/styles`.
- Allows users to select a style.
- Lazy loads style preview images using `IntersectionObserver` for performance.
- Includes a "back" arrow to return to the main context menu.
- **Styled Image Display (Implicit):**
- Styled images appear in the main gallery after processing.
- **User Authentication/Profile:**
- Login/Logout functionality (handled by Laravel Breeze/Fortify and Inertia.js).
- User profile management (via Laravel's built-in features and Filament admin panel).
### 2.2. Backend (Laravel 12 with Filament Admin Panel)
The backend is a monolithic Laravel application, with Filament providing a powerful administrative interface.
- **Filament Admin Panel:**
- Accessible via `/admin`.
- Provides CRUD (Create, Read, Update, Delete) operations for the following resources:
- **AI Models (`app/Filament/Resources/AiModelResource.php`):** Manage AI models, their IDs, types, associated API providers, and specific parameters (JSON).
- **API Providers (`app/Filament/Resources/ApiProviderResource.php`):** Configure connections to external AI services (API URL, authentication tokens/credentials, plugin type).
- **Styles (`app/Filament/Resources/StyleResource.php`):** Define AI styles, including their title, prompt, description, preview image, parameters (JSON), and associated AI model.
- **Images (via direct database interaction and synchronization):** While there's an `ImageResource`, image management is largely automated through synchronization.
- **Users (`app/Filament/Resources/UserResource.php`):** Manage user accounts and assign roles.
- **Roles (`app/Filament/Resources/RoleResource.php`):** Define user roles and permissions.
- **Settings (`app/Filament/Resources/SettingResource.php`):** Manage application-wide settings.
## 3. Resources/Entities (Models)
The application's core data structures are represented by Eloquent models:
- **`App\Models\User`**: Represents a user account.
- `id` (PK)
- `name`
- `email`
- `password`
- `role_id` (FK to `roles` table)
- `two_factor_secret`, `two_factor_recovery_codes`, `two_factor_confirmed_at` (for 2FA)
- `settings` (JSON)
- **`App\Models\Image`**: Stores metadata for both original and styled images.
- `id` (PK)
- `path` (string, file path relative to storage disk)
- `uuid` (string, unique identifier for tracking)
- `original_image_id` (FK to `images` table, for styled images)
- `style_id` (FK to `styles` table, for styled images)
- `is_temp` (boolean, true for temporary styled images)
- `is_public` (boolean, true for publicly visible images)
- `comfyui_prompt_id` (string, for tracking ComfyUI jobs)
- `created_at`, `updated_at`
- **`App\Models\Style`**: Defines an AI style.
- `id` (PK)
- `title` (string)
- `prompt` (text, the base prompt for the AI model)
- `description` (text)
- `preview_image` (string, path to style preview image)
- `parameters` (JSON, additional parameters for the AI plugin, cast to array)
- `ai_model_id` (FK to `ai_models` table)
- `enabled` (boolean)
- `created_at`, `updated_at`
- **`App\Models\AiModel`**: Represents a specific AI model (e.g., Stable Diffusion v1.5).
- `id` (PK)
- `name` (string)
- `model_id` (string, identifier used by the AI service)
- `model_type` (string, e.g., "Stable Diffusion")
- `enabled` (boolean)
- `parameters` (JSON, additional parameters for the AI plugin, cast to array)
- `created_at`, `updated_at`
- **`App\Models\ApiProvider`**: Configures connection details for an external AI service.
- `id` (PK)
- `name` (string, e.g., "ComfyUI API")
- `api_url` (string, base URL of the AI service)
- `username` (string, nullable)
- `password` (string, nullable)
- `token` (string, nullable)
- `plugin` (string, identifies the plugin to use, e.g., "comfyui", "runwareai")
- `enabled` (boolean)
- `created_at`, `updated_at`
- **`App\Models\Role`**: Defines user roles for access control.
- `id` (PK)
- `name` (string, e.g., "admin", "user")
- `created_at`, `updated_at`
- **`App\Models\Setting`**: Stores application-wide key-value settings.
- `id` (PK)
- `key` (string)
- `value` (text)
- `created_at`, `updated_at`
## 4. Database Structure (Schema)
Key tables and their relevant columns:
- **`users`**
- `id`: `bigint unsigned auto_increment primary key`
- `name`: `varchar(255)`
- `email`: `varchar(255) unique`
- `password`: `varchar(255)`
- `role_id`: `bigint unsigned null` (FK to `roles.id`)
- `two_factor_secret`: `text null`
- `two_factor_recovery_codes`: `text null`
- `two_factor_confirmed_at`: `timestamp null`
- `settings`: `json null`
- `created_at`: `timestamp null`
- `updated_at`: `timestamp null`
- **`images`**
- `id`: `bigint unsigned auto_increment primary key`
- `path`: `varchar(255)`
- `uuid`: `char(36) unique`
- `original_image_id`: `bigint unsigned null` (FK to `images.id`)
- `style_id`: `bigint unsigned null` (FK to `styles.id`)
- `is_temp`: `tinyint(1) default 0`
- `is_public`: `tinyint(1) default 1`
- `comfyui_prompt_id`: `varchar(255) null`
- `created_at`: `timestamp null`
- `updated_at`: `timestamp null`
- **`styles`**
- `id`: `bigint unsigned auto_increment primary key`
- `title`: `varchar(255)`
- `prompt`: `longtext`
- `description`: `longtext`
- `preview_image`: `varchar(255)`
- `parameters`: `json null`
- `ai_model_id`: `bigint unsigned` (FK to `ai_models.id`)
- `enabled`: `tinyint(1) default 1`
- `created_at`: `timestamp null`
- `updated_at`: `timestamp null`
- **`ai_models`**
- `id`: `bigint unsigned auto_increment primary key`
- `name`: `varchar(255)`
- `model_id`: `varchar(255)`
- `model_type`: `varchar(255) null`
- `enabled`: `tinyint(1) default 1`
- `parameters`: `json null`
- `created_at`: `timestamp null`
- `updated_at`: `timestamp null`
- **`api_providers`**
- `id`: `bigint unsigned auto_increment primary key`
- `name`: `varchar(255)`
- `api_url`: `varchar(255)`
- `username`: `varchar(255) null`
- `password`: `varchar(255) null`
- `token`: `varchar(255) null`
- `plugin`: `varchar(255)`
- `enabled`: `tinyint(1) default 1`
- `created_at`: `timestamp null`
- `updated_at`: `timestamp null`
- **`roles`**
- `id`: `bigint unsigned auto_increment primary key`
- `name`: `varchar(255) unique`
- `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`**
- `id`: `bigint unsigned auto_increment primary key`
- `key`: `varchar(255) unique`
- `value`: `longtext`
- `created_at`: `timestamp null`
- `updated_at`: `timestamp null`
## 5. User Interactions
### 5.1. Frontend User Interactions
- **Image Upload:** Users can upload images via a dedicated interface (not explicitly detailed in provided context, but implied by gallery functionality).
- **Image Selection:** Tapping on an image in the gallery opens a context menu.
- **Context Menu Actions:**
- "Drucken" (Print): Placeholder for printing functionality.
- "Stil ändern" (Change Style): Navigates to the style selection interface.
- "Schließen" (Close): Closes the context menu.
- **Style Selection:**
- Users browse a list of available styles.
- Selecting a style initiates the AI image transformation process.
- "Back" arrow: Returns to the image context menu.
- **Gallery Refresh:** The gallery automatically updates to show newly processed images (polling every 5 seconds).
- **Authentication:** Users can log in and out.
### 5.2. Backend (Admin Panel) User Interactions
- **Resource Management:** Full CRUD operations for AI Models, API Providers, Styles, Users, and Roles.
- **Toggle Status:** Enable/disable AI Models, API Providers, and Styles.
- **Duplication:** Duplicate existing AI Models and Styles to quickly create new ones.
- **Settings Management:** Update application-wide settings.
## 6. External System Interactions
### 6.1. AI Web Services
The application integrates with external AI services for image processing. The specific plugin used is determined by the `plugin` field in the `ApiProvider` model.
- **ComfyUI (via `App\Api\Plugins\ComfyUi.php`):**
- **Image Upload:** Sends image data (base64 encoded) to the ComfyUI server's `/upload/image` endpoint.
- **Prompt Queuing:** Sends the constructed workflow JSON to the ComfyUI server's `/prompt` endpoint.
- **Result Fetching:** Polls the ComfyUI server's `/history/{prompt_id}` endpoint to check the status and retrieve the base64 encoded styled image.
- **RunwareAI (via `App\Api\Plugins\RunwareAi.php`):**
- **Image Upload:** Sends image data (base64 encoded) to the RunwareAI API.
- **Style Change Request:** Sends a request with prompt, seed image UUID, model ID, and merged parameters to the RunwareAI API for image inference.
### 6.2. Authentication
- **Laravel Sanctum:** Used for API authentication, securing routes that require user login (e.g., keeping/deleting images, admin panel access).
## 7. Call Structure and Access Rights
### 7.1. API Routes (`routes/api.php`)
- **Publicly Accessible Routes:**
- `GET /api/images`: Retrieves a list of images (public and temporary for unauthenticated users, all for authenticated users). Handled by `ImageController@index`.
- `GET /api/styles`: Retrieves a list of available styles. Handled by `StyleController@index`.
- `POST /api/images/style-change`: Initiates an AI style change request. Handled by `ImageController@styleChangeRequest`.
- `GET /api/comfyui-url`: Retrieves the ComfyUI API URL. Handled by `ImageController@getComfyUiUrl`.
- `GET /api/images/fetch-styled/{prompt_id}`: Fetches the result of a styled image request. Handled by `ImageController@fetchStyledImage`.
- **Authenticated Routes (requires `auth:sanctum` middleware):**
- `GET /api/user`: Retrieves authenticated user details.
- `POST /api/admin/navigation-state`: Stores admin navigation state. Handled by `NavigationStateController@store`.
- `POST /api/images/keep`: Marks a temporary styled image as permanent. Handled by `ImageController@keepImage`.
- `DELETE /api/images/{image}`: Deletes an image. Handled by `ImageController@deleteImage`.
- `GET /api/images/status`: Retrieves the status of an image (placeholder for future use). Handled by `ImageController@getStatus`.
### 7.2. Web Routes (`routes/web.php`)
- Standard Laravel web routes for serving the Inertia.js frontend. The main application entry point is typically handled by a route that returns an Inertia response (e.g., `Route::get('/', ...)`).
### 7.3. Access Rights
- **API Authentication:** Laravel Sanctum is used to protect API routes. Users must be authenticated to access certain functionalities.
- **Filament Admin Panel:** Access to the `/admin` panel is controlled by Filament's built-in authentication and authorization system, typically based on user roles.
- **Image Visibility:**
- `is_public` flag on `Image` model: Controls whether an image is visible to unauthenticated users.
- `is_temp` flag on `Image` model: Identifies temporary styled images. Unauthenticated users can see their own temporary images.
- **Resource Status:**
- `enabled` flag on `AiModel`, `ApiProvider`, and `Style` models: Controls whether these resources are active and usable within the application.
## 8. Detailed Description of Key Logic/Flows
### 8.1. Image Styling Process
1. **User Action (Frontend):** A user selects an image in the gallery and chooses a style from the `StyleSelector` component.
2. **Frontend Request:** The `Home.vue` component sends an `axios.post` request to `/api/images/style-change`, including the `image_id` and `style_id`.
3. **Backend (ImageController@styleChangeRequest):**
- Retrieves the `Image` and `Style` models based on the provided IDs.
- Retrieves the associated `AiModel` and `ApiProvider` from the `Style` model.
- Loads the appropriate AI plugin (e.g., `ComfyUi`, `RunwareAi`) using `PluginLoader::getPlugin()`.
- Calls the `processImageStyleChange()` method on the loaded plugin, passing the `Image` and `Style` models.
4. **AI Plugin (`ComfyUi.php` or `RunwareAi.php`):**
- **Image Upload:** The plugin first uploads the original image to the external AI service.
- **Parameter Merging:**
- It retrieves `parameters` from both the `AiModel` and the `Style` models.
- These parameters (which are JSON objects) are deeply merged using `array_replace_recursive()`. This ensures that specific parameters from the style can override or extend parameters defined at the model level.
- **Prompt Construction:** The plugin constructs the final prompt/workflow for the AI service.
- For ComfyUI, it takes the merged parameters (workflow JSON) and performs string replacements for placeholders like `__PROMPT__` (from `Style->prompt`), `__FILENAME__` (uploaded image filename), and `__MODEL_ID__` (from `AiModel->model_id`).
- Crucially, values for placeholders are JSON-encoded and then stripped of outer quotes to ensure safe injection into the JSON workflow, preventing syntax errors.
- **API Call:** The plugin sends the prepared request (e.g., prompt to ComfyUI, inference request to RunwareAI) to the external AI service.
- **Response Handling:** The plugin waits for a response from the AI service (e.g., `prompt_id` from ComfyUI, base64 image data from RunwareAI).
5. **Backend (ImageController@styleChangeRequest - continued):**
- Receives the initial response from the plugin (e.g., `prompt_id`).
- Updates the `Image` record with the `comfyui_prompt_id` and `style_id` for tracking.
- Returns a JSON response to the frontend with the `prompt_id` and `image_uuid`.
6. **Frontend (Home.vue - Polling for Result):**
- Upon receiving the `prompt_id`, the frontend starts polling `/api/images/fetch-styled/{prompt_id}`.
7. **Backend (ImageController@fetchStyledImage):**
- Retrieves the `Image` record using the `comfyui_prompt_id`.
- Loads the relevant AI plugin.
- Calls a method on the plugin (e.g., `waitForResult` for ComfyUI) to retrieve the final base64 encoded styled image data.
- Decodes the base64 image, saves it to `public/storage/uploads` (e.g., `styled_UUID.png`).
- Creates a new `Image` record in the database for the styled image, linking it to the original image and style, and setting `is_temp` to `true`.
- Returns a JSON response with the styled image's details.
8. **Frontend (Home.vue - Gallery Refresh):**
- Upon successful fetching of the styled image, the frontend calls `fetchImages()` to refresh the gallery, which now includes the newly created styled image.
### 8.2. Image Synchronization
- The `ImageController@index` method performs a synchronization between the `public/storage/uploads` directory and the `images` table in the database.
- It adds new image files found on disk to the database.
- It removes database entries for images that no longer exist on disk.
- This ensures the gallery always reflects the actual files in storage.
### 8.3. Parameter Merging Logic
- The `parameters` fields in `Style` and `AiModel` are stored as JSON in the database and automatically cast to PHP arrays by Eloquent.
- In the AI plugins (`ComfyUi.php`, `RunwareAi.php`), when constructing the AI service request:
- `$modelParams = $style->aiModel->parameters ?? [];`
- `$styleParams = $style->parameters ?? [];`
- `$mergedParams = array_replace_recursive($modelParams, $styleParams);`
- This `array_replace_recursive` function is crucial for deep merging, allowing style-specific parameters to override or extend model-level parameters.
- Placeholders (`__PROMPT__`, `__FILENAME__`, `__MODEL_ID__`) within the merged JSON are replaced with actual values. These values are first JSON-encoded and then trimmed of their outer quotes to ensure they are safely inserted into the JSON structure without breaking it.
### 8.4. File Storage Configuration
- The application uses Laravel's filesystem configuration.
- The `public` disk is configured in `config/filesystems.php` to point directly to `public_path('storage')`.
- Images uploaded via Filament (e.g., style previews) are stored in `public/storage/style_previews`.
- The `public/storage` directory is a symbolic link to `storage/app/public` (though the configuration was adjusted to point directly to `public/storage` for the `public` disk).
This detailed overview should provide a solid foundation for understanding and rebuilding the AI StyleGallery application.

46
Styles Flux kontext v1.md Normal file
View File

@@ -0,0 +1,46 @@
Transform the people in the image into a pastel drawing with gentle textures and soft hues.
Transform the people in the image into an abstract painting with vibrant swirls and emotional energy.
Transform the people in the image into pixel art characters with blocky shapes and a retro video game feel.
Transform the people in the image into low-poly 3D models with geometric surfaces and flat shading.
Transform the people in the image into chrome sculptures with reflective surfaces and metallic shine.
Transform the people in the image into blueprint-style figures with line work and measurement details.
Transform the people in the image into characters from a Studio Ghibli film with soft shading and magical warmth.
Transform the people in the image into a comic book scene with halftone shading and dynamic poses.
Transform the people in the image into characters from a 3D Pixar-style movie with expressive faces and big eyes.
Transform the people in the image into characters from The Simpsons with yellow skin and over-the-top expressions.
Transform the people in the image into LEGO-style figures with plastic texture and toy-like features.
Transform the people in the image into South Park-style cutout characters with flat shapes and goofy faces.
Transform the people in the image into medieval knights and nobles in a fantasy setting with ornate costumes. make the image bright
Transform the people in the image into elves and wizards from a magical forest with glowing runes
Transform the people in the image into steampunk characters with gears, goggles, and Victorian flair.
Transform the people in the image into ancient stone statues with cracks and moss growing on them
Transform the people in the image into a group of zombies with cartoony decay and goofy expressions. make the image bright.
Transform the people in the image into carved wooden figures with natural grain patterns, warm tones, and handmade imperfections.
Transform the people in the image into graffiti-style characters on a concrete wall, with spray paint textures, vibrant strokes, and urban flair.
Transform the people in the image into 3D-printed sculptures with plastic textures, visible print lines, and geometric precision.
Transform the people in the image into painted cardboard cutouts with flat surfaces, hand-drawn outlines, and theater-prop appearance.
Transform the people in the image into figures like on an ancient Greek vase, rendered in black-figure ceramic painting with elegant poses.
Transform the people in the image into medieval illuminated manuscript figures with gold leaf accents, stylized faces, and vibrant borders.
Transform the people in the image into Aztec stone carvings with geometric patterns, mythological motifs, and ancient symbolism.
Transform the people in the image into cracked porcelain dolls with aged glaze, fine fractures, and haunting fragility.
Transform the people in the image into cardboard paper dolls with tabbed joints, illustrated features, and moveable parts.
Transform the people in the image into stylized cut-paper collages, with torn edges, colorful flat textures, and assembled human shapes.
Transform the people in the image into 80s disco icons with glitter outfits, exaggerated hair, shiny dance floors, and neon lighting.
Transform the people in the image into soap opera villains mid-dramatic twist, with wind machines, sparkles, and over-the-top reactions.
Transform the people in the image into enchanted talking teapots, cups, and kitchen objects with faces and arms, ready to sing.
Transform the image into a sunny day in front of the Eiffel Tower in Paris, with the people posing like tourists, café tables nearby and pigeons flying around.
Transform the image into a night scene in Tokyos Shibuya Crossing, with neon lights, animated billboards, and a bustling futuristic city backdrop.
remove the background and Transform the image into a street performance in New Yorks Times Square, with giant screens, yellow taxis, and amazed onlookers.
remove the background and Transform the image into a group photo in front of the Colosseum in Rome, with sunny weather, tourists with cameras, and ancient stone textures. Keep all the face details from the original
remove the background and Transform the image into a sunset beach party in Hawaii, with palm trees, ukuleles, tiki torches, and ocean waves.
remove the background and Transform the image into a hike through a misty rainforest with lush green foliage, vines, and curious animals peeking from the trees.
remove the background and Transform the image into a field of sunflowers stretching to the horizon, with bees buzzing and the people dressed in summer clothes.
remove the background and Transform the image into a magical floating island in the sky, with waterfalls cascading into the clouds and glowing plants surrounding the group.
remove the background and Transform the image into a dreamlike moonbase picnic with Earth visible above, moon buggies nearby, and silver spacesuits.
remove the background and Transform the image into a carnival at night, with colorful tents, cotton candy, blinking lights, and joyful movement.
remove the background and Transform the image into a retro 80s arcade hall, with glowing cabinets, pixelated screens, and classic synth lighting.
remove the background and Transform the image into a Moroccan market at sunset, with patterned rugs, spices in the air, and hanging lamps lighting the scene.
remove the background and Transform the image into a steampunk city plaza with brass towers, flying machines, and the group dressed in goggles and gears.
remove the background and Transform the image into a colorful Holi festival in India, with powder paint in the air and everyone covered in bright colors.
remove the background and Transform the image into a vintage movie set from the 1920s, with sepia tones, cameras on tracks, and dramatic film star poses.
insert into styles (title,prompt,description,preview_image,created_at,ai_model_id,enabled), VALUES(*titel*, *prompt*, *beschreibung*,'uploads/ComfyUI_*laufende Nummer mit 4 führenden Nullen*_.png, NOW(), 8, 1);

View File

@@ -11,5 +11,5 @@ interface ApiPluginInterface
public function disable(): bool;
public function getStatus(string $imageUUID): array;
public function getProgress(string $imageUUID): array;
public function processImageStyleChange(string $imagePath, string $prompt, string $modelId, ?string $parameters = null): array;
public function processImageStyleChange(\App\Models\Image $image, \App\Models\Style $style): array;
}

View File

@@ -82,16 +82,16 @@ class ComfyUi implements ApiPluginInterface
return $response->json();
}
public function processImageStyleChange(string $imagePath, string $prompt, string $modelId, ?string $parameters = null): array
public function processImageStyleChange(\App\Models\Image $image, \App\Models\Style $style): array
{
$this->logInfo('Starting ComfyUI style change process.', ['image_path' => $imagePath]);
$this->logInfo('Starting ComfyUI style change process.', ['image_id' => $image->id, 'style_id' => $style->id]);
// 1. Upload image to ComfyUI
$uploadResponse = $this->uploadImage($imagePath);
$uploadResponse = $this->uploadImage(public_path('storage/' . $image->path));
$filename = $uploadResponse['name'];
// 2. Construct the prompt
$promptData = $this->constructPrompt($prompt, $filename, $modelId, $parameters);
$promptData = $this->constructPrompt($style, $filename);
// 3. Queue the prompt
$queueResponse = $this->queuePrompt($promptData);
@@ -119,18 +119,39 @@ class ComfyUi implements ApiPluginInterface
return $response->json();
}
private function constructPrompt(string $prompt, string $filename, string $modelId, ?string $parameters): array
private function constructPrompt(\App\Models\Style $style, string $filename): array
{
if (empty($parameters)) {
$modelParams = $style->aiModel->parameters ?? [];
$styleParams = $style->parameters ?? [];
if (empty($modelParams) && empty($styleParams)) {
throw new \Exception('ComfyUI workflow (parameters) is missing.');
}
$workflow = $parameters;
$workflow = str_replace('__PROMPT__', $prompt, $workflow);
$workflow = str_replace('__FILENAME__', $filename, $workflow);
$workflow = str_replace('__MODEL_ID__', $modelId, $workflow);
// Use array_replace_recursive for a deep merge
$mergedParams = array_replace_recursive($modelParams, $styleParams);
$workflow = json_encode($mergedParams);
return json_decode($workflow, true);
// Properly escape the values for JSON injection
$prompt = substr(json_encode($style->prompt, JSON_UNESCAPED_SLASHES), 1, -1);
$filename_escaped = substr(json_encode($filename, JSON_UNESCAPED_SLASHES), 1, -1);
$modelId_escaped = substr(json_encode($style->aiModel->model_id, JSON_UNESCAPED_SLASHES), 1, -1);
$workflow = str_replace('__PROMPT__', $prompt, $workflow);
$workflow = str_replace('__FILENAME__', $filename_escaped, $workflow);
$workflow = str_replace('__MODEL_ID__', $modelId_escaped, $workflow);
$decodedWorkflow = json_decode($workflow, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$this->logError('Failed to decode workflow JSON after placeholder replacement.', [
'json_error' => json_last_error_msg(),
'workflow_string' => $workflow
]);
throw new \Exception('Failed to construct valid ComfyUI workflow JSON: ' . json_last_error_msg());
}
return $decodedWorkflow;
}
private function queuePrompt(array $promptData): array

View File

@@ -71,10 +71,10 @@ class RunwareAi implements ApiPluginInterface
return ['progress' => 0];
}
public function processImageStyleChange(string $imagePath, string $prompt, string $modelId, ?string $parameters = null): array
public function processImageStyleChange(\App\Models\Image $image, \App\Models\Style $style): array
{
// Step 1: Upload the original image
$uploadResult = $this->upload($imagePath);
$uploadResult = $this->upload(public_path('storage/' . $image->path));
if (!isset($uploadResult['data'][0]['imageUUID'])) {
throw new \Exception('Image upload to AI service failed or returned no UUID.');
@@ -82,7 +82,7 @@ class RunwareAi implements ApiPluginInterface
$seedImageUUID = $uploadResult['data'][0]['imageUUID'];
// Step 2: Request style change using the uploaded image's UUID
$result = $this->styleChangeRequest($prompt, $seedImageUUID, $modelId, $parameters);
$result = $this->styleChangeRequest($style, $seedImageUUID);
if (!isset($result['base64Data'])) {
throw new \Exception('AI service did not return base64 image data.');
@@ -127,9 +127,9 @@ class RunwareAi implements ApiPluginInterface
}
}
private function styleChangeRequest(string $prompt, string $seedImageUUID, string $modelId, ?string $parameters = null): array
private function styleChangeRequest(\App\Models\Style $style, string $seedImageUUID): array
{
$this->logInfo('Attempting style change request to RunwareAI.', ['prompt' => $prompt, 'seed_image_uuid' => $seedImageUUID]);
$this->logInfo('Attempting style change request to RunwareAI.', ['style_id' => $style->id, 'seed_image_uuid' => $seedImageUUID]);
if (!$this->apiProvider->api_url || !$this->apiProvider->token) {
$this->logError('RunwareAI API URL or Token not configured for style change.', ['provider_name' => $this->apiProvider->name]);
throw new \Exception('RunwareAI API URL or Token not configured.');
@@ -139,17 +139,20 @@ class RunwareAi implements ApiPluginInterface
$token = $this->apiProvider->token;
$taskUUID = (string) Str::uuid();
$modelParams = $style->aiModel->parameters ?? [];
$styleParams = $style->parameters ?? [];
$mergedParams = array_replace_recursive($modelParams, $styleParams);
$data = [
'taskType' => 'imageInference',
'taskUUID' => $taskUUID,
'positivePrompt' => $prompt,
'positivePrompt' => $style->prompt,
'seedImage' => $seedImageUUID,
'outputType' => 'base64Data',
'model' => $modelId,
'model' => $style->aiModel->model_id,
];
$decodedParameters = json_decode($parameters, true) ?? [];
foreach ($decodedParameters as $key => $value) {
foreach ($mergedParams as $key => $value) {
$data[$key] = $value;
}

View File

@@ -47,6 +47,13 @@ class AiModelResource extends Resource
->preload()
->searchable(false)
->label(__('filament.resource.ai_model.form.api_providers')),
Forms\Components\Textarea::make('parameters')
->label(__('filament.resource.ai_model.form.parameters'))
->nullable()
->rows(15)
->json()
->helperText(__('filament.resource.ai_model.form.parameters_help'))
->formatStateUsing(fn (?array $state): ?string => $state ? json_encode($state, JSON_PRETTY_PRINT) : null),
]);
}

View File

@@ -56,7 +56,8 @@ class StyleResource extends Resource
->nullable()
->rows(15)
->json()
->helperText(__('filament.resource.style.form.parameters_help')),
->helperText(__('filament.resource.style.form.parameters_help'))
->formatStateUsing(fn (?array $state): ?string => $state ? json_encode($state, JSON_PRETTY_PRINT) : null),
Select::make('ai_model_id')
->relationship('aiModel', 'name')
->label(__('filament.resource.style.form.ai_model'))

View File

@@ -154,12 +154,7 @@ class ImageController extends Controller
}
$plugin = PluginLoader::getPlugin($apiProvider->plugin, $apiProvider);
$result = $plugin->processImageStyleChange(
public_path('storage/' . $image->path),
$style->prompt,
$style->aiModel->model_id,
$style->parameters
);
$result = $plugin->processImageStyleChange($image, $style);
// Update the image model with the ComfyUI prompt_id and style_id
$image->comfyui_prompt_id = $result['prompt_id'];

View File

@@ -13,6 +13,11 @@ class AiModel extends Model
'name',
'model_id',
'model_type',
'parameters',
];
protected $casts = [
'parameters' => 'array',
];
public function apiProviders()

View File

@@ -21,6 +21,7 @@ class Style extends Model
protected $casts = [
'enabled' => 'boolean',
'parameters' => 'array',
];
public function aiModel()

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('ai_models', function (Blueprint $table) {
$table->json('parameters')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('ai_models', function (Blueprint $table) {
$table->dropColumn('parameters');
});
}
};

13
package-lock.json generated
View File

@@ -9,7 +9,8 @@
"@fortawesome/free-solid-svg-icons": "^7.0.0",
"@fortawesome/vue-fontawesome": "^3.1.1",
"laravel-echo": "^2.1.7",
"pusher-js": "^8.4.0"
"pusher-js": "^8.4.0",
"vanilla-lazyload": "^19.1.3"
},
"devDependencies": {
"@inertiajs/vue3": "^1.0.0",
@@ -3141,6 +3142,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/vanilla-lazyload": {
"version": "19.1.3",
"resolved": "https://registry.npmjs.org/vanilla-lazyload/-/vanilla-lazyload-19.1.3.tgz",
"integrity": "sha512-bBMERPu2AFJc35krS+8BOhq++c6dRfL6q368lJPnkS5U92fRQagTR3FsNta69/GukfZzDwDEjD5M3U7VuSiCDw==",
"license": "MIT",
"funding": {
"type": "individual",
"url": "https://ko-fi.com/verlok"
}
},
"node_modules/vite": {
"version": "5.4.19",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz",

View File

@@ -21,6 +21,7 @@
"@fortawesome/free-solid-svg-icons": "^7.0.0",
"@fortawesome/vue-fontawesome": "^3.1.1",
"laravel-echo": "^2.1.7",
"pusher-js": "^8.4.0"
"pusher-js": "^8.4.0",
"vanilla-lazyload": "^19.1.3"
}
}

View File

@@ -15,7 +15,7 @@
class="style-item"
@click="selectStyle(style)"
>
<img :src="'/storage/' + style.preview_image" :alt="style.title" class="style-thumbnail" />
<img :data-src="'/storage/' + style.preview_image" :alt="style.title" class="style-thumbnail" />
<div class="style-details">
<h4>{{ style.title }}</h4>
<p>{{ style.description }}</p>
@@ -27,7 +27,7 @@
<script setup>
import axios from 'axios';
import { ref, onMounted } from 'vue';
import { ref, onMounted, nextTick } from 'vue';
const styles = ref([]);
@@ -44,6 +44,24 @@ const fetchStyles = () => {
axios.get('/api/styles')
.then(response => {
styles.value = response.data;
nextTick(() => {
const stylesList = document.querySelector('.styles-list');
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
}, {
root: stylesList // Observe intersections relative to .styles-list
});
stylesList.querySelectorAll('.style-thumbnail').forEach(img => {
observer.observe(img);
});
});
})
.catch(error => {
console.error('Error fetching styles:', error);

View File

@@ -8,7 +8,9 @@ return [
'model_id' => 'Modell ID',
'model_type' => 'Modell Typ',
'enabled' => 'Aktiviert',
'api_providers' => 'API Anbieter',
'api_providers' => 'API Provider',
'parameters' => 'Parameter',
'parameters_help' => 'Für ComfyUI, fügen Sie hier das Workflow-JSON ein. Verwenden Sie __PROMPT__, __FILENAME__ und __MODEL_ID__ als Platzhalter.',
],
'table' => [
'name' => 'Name',

View File

@@ -9,6 +9,8 @@ return [
'model_type' => 'Model Type',
'enabled' => 'Enabled',
'api_providers' => 'API Providers',
'parameters' => 'Parameters',
'parameters_help' => 'For ComfyUI, paste the workflow JSON here. Use __PROMPT__, __FILENAME__, and __MODEL_ID__ as placeholders.',
],
'table' => [
'name' => 'Name',