upgrade to laravel 12 done
This commit is contained in:
@@ -65,9 +65,21 @@ class ComfyUi implements ApiPluginInterface
|
||||
|
||||
public function getProgress(string $imageUUID): array
|
||||
{
|
||||
$this->logDebug('Getting progress for image.', ['image_uuid' => $imageUUID]);
|
||||
// Implement ComfyUI specific progress check
|
||||
return ['progress' => 0];
|
||||
$this->logDebug('Progress updates are handled via WebSocket.', ['image_uuid' => $imageUUID]);
|
||||
return ['progress' => 0]; // Progress is now handled by WebSocket
|
||||
}
|
||||
|
||||
private function getHistory(string $promptId): array
|
||||
{
|
||||
// This method is no longer used for progress polling, but might be used for final result retrieval
|
||||
$apiUrl = rtrim($this->apiProvider->api_url, '/');
|
||||
$timeout = 60; // seconds
|
||||
$this->logDebug('ComfyUI History API URL:', ['url' => $apiUrl . '/history/' . $promptId, 'timeout' => $timeout]);
|
||||
$response = Http::timeout($timeout)->get($apiUrl . '/history/' . $promptId);
|
||||
if ($response->failed()) {
|
||||
throw new \Exception('Failed to get history from ComfyUI');
|
||||
}
|
||||
return $response->json();
|
||||
}
|
||||
|
||||
public function processImageStyleChange(string $imagePath, string $prompt, string $modelId, ?string $parameters = null): array
|
||||
@@ -85,10 +97,8 @@ class ComfyUi implements ApiPluginInterface
|
||||
$queueResponse = $this->queuePrompt($promptData);
|
||||
$promptId = $queueResponse['prompt_id'];
|
||||
|
||||
// 4. Wait for and get the result
|
||||
$result = $this->waitForResult($promptId);
|
||||
|
||||
return ['base64Data' => $result];
|
||||
// Return the prompt_id for frontend WebSocket tracking
|
||||
return ['prompt_id' => $promptId];
|
||||
}
|
||||
|
||||
private function uploadImage(string $imagePath): array
|
||||
@@ -96,7 +106,7 @@ class ComfyUi implements ApiPluginInterface
|
||||
$this->logInfo('Uploading image to ComfyUI.', ['image_path' => $imagePath]);
|
||||
$response = Http::attach(
|
||||
'image', file_get_contents($imagePath), basename($imagePath)
|
||||
)->timeout(120)->post(rtrim($this->apiProvider->api_url, '/') . '/upload/image', [
|
||||
)->timeout(60)->post(rtrim($this->apiProvider->api_url, '/') . '/upload/image', [
|
||||
'type' => 'input',
|
||||
'overwrite' => 'false',
|
||||
]);
|
||||
@@ -126,7 +136,7 @@ class ComfyUi implements ApiPluginInterface
|
||||
private function queuePrompt(array $promptData): array
|
||||
{
|
||||
$this->logInfo('Queueing prompt in ComfyUI.');
|
||||
$response = Http::timeout(120)->post(rtrim($this->apiProvider->api_url, '/') . '/prompt', ['prompt' => $promptData]);
|
||||
$response = Http::timeout(60)->post(rtrim($this->apiProvider->api_url, '/') . '/prompt', ['prompt' => $promptData]);
|
||||
|
||||
if ($response->failed()) {
|
||||
$this->logError('Failed to queue prompt in ComfyUI.', ['response' => $response->body()]);
|
||||
@@ -136,30 +146,64 @@ class ComfyUi implements ApiPluginInterface
|
||||
return $response->json();
|
||||
}
|
||||
|
||||
private function waitForResult(string $promptId): string
|
||||
public function waitForResult(string $promptId): string
|
||||
{
|
||||
$this->logInfo('Waiting for ComfyUI result.', ['prompt_id' => $promptId]);
|
||||
while (true) {
|
||||
$response = Http::timeout(120)->get($this->apiProvider->api_url . '/history/' . $promptId);
|
||||
$data = $response->json();
|
||||
set_time_limit(120); // Set maximum execution time for this function
|
||||
$this->logInfo('waitForResult: Waiting for ComfyUI result.', ['prompt_id' => $promptId]);
|
||||
$startTime = microtime(true);
|
||||
$timeout = 180; // seconds
|
||||
|
||||
if (!empty($data[$promptId]['outputs'])) {
|
||||
$outputs = $data[$promptId]['outputs'];
|
||||
// Assuming the first output with an image is the one we want
|
||||
foreach ($outputs as $output) {
|
||||
if (isset($output['images'][0]['type']) && $output['images'][0]['type'] === 'output') {
|
||||
$imageUrl = sprintf('%s/view?filename=%s&subfolder=%s&type=output',
|
||||
$this->apiProvider->api_url,
|
||||
$output['images'][0]['filename'],
|
||||
$output['images'][0]['subfolder']
|
||||
);
|
||||
$image_data = file_get_contents($imageUrl);
|
||||
return base64_encode($image_data);
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
if (microtime(true) - $startTime > $timeout) {
|
||||
$this->logError('waitForResult: ComfyUI result polling timed out.', ['prompt_id' => $promptId]);
|
||||
throw new \Exception('ComfyUI result polling timed out.');
|
||||
}
|
||||
|
||||
sleep(2); // Wait for 2 seconds before polling again
|
||||
try {
|
||||
$response = Http::timeout(60)->get(rtrim($this->apiProvider->api_url, '/') . '/history/' . $promptId);
|
||||
$this->logDebug('waitForResult: History API response status.', ['status' => $response->status(), 'prompt_id' => $promptId]);
|
||||
|
||||
if ($response->failed()) {
|
||||
$this->logError('waitForResult: Failed to get history from ComfyUI.', ['prompt_id' => $promptId, 'response' => $response->body()]);
|
||||
throw new \Exception('Failed to get history from ComfyUI');
|
||||
}
|
||||
|
||||
$data = $response->json();
|
||||
$this->logDebug('waitForResult: History API response data.', ['data' => $data, 'prompt_id' => $promptId]);
|
||||
|
||||
if (isset($data[$promptId]['outputs'])) {
|
||||
$outputs = $data[$promptId]['outputs'];
|
||||
$this->logInfo('waitForResult: Found outputs in history.', ['prompt_id' => $promptId, 'outputs_count' => count($outputs)]);
|
||||
|
||||
foreach ($outputs as $output) {
|
||||
if (isset($output['images'][0]['type']) && $output['images'][0]['type'] === 'output') {
|
||||
$imageUrl = sprintf('%s/view?filename=%s&subfolder=%s&type=output',
|
||||
rtrim($this->apiProvider->api_url, '/'),
|
||||
$output['images'][0]['filename'],
|
||||
$output['images'][0]['subfolder']
|
||||
);
|
||||
$this->logInfo('waitForResult: Constructed image URL.', ['imageUrl' => $imageUrl, 'prompt_id' => $promptId]);
|
||||
|
||||
$imageResponse = Http::timeout(60)->get($imageUrl);
|
||||
$this->logDebug('waitForResult: Image fetch response status.', ['status' => $imageResponse->status(), 'imageUrl' => $imageUrl]);
|
||||
|
||||
if ($imageResponse->failed()) {
|
||||
$this->logError('waitForResult: Failed to retrieve image data from ComfyUI.', ['imageUrl' => $imageUrl, 'response' => $imageResponse->body()]);
|
||||
throw new \Exception('Failed to retrieve image data from ComfyUI');
|
||||
}
|
||||
$this->logInfo('waitForResult: Successfully retrieved image data.', ['prompt_id' => $promptId]);
|
||||
return base64_encode($imageResponse->body());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->logDebug('waitForResult: No outputs found yet for prompt.', ['prompt_id' => $promptId]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->logError('waitForResult: Exception caught during polling.', ['prompt_id' => $promptId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
|
||||
throw $e; // Re-throw the exception to be caught by ImageController
|
||||
}
|
||||
|
||||
usleep(500000); // Wait for 0.5 seconds before polling again
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*/
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
// $schedule->command('inspire')->hourly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the commands for the application.
|
||||
*/
|
||||
protected function commands(): void
|
||||
{
|
||||
$this->load(__DIR__.'/Commands');
|
||||
|
||||
require base_path('routes/console.php');
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ class CollectionEloquentBuilder extends Builder
|
||||
return $this->collection->firstWhere('id', $id);
|
||||
}
|
||||
|
||||
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
|
||||
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null, $total = null)
|
||||
{
|
||||
$page = $page ?: Paginator::resolveCurrentPage($pageName);
|
||||
|
||||
|
||||
@@ -45,10 +45,11 @@ class StyleResource extends Resource
|
||||
->rows(5),
|
||||
FileUpload::make('preview_image')
|
||||
->label(__('filament.resource.style.form.preview_image'))
|
||||
->required()
|
||||
->image()
|
||||
->disk('public')
|
||||
->directory('style_previews'),
|
||||
->directory('style_previews')
|
||||
->image()
|
||||
->required()
|
||||
->rules(['mimes:jpeg,png,bmp,gif,webp']),
|
||||
Textarea::make('parameters')
|
||||
->label(__('filament.resource.style.form.parameters'))
|
||||
->nullable()
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Models\ApiProvider;
|
||||
use App\Models\Style;
|
||||
use App\Models\Image;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\Setting;
|
||||
|
||||
@@ -75,7 +76,7 @@ class ImageController extends Controller
|
||||
public function upload(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'image' => 'required|image|max:10240', // Max 10MB
|
||||
'image' => 'required|image|mimes:jpeg,png,bmp,gif,webp|max:10240', // Max 10MB
|
||||
]);
|
||||
|
||||
$file = $request->file('image');
|
||||
@@ -156,34 +157,16 @@ class ImageController extends Controller
|
||||
$style->parameters
|
||||
);
|
||||
|
||||
$base64Image = $result['base64Data'];
|
||||
$decodedImage = base64_decode(preg_replace('#^data:image/\w+;base64, #i', '', $base64Image));
|
||||
|
||||
$newImageName = 'styled_' . uniqid() . '.png'; // Assuming PNG for now
|
||||
$newImagePathRelative = 'uploads/' . $newImageName; // Path relative to public/storage/
|
||||
$newImageFullPath = public_path('storage/' . $newImagePathRelative); // Full path to save
|
||||
|
||||
// Ensure the directory exists
|
||||
if (!File::exists(public_path('storage/uploads'))) {
|
||||
File::makeDirectory(public_path('storage/uploads'), 0755, true);
|
||||
}
|
||||
|
||||
File::put($newImageFullPath, $decodedImage); // Save using File facade
|
||||
|
||||
$newImage = Image::create([
|
||||
'path' => $newImagePathRelative, // Store relative path
|
||||
'original_image_id' => $image->id, // Link to original image
|
||||
'style_id' => $style->id, // Link to applied style
|
||||
'is_temp' => true, // Mark as temporary until user keeps it
|
||||
]);
|
||||
// Update the image model with the ComfyUI prompt_id and style_id
|
||||
$image->comfyui_prompt_id = $result['prompt_id'];
|
||||
$image->style_id = $style->id;
|
||||
$image->save();
|
||||
|
||||
// Return the prompt_id for WebSocket tracking
|
||||
return response()->json([
|
||||
'message' => 'Style change successful',
|
||||
'styled_image' => [
|
||||
'id' => $newImage->id,
|
||||
'path' => asset('storage/' . $newImage->path),
|
||||
'is_temp' => $newImage->is_temp,
|
||||
],
|
||||
'message' => 'Style change request sent.',
|
||||
'prompt_id' => $result['prompt_id'],
|
||||
'image_uuid' => $image->uuid, // Pass image UUID for frontend tracking
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json(['error' => $e->getMessage()], 500);
|
||||
@@ -243,26 +226,99 @@ class ImageController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
public function getProgress(Request $request)
|
||||
public function fetchStyledImage(string $promptId)
|
||||
{
|
||||
$request->validate([
|
||||
'image_id' => 'required|exists:images,id',
|
||||
'api_provider_name' => 'required|string',
|
||||
]);
|
||||
|
||||
$image = Image::find($request->image_id);
|
||||
$apiProvider = ApiProvider::where('name', $request->api_provider_name)->first();
|
||||
|
||||
if (!$image || !$apiProvider) {
|
||||
return response()->json(['error' => __('api.image_or_provider_not_found')], 404);
|
||||
}
|
||||
|
||||
Log::info('fetchStyledImage called.', ['prompt_id' => $promptId]);
|
||||
try {
|
||||
$plugin = PluginLoader::getPlugin($apiProvider->name);
|
||||
$progress = $plugin->getProgress($image->uuid); // Annahme: Image Model hat eine UUID
|
||||
return response()->json($progress);
|
||||
// Find the image associated with the prompt_id, eagerly loading relationships
|
||||
$image = Image::with(['style.aiModel.apiProviders' => function ($query) {
|
||||
$query->where('enabled', true);
|
||||
}])->where('comfyui_prompt_id', $promptId)->first();
|
||||
|
||||
if (!$image) {
|
||||
Log::warning('fetchStyledImage: Image not found for prompt_id.', ['prompt_id' => $promptId]);
|
||||
return response()->json(['error' => __('api.image_not_found')], 404);
|
||||
}
|
||||
|
||||
Log::info('fetchStyledImage: Image found.', ['image_id' => $image->id, 'image_uuid' => $image->uuid, 'comfyui_prompt_id' => $image->comfyui_prompt_id]);
|
||||
|
||||
// Get the style and API provider associated with the image
|
||||
$style = $image->style;
|
||||
if (!$style) {
|
||||
Log::warning('fetchStyledImage: Style not found for image.', ['image_id' => $image->id]);
|
||||
return response()->json(['error' => __('api.style_or_provider_not_found')], 404);
|
||||
}
|
||||
Log::info('fetchStyledImage: Style found.', ['style_id' => $style->id, 'style_name' => $style->title]);
|
||||
|
||||
if (!$style->aiModel) {
|
||||
Log::warning('fetchStyledImage: AI Model not found for style.', ['style_id' => $style->id]);
|
||||
return response()->json(['error' => __('api.style_or_provider_not_found')], 404);
|
||||
}
|
||||
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);
|
||||
}
|
||||
$apiProvider = $style->aiModel->apiProviders->first();
|
||||
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
|
||||
|
||||
if (empty($base64Image)) {
|
||||
Log::error('Received empty base64 image from plugin.', ['prompt_id' => $promptId]);
|
||||
return response()->json(['error' => 'Received empty image data.'], 500);
|
||||
}
|
||||
|
||||
Log::info('Base64 image received. Decoding and saving.');
|
||||
$decodedImage = base64_decode(preg_replace('#^data:image/\w+;base64, #i', '', $base64Image));
|
||||
|
||||
$newImageName = 'styled_' . uniqid() . '.png';
|
||||
$newImagePathRelative = 'uploads/' . $newImageName;
|
||||
$newImageFullPath = public_path('storage/' . $newImagePathRelative);
|
||||
|
||||
if (!File::exists(public_path('storage/uploads'))) {
|
||||
File::makeDirectory(public_path('storage/uploads'), 0755, true);
|
||||
Log::info('Created uploads directory.', ['path' => public_path('storage/uploads')]);
|
||||
}
|
||||
|
||||
File::put($newImageFullPath, $decodedImage); // Save using File facade
|
||||
Log::info('Image saved to disk.', ['path' => $newImageFullPath]);
|
||||
|
||||
$newImage = Image::create([
|
||||
'path' => $newImagePathRelative, // Store relative path
|
||||
'original_image_id' => $image->id,
|
||||
'style_id' => $style->id,
|
||||
'is_temp' => true,
|
||||
]);
|
||||
|
||||
Log::info('New image record created in database.', ['image_id' => $newImage->id, 'path' => $newImage->path]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Styled image fetched successfully',
|
||||
'styled_image' => [
|
||||
'id' => $newImage->id,
|
||||
'path' => asset('storage/' . $newImage->path),
|
||||
'is_temp' => $newImage->is_temp,
|
||||
],
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error in fetchStyledImage: ' . $e->getMessage(), ['exception' => $e]);
|
||||
return response()->json(['error' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getComfyUiUrl()
|
||||
{
|
||||
$apiProvider = ApiProvider::where('plugin', 'comfyui')->where('enabled', true)->first();
|
||||
|
||||
if (!$apiProvider) {
|
||||
return response()->json(['error' => 'No enabled ComfyUI API provider found.'], 404);
|
||||
}
|
||||
|
||||
return response()->json(['comfyui_url' => rtrim($apiProvider->api_url, '/')]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
/**
|
||||
* The application's global HTTP middleware stack.
|
||||
*
|
||||
* These middleware are run during every request to your application.
|
||||
*
|
||||
* @var array<int, class-string|string>
|
||||
*/
|
||||
protected $middleware = [
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware groups.
|
||||
*
|
||||
* @var array<string, array<int, class-string|string>>
|
||||
*/
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\SetContentSecurityPolicy::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\HandleInertiaRequests::class,
|
||||
\Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's middleware aliases.
|
||||
*
|
||||
* Aliases may be used to conveniently assign middleware to routes and groups.
|
||||
*
|
||||
* @var array<string, class-string|string>
|
||||
*/
|
||||
protected $middlewareAliases = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
];
|
||||
}
|
||||
@@ -17,5 +17,11 @@ class Image extends Model
|
||||
'style_id',
|
||||
'is_temp',
|
||||
'is_public',
|
||||
'comfyui_prompt_id',
|
||||
];
|
||||
|
||||
public function style()
|
||||
{
|
||||
return $this->belongsTo(Style::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Create The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The first thing we will do is create a new Laravel application instance
|
||||
| which serves as the "glue" for all the components of Laravel, and is
|
||||
| the IoC container for the system binding all of the various parts.
|
||||
|
|
||||
*/
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
|
||||
$app = new Illuminate\Foundation\Application(
|
||||
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
|
||||
);
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
$middleware->web(append: [
|
||||
\App\Http\Middleware\HandleInertiaRequests::class,
|
||||
\Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class,
|
||||
]);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Bind Important Interfaces
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Next, we need to bind some important interfaces into the container so
|
||||
| we will be able to resolve them when needed. The kernels serve the
|
||||
| incoming requests to this application from both the web and CLI.
|
||||
|
|
||||
*/
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Http\Kernel::class,
|
||||
App\Http\Kernel::class
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Console\Kernel::class,
|
||||
App\Console\Kernel::class
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Debug\ExceptionHandler::class,
|
||||
App\Exceptions\Handler::class
|
||||
);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Return The Application
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This script returns the application instance. The instance is given to
|
||||
| the calling script so we can separate the building of the instances
|
||||
| from the actual running of the application and sending responses.
|
||||
|
|
||||
*/
|
||||
|
||||
return $app;
|
||||
$middleware->alias([
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions) {
|
||||
//
|
||||
})->create();
|
||||
@@ -5,14 +5,16 @@
|
||||
"keywords": ["framework", "laravel"],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"filament/filament": "3.0",
|
||||
"php": "^8.3",
|
||||
"amphp/websocket-client": "^2.0",
|
||||
"filament/filament": "^3.2",
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"inertiajs/inertia-laravel": "^0.6.8",
|
||||
"laravel/breeze": "1.29",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/sanctum": "^3.2",
|
||||
"inertiajs/inertia-laravel": "^1.0",
|
||||
"laravel/breeze": "^2.0",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/tinker": "^2.8",
|
||||
"predis/predis": "^3.1",
|
||||
"tightenco/ziggy": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -20,9 +22,9 @@
|
||||
"laravel/pint": "^1.0",
|
||||
"laravel/sail": "^1.18",
|
||||
"mockery/mockery": "^1.4.4",
|
||||
"nunomaduro/collision": "^7.0",
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"spatie/laravel-ignition": "^2.0"
|
||||
"nunomaduro/collision": "^8.1",
|
||||
"phpunit/phpunit": "^12.0",
|
||||
"spatie/laravel-ignition": "^2.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
||||
3636
composer.lock
generated
3636
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('BROADCAST_DRIVER', 'null'),
|
||||
'default' => env('BROADCAST_DRIVER', 'redis'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
@@ -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('images', function (Blueprint $table) {
|
||||
$table->string('comfyui_prompt_id')->nullable()->after('uuid');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('images', function (Blueprint $table) {
|
||||
$table->dropColumn('comfyui_prompt_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
149
package-lock.json
generated
149
package-lock.json
generated
@@ -7,7 +7,9 @@
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^7.0.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.0.0",
|
||||
"@fortawesome/vue-fontawesome": "^3.1.1"
|
||||
"@fortawesome/vue-fontawesome": "^3.1.1",
|
||||
"laravel-echo": "^2.1.7",
|
||||
"pusher-js": "^8.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@inertiajs/vue3": "^1.0.0",
|
||||
@@ -928,6 +930,13 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@tailwindcss/forms": {
|
||||
"version": "0.5.10",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz",
|
||||
@@ -1426,6 +1435,24 @@
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/deepmerge": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||
@@ -1496,6 +1523,30 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
|
||||
"integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
@@ -1992,6 +2043,19 @@
|
||||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
},
|
||||
"node_modules/laravel-echo": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-2.1.7.tgz",
|
||||
"integrity": "sha512-EMcRmI/hJhea+eCeyJY9e7gkdVVZ42kGyntKZuM3NxeR00Glu45Cpsr0kNz4QC09YCQd48LZjQA1xSTtYteTwg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pusher-js": "*",
|
||||
"socket.io-client": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/laravel-vite-plugin": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.3.0.tgz",
|
||||
@@ -2156,6 +2220,13 @@
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
@@ -2489,6 +2560,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pusher-js": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0.tgz",
|
||||
"integrity": "sha512-wp3HqIIUc1GRyu1XrP6m2dgyE9MoCsXVsWNlohj0rjSkLf+a0jLvEyVubdg58oMk7bhjBWnFClgp8jfAa6Ak4Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tweetnacl": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||
@@ -2757,6 +2837,36 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
|
||||
"integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.6.1",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
@@ -2987,6 +3097,12 @@
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
|
||||
@@ -3231,6 +3347,37 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
|
||||
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^7.0.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.0.0",
|
||||
"@fortawesome/vue-fontawesome": "^3.1.1"
|
||||
"@fortawesome/vue-fontawesome": "^3.1.1",
|
||||
"laravel-echo": "^2.1.7",
|
||||
"pusher-js": "^8.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}.tippy-box[data-theme~=light]{color:#26323d;box-shadow:0 0 20px 4px #9aa1b126,0 4px 80px -8px #24282f40,0 4px 4px -2px #5b5e6926;background-color:#fff}.tippy-box[data-theme~=light][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=light][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff}.tippy-box[data-theme~=light][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=light][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff}.tippy-box[data-theme~=light]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=light]>.tippy-svg-arrow{fill:#fff}
|
||||
.fi-pagination-items,.fi-pagination-overview,.fi-pagination-records-per-page-select:not(.fi-compact){display:none}@supports (container-type:inline-size){.fi-pagination{container-type:inline-size}@container (min-width: 28rem){.fi-pagination-records-per-page-select.fi-compact{display:none}.fi-pagination-records-per-page-select:not(.fi-compact){display:inline}}@container (min-width: 56rem){.fi-pagination:not(.fi-simple)>.fi-pagination-previous-btn{display:none}.fi-pagination-overview{display:inline}.fi-pagination:not(.fi-simple)>.fi-pagination-next-btn{display:none}.fi-pagination-items{display:flex}}}@supports not (container-type:inline-size){@media (min-width:640px){.fi-pagination-records-per-page-select.fi-compact{display:none}.fi-pagination-records-per-page-select:not(.fi-compact){display:inline}}@media (min-width:768px){.fi-pagination:not(.fi-simple)>.fi-pagination-previous-btn{display:none}.fi-pagination-overview{display:inline}.fi-pagination:not(.fi-simple)>.fi-pagination-next-btn{display:none}.fi-pagination-items{display:flex}}}.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{background-color:#333;border-radius:4px;color:#fff;font-size:14px;line-height:1.4;outline:0;position:relative;transition-property:transform,visibility,opacity;white-space:normal}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{border-top-color:initial;border-width:8px 8px 0;bottom:-7px;left:0;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:initial;border-width:0 8px 8px;left:0;top:-7px;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-left-color:initial;border-width:8px 0 8px 8px;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{border-right-color:initial;border-width:8px 8px 8px 0;left:-7px;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{color:#333;height:16px;width:16px}.tippy-arrow:before{border-color:transparent;border-style:solid;content:"";position:absolute}.tippy-content{padding:5px 9px;position:relative;z-index:1}.tippy-box[data-theme~=light]{background-color:#fff;box-shadow:0 0 20px 4px #9aa1b126,0 4px 80px -8px #24282f40,0 4px 4px -2px #5b5e6926;color:#26323d}.tippy-box[data-theme~=light][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=light][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff}.tippy-box[data-theme~=light][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=light][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff}.tippy-box[data-theme~=light]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=light]>.tippy-svg-arrow{fill:#fff}.fi-sortable-ghost{opacity:.3}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
function i({state:o}){return{state:o,rows:[],shouldUpdateRows:!0,init:function(){this.updateRows(),this.rows.length<=0&&this.addRow(),this.shouldUpdateRows=!0,this.$watch("state",()=>{if(!this.shouldUpdateRows){this.shouldUpdateRows=!0;return}this.updateRows()})},addRow:function(){this.rows.push({key:"",value:""}),this.updateState()},deleteRow:function(t){this.rows.splice(t,1),this.rows.length<=0&&this.addRow(),this.updateState(),this.shouldUpdateRows=!0},reorderRows:function(t){let e=Alpine.raw(this.rows),s=e.splice(t.oldIndex,1)[0];e.splice(t.newIndex,0,s),this.rows=e,this.updateState()},updateRows:function(){let t=[];for(let[e,s]of Object.entries(this.state??{}))t.push({key:e,value:s});this.rows=t},updateState:function(){let t={};this.rows.forEach(e=>{e.key===""||e.key===null||(t[e.key]=e.value)}),this.shouldUpdateRows=!1,this.state=t}}}export{i as default};
|
||||
function r({state:o}){return{state:o,rows:[],shouldUpdateRows:!0,init:function(){this.updateRows(),this.rows.length<=0?this.rows.push({key:"",value:""}):this.updateState(),this.$watch("state",(t,e)=>{let s=i=>i===null?0:Array.isArray(i)?i.length:typeof i!="object"?0:Object.keys(i).length;s(t)===0&&s(e)===0||this.updateRows()})},addRow:function(){this.rows.push({key:"",value:""}),this.updateState()},deleteRow:function(t){this.rows.splice(t,1),this.rows.length<=0&&this.addRow(),this.updateState()},reorderRows:function(t){let e=Alpine.raw(this.rows);this.rows=[];let s=e.splice(t.oldIndex,1)[0];e.splice(t.newIndex,0,s),this.$nextTick(()=>{this.rows=e,this.updateState()})},updateRows:function(){if(!this.shouldUpdateRows){this.shouldUpdateRows=!0;return}let t=[];for(let[e,s]of Object.entries(this.state??{}))t.push({key:e,value:s});this.rows=t},updateState:function(){let t={};this.rows.forEach(e=>{e.key===""||e.key===null||(t[e.key]=e.value)}),this.shouldUpdateRows=!1,this.state=t}}}export{r as default};
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
function i({state:a,splitKeys:n}){return{newTag:"",state:a,createTag:function(){if(this.newTag=this.newTag.trim(),this.newTag!==""){if(this.state.includes(this.newTag)){this.newTag="";return}this.state.push(this.newTag),this.newTag=""}},deleteTag:function(t){this.state=this.state.filter(e=>e!==t)},input:{["x-on:blur"]:"createTag()",["x-model"]:"newTag",["x-on:keydown"](t){["Enter",...n].includes(t.key)&&(t.preventDefault(),t.stopPropagation(),this.createTag())},["x-on:paste"](){$nextTick(()=>{let t=n.map(e=>e.replace(/[/\-\\^$*+?.()|[\]{}]/g,"\\$&")).join("|");this.newTag.split(new RegExp(t,"g")).forEach(e=>{this.newTag=e,this.createTag()})})}}}}export{i as default};
|
||||
function i({state:a,splitKeys:n}){return{newTag:"",state:a,createTag:function(){if(this.newTag=this.newTag.trim(),this.newTag!==""){if(this.state.includes(this.newTag)){this.newTag="";return}this.state.push(this.newTag),this.newTag=""}},deleteTag:function(t){this.state=this.state.filter(e=>e!==t)},reorderTags:function(t){let e=this.state.splice(t.oldIndex,1)[0];this.state.splice(t.newIndex,0,e),this.state=[...this.state]},input:{"x-on:blur":"createTag()","x-model":"newTag","x-on:keydown"(t){["Enter",...n].includes(t.key)&&(t.preventDefault(),t.stopPropagation(),this.createTag())},"x-on:paste"(){this.$nextTick(()=>{if(n.length===0){this.createTag();return}let t=n.map(e=>e.replace(/[/\-\\^$*+?.()|[\]{}]/g,"\\$&")).join("|");this.newTag.split(new RegExp(t,"g")).forEach(e=>{this.newTag=e,this.createTag()})})}}}}export{i as default};
|
||||
|
||||
@@ -1 +1 @@
|
||||
function t({initialHeight:e}){return{render:function(){this.$el.scrollHeight>0&&(this.$el.style.height=e+"rem",this.$el.style.height=this.$el.scrollHeight+"px")}}}export{t as default};
|
||||
function r({initialHeight:t,shouldAutosize:i,state:s}){return{state:s,wrapperEl:null,init:function(){this.wrapperEl=this.$el.parentNode,this.setInitialHeight(),i?this.$watch("state",()=>{this.resize()}):this.setUpResizeObserver()},setInitialHeight:function(){this.$el.scrollHeight<=0||(this.wrapperEl.style.height=t+"rem")},resize:function(){if(this.setInitialHeight(),this.$el.scrollHeight<=0)return;let e=this.$el.scrollHeight+"px";this.wrapperEl.style.height!==e&&(this.wrapperEl.style.height=e)},setUpResizeObserver:function(){new ResizeObserver(()=>{this.wrapperEl.style.height=this.$el.style.height}).observe(this.$el)}}}export{r as default};
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/js/filament/tables/components/table.js
Normal file
1
public/js/filament/tables/components/table.js
Normal file
@@ -0,0 +1 @@
|
||||
function d(){return{checkboxClickController:null,collapsedGroups:[],isLoading:!1,selectedRecords:[],shouldCheckUniqueSelection:!0,lastCheckedRecord:null,livewireId:null,init:function(){this.livewireId=this.$root.closest("[wire\\:id]").attributes["wire:id"].value,this.$wire.$on("deselectAllTableRecords",()=>this.deselectAllRecords()),this.$watch("selectedRecords",()=>{if(!this.shouldCheckUniqueSelection){this.shouldCheckUniqueSelection=!0;return}this.selectedRecords=[...new Set(this.selectedRecords)],this.shouldCheckUniqueSelection=!1}),this.$nextTick(()=>this.watchForCheckboxClicks()),Livewire.hook("element.init",({component:e})=>{e.id===this.livewireId&&this.watchForCheckboxClicks()})},mountAction:function(e,t=null){this.$wire.set("selectedTableRecords",this.selectedRecords,!1),this.$wire.mountTableAction(e,t)},mountBulkAction:function(e){this.$wire.set("selectedTableRecords",this.selectedRecords,!1),this.$wire.mountTableBulkAction(e)},toggleSelectRecordsOnPage:function(){let e=this.getRecordsOnPage();if(this.areRecordsSelected(e)){this.deselectRecords(e);return}this.selectRecords(e)},toggleSelectRecordsInGroup:async function(e){this.isLoading=!0;let t=await this.$wire.getGroupedSelectableTableRecordKeys(e);this.areRecordsSelected(this.getRecordsInGroupOnPage(e))?this.deselectRecords(t):this.selectRecords(t),this.isLoading=!1},getRecordsInGroupOnPage:function(e){let t=[];for(let s of this.$root?.getElementsByClassName("fi-ta-record-checkbox")??[])s.dataset.group===e&&t.push(s.value);return t},getRecordsOnPage:function(){let e=[];for(let t of this.$root?.getElementsByClassName("fi-ta-record-checkbox")??[])e.push(t.value);return e},selectRecords:function(e){for(let t of e)this.isRecordSelected(t)||this.selectedRecords.push(t)},deselectRecords:function(e){for(let t of e){let s=this.selectedRecords.indexOf(t);s!==-1&&this.selectedRecords.splice(s,1)}},selectAllRecords:async function(){this.isLoading=!0,this.selectedRecords=await this.$wire.getAllSelectableTableRecordKeys(),this.isLoading=!1},deselectAllRecords:function(){this.selectedRecords=[]},isRecordSelected:function(e){return this.selectedRecords.includes(e)},areRecordsSelected:function(e){return e.every(t=>this.isRecordSelected(t))},toggleCollapseGroup:function(e){if(this.isGroupCollapsed(e)){this.collapsedGroups.splice(this.collapsedGroups.indexOf(e),1);return}this.collapsedGroups.push(e)},isGroupCollapsed:function(e){return this.collapsedGroups.includes(e)},resetCollapsedGroups:function(){this.collapsedGroups=[]},watchForCheckboxClicks:function(){this.checkboxClickController&&this.checkboxClickController.abort(),this.checkboxClickController=new AbortController;let{signal:e}=this.checkboxClickController;this.$root?.addEventListener("click",t=>t.target?.matches(".fi-ta-record-checkbox")&&this.handleCheckboxClick(t,t.target),{signal:e})},handleCheckboxClick:function(e,t){if(!this.lastChecked){this.lastChecked=t;return}if(e.shiftKey){let s=Array.from(this.$root?.getElementsByClassName("fi-ta-record-checkbox")??[]);if(!s.includes(this.lastChecked)){this.lastChecked=t;return}let l=s.indexOf(this.lastChecked),r=s.indexOf(t),o=[l,r].sort((c,n)=>c-n),i=[];for(let c=o[0];c<=o[1];c++)s[c].checked=t.checked,i.push(s[c].value);t.checked?this.selectRecords(i):this.deselectRecords(i)}this.lastChecked=t}}}export{d as default};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3,12 +3,20 @@
|
||||
<div class="bg-white p-6 rounded-lg shadow-lg text-center flex flex-col items-center">
|
||||
<div class="loader ease-linear rounded-full border-4 border-t-4 border-gray-200 h-12 w-12 mb-4"></div>
|
||||
<p class="text-gray-700 text-lg">{{ __('loading_spinner.processing_image') }}</p>
|
||||
<p v-if="progress > 0" class="text-gray-700 text-sm mt-2">{{ progress }}%</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// No script logic needed for a simple spinner
|
||||
import { defineProps } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
progress: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
@delete="deleteStyledImage"
|
||||
/>
|
||||
|
||||
<LoadingSpinner v-if="isLoading" />
|
||||
<LoadingSpinner v-if="isLoading" :progress="processingProgress" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -79,6 +79,8 @@ const currentOverlayComponent = ref(null); // null, 'contextMenu', 'styleSelecto
|
||||
const contextMenuPosition = ref({ x: 0, y: 0 });
|
||||
const selectedImage = ref(null);
|
||||
const styledImage = ref(null); // To store the newly styled image
|
||||
const processingImageUuid = ref(null); // To store the UUID of the image being processed
|
||||
const processingProgress = ref(0); // To store the progress percentage
|
||||
const errorMessage = ref(null); // New ref for error messages
|
||||
const isLoading = ref(false); // New ref for loading state
|
||||
const currentTheme = ref('light'); // New ref for current theme
|
||||
@@ -138,23 +140,91 @@ const applyStyle = (style, imageId) => {
|
||||
console.log('Applying style:', style.title, 'to image:', imageId);
|
||||
currentOverlayComponent.value = null; // Close style selector immediately
|
||||
isLoading.value = true; // Show loading spinner
|
||||
processingImageUuid.value = selectedImage.value.uuid; // Set the UUID of the image being processed
|
||||
processingProgress.value = 0; // Reset progress
|
||||
|
||||
axios.post('/api/images/style-change', {
|
||||
image_id: imageId,
|
||||
style_id: style.id,
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Style change request successful:', response.data);
|
||||
styledImage.value = response.data.styled_image;
|
||||
currentOverlayComponent.value = 'styledImageDisplay';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error applying style:', error);
|
||||
showError(error.response?.data?.error || 'Failed to apply style.');
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading.value = false; // Hide loading spinner
|
||||
});
|
||||
axios.get('/api/comfyui-url')
|
||||
.then(response => {
|
||||
const comfyUiBaseUrl = response.data.comfyui_url;
|
||||
const wsUrl = `ws://${new URL(comfyUiBaseUrl).host}/ws`;
|
||||
const ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('WebSocket connected to ComfyUI.');
|
||||
// Send prompt to ComfyUI via HTTP, then listen for progress via WS
|
||||
axios.post('/api/images/style-change', {
|
||||
image_id: imageId,
|
||||
style_id: style.id,
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Style change request sent:', response.data);
|
||||
// Store the prompt_id from the backend response
|
||||
const promptId = response.data.prompt_id;
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const message = JSON.parse(event.data);
|
||||
if (message.type === 'progress') {
|
||||
console.log('ComfyUI Progress Message:', message);
|
||||
const { value, max } = message.data;
|
||||
const progress = (max > 0) ? (value / max) * 100 : 0;
|
||||
if (message.data.prompt_id === promptId) {
|
||||
processingProgress.value = progress;
|
||||
|
||||
if (processingProgress.value >= 100) {
|
||||
console.log('Frontend: Progress reached 100%. Attempting to fetch final image.', { promptId: promptId });
|
||||
// Fetch the final styled image from the backend
|
||||
axios.get(`/api/images/fetch-styled/${promptId}`)
|
||||
.then(imageResponse => {
|
||||
console.log('Frontend: Successfully fetched styled image.', imageResponse.data);
|
||||
styledImage.value = imageResponse.data.styled_image;
|
||||
currentOverlayComponent.value = 'styledImageDisplay';
|
||||
fetchImages(); // Refresh gallery
|
||||
})
|
||||
.catch(imageError => {
|
||||
console.error('Frontend: Error fetching styled image:', imageError.response?.data?.error || imageError.message);
|
||||
showError(imageError.response?.data?.error || 'Failed to fetch styled image.');
|
||||
})
|
||||
.finally(() => {
|
||||
console.log('Frontend: Final fetch process completed.');
|
||||
isLoading.value = false;
|
||||
processingImageUuid.value = null;
|
||||
processingProgress.value = 0;
|
||||
ws.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn('Received unexpected WebSocket message type:', message.type, message);
|
||||
}
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error applying style:', error);
|
||||
showError(error.response?.data?.error || 'Failed to apply style.');
|
||||
isLoading.value = false;
|
||||
processingImageUuid.value = null;
|
||||
processingProgress.value = 0;
|
||||
ws.close();
|
||||
});
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket error:', error);
|
||||
showError('WebSocket connection error.');
|
||||
isLoading.value = false;
|
||||
processingImageUuid.value = null;
|
||||
processingProgress.value = 0;
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('WebSocket closed.');
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching ComfyUI URL:', error);
|
||||
showError(error.response?.data?.error || 'Failed to get ComfyUI URL.');
|
||||
isLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const keepStyledImage = (imageToKeep) => {
|
||||
|
||||
6
resources/js/bootstrap.js
vendored
6
resources/js/bootstrap.js
vendored
@@ -9,6 +9,12 @@ window.axios = axios;
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/**
|
||||
* Echo exposes an expressive API for subscribing to channels and listening
|
||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
||||
* allows your team to easily build robust real-time web applications.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Echo exposes an expressive API for subscribing to channels and listening
|
||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
||||
|
||||
@@ -15,4 +15,8 @@ return [
|
||||
'navigation.next' => 'Weiter',
|
||||
'navigation.page_of' => 'Seite :currentPage von :totalPages',
|
||||
'loading_spinner.processing_image' => 'Bild wird verarbeitet...',
|
||||
'styled_image_display.title' => 'Neu gestyltes Bild',
|
||||
'styled_image_display.keep_button' => 'Behalten',
|
||||
'styled_image_display.delete_button' => 'Löschen',
|
||||
|
||||
];
|
||||
|
||||
@@ -104,11 +104,6 @@ return [
|
||||
'delete' => 'Löschen',
|
||||
],
|
||||
],
|
||||
'styled_image_display' => [
|
||||
'title' => 'Neu gestyltes Bild',
|
||||
'keep_button' => 'Behalten',
|
||||
'delete_button' => 'Löschen',
|
||||
],
|
||||
'user' => [
|
||||
'navigation' => [
|
||||
'group' => 'Benutzerverwaltung',
|
||||
|
||||
@@ -15,4 +15,7 @@ return [
|
||||
'navigation.next' => 'Next',
|
||||
'navigation.page_of' => 'Page :currentPage of :totalPages',
|
||||
'loading_spinner.processing_image' => 'Processing image...',
|
||||
'styled_image_display.title' => 'Newly Styled Image',
|
||||
'styled_image_display.keep_button' => 'Keep',
|
||||
'styled_image_display.delete_button' => 'Delete',
|
||||
];
|
||||
|
||||
@@ -103,11 +103,6 @@ return [
|
||||
],
|
||||
],
|
||||
],
|
||||
'styled_image_display' => [
|
||||
'title' => 'Newly Styled Image',
|
||||
'keep_button' => 'Keep',
|
||||
'delete_button' => 'Delete',
|
||||
],
|
||||
'loading_spinner' => [
|
||||
'processing_image' => 'Processing image...',
|
||||
],
|
||||
|
||||
@@ -28,10 +28,12 @@ Route::post('/admin/navigation-state', [NavigationStateController::class, 'store
|
||||
Route::get('/images', [ImageController::class, 'index']);
|
||||
Route::get('/styles', [StyleController::class, 'index']);
|
||||
Route::post('/images/style-change', [ImageController::class, 'styleChangeRequest']);
|
||||
Route::get('/comfyui-url', [ImageController::class, 'getComfyUiUrl']);
|
||||
|
||||
Route::middleware('auth:sanctum')->group(function () {
|
||||
Route::post('/images/keep', [ImageController::class, 'keepImage']);
|
||||
Route::delete('/images/{image}', [ImageController::class, 'deleteImage']);
|
||||
Route::get('/images/status', [ImageController::class, 'getStatus']);
|
||||
Route::get('/images/progress', [ImageController::class, 'getProgress']);
|
||||
});
|
||||
|
||||
Route::get('/images/fetch-styled/{prompt_id}', [ImageController::class, 'fetchStyledImage']);
|
||||
|
||||
Reference in New Issue
Block a user