From 1860c223206d8203e75ac2f1190be46d2307eb7e Mon Sep 17 00:00:00 2001 From: Desktop Date: Wed, 12 Nov 2025 06:01:49 +0500 Subject: [PATCH] progress bar issues --- backend/igny8_core/ai/tasks.py | 140 ++++++++++++++++-- .../src/components/common/ImageQueueModal.tsx | 17 ++- 2 files changed, 140 insertions(+), 17 deletions(-) diff --git a/backend/igny8_core/ai/tasks.py b/backend/igny8_core/ai/tasks.py index 255369cf..2b1d3af1 100644 --- a/backend/igny8_core/ai/tasks.py +++ b/backend/igny8_core/ai/tasks.py @@ -177,7 +177,9 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None logger.info(f"[process_image_generation_queue] Full config: {config}") provider = config.get('provider', 'openai') - model = config.get('model', 'dall-e-3') + # FORCE DALL-E 2 ONLY FOR NOW + model = 'dall-e-2' + logger.info(f"[process_image_generation_queue] FORCED MODEL: {model} (ignoring config model: {config.get('model', 'dall-e-3')})") image_type = config.get('image_type', 'realistic') image_format = config.get('image_format', 'webp') desktop_enabled = config.get('desktop_enabled', True) @@ -249,7 +251,7 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None # Process each image sequentially for index, image_id in enumerate(image_ids, 1): try: - # Update task meta: current image processing + # Update task meta: current image processing (starting at 0%) self.update_state( state='PROGRESS', meta={ @@ -259,6 +261,7 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None 'failed': failed, 'status': 'processing', 'current_image_id': image_id, + 'current_image_progress': 0, 'results': results } ) @@ -436,6 +439,21 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None logger.info(f"[process_image_generation_queue] Final prompt length: {len(formatted_prompt)}") logger.info(f"[process_image_generation_queue] Image type: {image_type}") + # Update progress: Starting image generation (0%) + self.update_state( + state='PROGRESS', + meta={ + 'current_image': index, + 'total_images': total_images, + 'completed': completed, + 'failed': failed, + 'status': 'processing', + 'current_image_id': image_id, + 'current_image_progress': 0, + 'results': results + } + ) + result = ai_core.generate_image( prompt=formatted_prompt, provider=provider, @@ -446,6 +464,21 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None function_name='generate_images_from_prompts' ) + # Update progress: Image generation complete (50%) + self.update_state( + state='PROGRESS', + meta={ + 'current_image': index, + 'total_images': total_images, + 'completed': completed, + 'failed': failed, + 'status': 'processing', + 'current_image_id': image_id, + 'current_image_progress': 50, + 'results': results + } + ) + logger.info(f"[process_image_generation_queue] Image generation result: has_url={bool(result.get('url'))}, has_error={bool(result.get('error'))}") # Check for errors @@ -478,6 +511,71 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None logger.info(f"[process_image_generation_queue] Image {image_id} - URL received: {image_url[:100] if image_url else 'None'}...") logger.info(f"[process_image_generation_queue] Image {image_id} - URL length: {len(image_url) if image_url else 0} characters") + # Update progress: Downloading image (75%) + self.update_state( + state='PROGRESS', + meta={ + 'current_image': index, + 'total_images': total_images, + 'completed': completed, + 'failed': failed, + 'status': 'processing', + 'current_image_id': image_id, + 'current_image_progress': 75, + 'results': results + } + ) + + # Download and save image to /data/app/images + saved_file_path = None + if image_url: + try: + import os + import requests + from django.conf import settings + + # Create /data/app/images directory if it doesn't exist + images_dir = '/data/app/images' + os.makedirs(images_dir, exist_ok=True) + logger.info(f"[process_image_generation_queue] Image {image_id} - Created/verified directory: {images_dir}") + + # Generate filename: image_{image_id}_{timestamp}.png + import time + timestamp = int(time.time()) + filename = f"image_{image_id}_{timestamp}.png" + file_path = os.path.join(images_dir, filename) + + # Download image + logger.info(f"[process_image_generation_queue] Image {image_id} - Downloading from: {image_url[:100]}...") + response = requests.get(image_url, timeout=60) + response.raise_for_status() + + # Save to file + with open(file_path, 'wb') as f: + f.write(response.content) + + saved_file_path = file_path + logger.info(f"[process_image_generation_queue] Image {image_id} - Saved to: {file_path} ({len(response.content)} bytes)") + + except Exception as download_error: + logger.error(f"[process_image_generation_queue] Image {image_id} - Failed to download/save image: {download_error}", exc_info=True) + # Continue with URL only if download fails + + # Update progress: Saving to database (90%) + self.update_state( + state='PROGRESS', + meta={ + 'current_image': index, + 'total_images': total_images, + 'completed': completed, + 'failed': failed, + 'status': 'processing', + 'current_image_id': image_id, + 'current_image_progress': 90, + 'results': results + } + ) + # Log URL length for debugging (model field now supports up to 500 chars) if image_url and len(image_url) > 500: logger.error(f"[process_image_generation_queue] Image {image_id} - URL TOO LONG: {len(image_url)} chars (max 500). URL: {image_url[:150]}...") @@ -489,22 +587,20 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None logger.info(f"[process_image_generation_queue] Image {image_id} - URL length {len(image_url)} chars (was limited to 200, now supports 500)") try: - # Try to save - if URL is too long, this will fail - image.image_url = image_url + # Save file path if available, otherwise save URL + if saved_file_path: + # Store relative path or full path in image_url field + image.image_url = saved_file_path + else: + image.image_url = image_url image.status = 'generated' - logger.info(f"[process_image_generation_queue] Image {image_id} - Attempting to save to database with URL length: {len(image_url) if image_url else 0}") + logger.info(f"[process_image_generation_queue] Image {image_id} - Attempting to save to database") image.save(update_fields=['image_url', 'status']) logger.info(f"[process_image_generation_queue] Image {image_id} - Successfully saved to database") except Exception as save_error: error_str = str(save_error) logger.error(f"[process_image_generation_queue] Image {image_id} - Database save FAILED: {error_str}", exc_info=True) logger.error(f"[process_image_generation_queue] Image {image_id} - Error type: {type(save_error).__name__}") - logger.error(f"[process_image_generation_queue] Image {image_id} - URL that failed: {image_url[:200] if image_url else 'None'}...") - logger.error(f"[process_image_generation_queue] Image {image_id} - URL length: {len(image_url) if image_url else 0}") - - # Check if it's a length-related error - if 'too long' in error_str.lower() or 'varying' in error_str.lower() or '200' in error_str: - logger.error(f"[process_image_generation_queue] Image {image_id} - CONFIRMED: URL length issue. URLField max_length=200, but URL is {len(image_url) if image_url else 0} chars") # Continue even if save fails, but mark as failed in results # Truncate error message to 180 chars to avoid same issue when saving error @@ -516,10 +612,30 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None }) failed += 1 else: + # Update progress: Complete (100%) + self.update_state( + state='PROGRESS', + meta={ + 'current_image': index, + 'total_images': total_images, + 'completed': completed + 1, + 'failed': failed, + 'status': 'processing', + 'current_image_id': image_id, + 'current_image_progress': 100, + 'results': results + [{ + 'image_id': image_id, + 'status': 'completed', + 'image_url': saved_file_path or image_url, + 'revised_prompt': result.get('revised_prompt') + }] + } + ) + results.append({ 'image_id': image_id, 'status': 'completed', - 'image_url': result.get('url'), + 'image_url': saved_file_path or image_url, 'revised_prompt': result.get('revised_prompt') }) completed += 1 diff --git a/frontend/src/components/common/ImageQueueModal.tsx b/frontend/src/components/common/ImageQueueModal.tsx index a32ad89e..a6ddf3b2 100644 --- a/frontend/src/components/common/ImageQueueModal.tsx +++ b/frontend/src/components/common/ImageQueueModal.tsx @@ -183,7 +183,7 @@ export default function ImageQueueModal({ }, [isOpen, taskId]); const updateQueueFromTaskMeta = (meta: any) => { - const { current_image, total_images, completed, failed, results } = meta; + const { current_image, total_images, completed, failed, results, current_image_progress, current_image_id } = meta; setLocalQueue(prevQueue => { return prevQueue.map((item, index) => { @@ -196,18 +196,25 @@ export default function ImageQueueModal({ result.status === 'failed' ? 'failed' : 'processing', progress: result.status === 'completed' ? 100 : result.status === 'failed' ? 0 : + // Use current_image_progress if this is the current image being processed + (current_image_id === item.imageId && current_image_progress !== undefined) ? current_image_progress : index + 1 < current_image ? 100 : - index + 1 === current_image ? 50 : 0, + index + 1 === current_image ? 0 : 0, imageUrl: result.image_url || item.imageUrl, error: result.error || null }; } - // Update based on current_image index + // Update based on current_image index and progress if (index + 1 < current_image) { + // Already completed return { ...item, status: 'completed', progress: 100 }; - } else if (index + 1 === current_image) { - return { ...item, status: 'processing', progress: 50 }; + } else if (index + 1 === current_image || current_image_id === item.imageId) { + // Currently processing - use current_image_progress if available + const progress = (current_image_progress !== undefined && current_image_id === item.imageId) + ? current_image_progress + : 0; + return { ...item, status: 'processing', progress }; } return item;