From ce9663438b5e1c1da89444f8f295dbe8612371ad Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Tue, 11 Nov 2025 22:19:13 +0000 Subject: [PATCH] Enhance image generation functionality: Add console tracking to monitor progress and errors during image processing, and include image queue in response metadata for better integration. --- backend/igny8_core/ai/base.py | 3 +- backend/igny8_core/ai/engine.py | 4 +- .../functions/generate_images_from_prompts.py | 70 +++++++++++++++++-- .../modules/system/integration_views.py | 3 + 4 files changed, 71 insertions(+), 9 deletions(-) diff --git a/backend/igny8_core/ai/base.py b/backend/igny8_core/ai/base.py index 20f79613..0c178c9c 100644 --- a/backend/igny8_core/ai/base.py +++ b/backend/igny8_core/ai/base.py @@ -84,7 +84,8 @@ class BaseAIFunction(ABC): original_data: Any, account=None, progress_tracker=None, - step_tracker=None + step_tracker=None, + console_tracker=None ) -> Dict: """ Save parsed results to database. diff --git a/backend/igny8_core/ai/engine.py b/backend/igny8_core/ai/engine.py index 1dba4665..0b62841d 100644 --- a/backend/igny8_core/ai/engine.py +++ b/backend/igny8_core/ai/engine.py @@ -348,8 +348,8 @@ class AIEngine: return self._handle_error(error_msg, fn) # Phase 5: SAVE - Database Operations (85-98%) - # Pass step_tracker to save_output so it can add validation steps - save_result = fn.save_output(parsed, data, self.account, self.tracker, step_tracker=self.step_tracker) + # Pass step_tracker and console_tracker to save_output so it can add validation steps and log + save_result = fn.save_output(parsed, data, self.account, self.tracker, step_tracker=self.step_tracker, console_tracker=self.console_tracker) clusters_created = save_result.get('clusters_created', 0) keywords_updated = save_result.get('keywords_updated', 0) count = save_result.get('count', 0) diff --git a/backend/igny8_core/ai/functions/generate_images_from_prompts.py b/backend/igny8_core/ai/functions/generate_images_from_prompts.py index b5dfe116..90bea7e5 100644 --- a/backend/igny8_core/ai/functions/generate_images_from_prompts.py +++ b/backend/igny8_core/ai/functions/generate_images_from_prompts.py @@ -146,15 +146,24 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): original_data: Dict, account=None, progress_tracker=None, - step_tracker=None + step_tracker=None, + console_tracker=None ) -> Dict: """ Process all images sequentially and generate them. This method handles the loop and makes AI calls directly. """ + function_name = self.get_name() + + if console_tracker: + console_tracker.save(f"[{function_name}] Starting image generation queue") + images = original_data.get('images', []) if not images: - raise ValueError("No images to process") + error_msg = "[{function_name}] No images to process" + if console_tracker: + console_tracker.error('ValidationError', error_msg) + raise ValueError(error_msg) provider = original_data.get('provider', 'openai') model = original_data.get('model', 'dall-e-3') @@ -169,6 +178,9 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): images_failed = 0 errors = [] + if console_tracker: + console_tracker.prep(f"[{function_name}] Preparing {total_images} image{'s' if total_images != 1 else ''} for generation") + # Initialize image queue in meta for frontend image_queue = [] for idx, img in enumerate(images, 1): @@ -198,6 +210,9 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): initial_meta['image_queue'] = image_queue progress_tracker.update("PREP", 10, f"Preparing to generate {total_images} image{'s' if total_images != 1 else ''}", meta=initial_meta) + if console_tracker: + console_tracker.prep(f"[{function_name}] Image queue initialized with {total_images} image{'s' if total_images != 1 else ''}") + # Process each image sequentially for index, image in enumerate(images, 1): queue_item = image_queue[index - 1] @@ -216,6 +231,9 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): else: content_title = content.title or content.meta_title or "Content" + if console_tracker: + console_tracker.prep(f"[{function_name}] Processing image {index}/{total_images}: {image.image_type} for '{content_title}'") + # Format prompt using template if image_prompt_template: try: @@ -224,12 +242,18 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): image_prompt=image.prompt, image_type=image_type ) + if console_tracker: + console_tracker.prep(f"[{function_name}] Formatted prompt using template (length: {len(formatted_prompt)})") except KeyError as e: logger.warning(f"Template formatting error: {e}, using simple format") formatted_prompt = f"Create a high-quality {image_type} image: {image.prompt}" + if console_tracker: + console_tracker.prep(f"[{function_name}] Template formatting error, using fallback prompt") else: # Fallback template formatted_prompt = f"Create a high-quality {image_type} image: {image.prompt}" + if console_tracker: + console_tracker.prep(f"[{function_name}] Using fallback prompt template") # Update progress: PREP phase for this image if progress_tracker and step_tracker: @@ -261,6 +285,9 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): # Generate image (this is the actual API call) # Frontend will simulate smooth progress from 50% to 95% while waiting + if console_tracker: + console_tracker.ai_call(f"[{function_name}] Calling {provider}/{model} API for image {index}/{total_images}") + result = ai_core.generate_image( prompt=formatted_prompt, provider=provider, @@ -286,11 +313,14 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): image.status = 'failed' image.save(update_fields=['status', 'updated_at']) - error_msg = f"Image {index} failed: {result['error']}" + error_msg = f"[{function_name}] Image {index}/{total_images} failed: {result['error']}" errors.append(error_msg) images_failed += 1 logger.error(f"Image generation failed for image {image.id}: {result['error']}") + if console_tracker: + console_tracker.error('ImageGenerationError', error_msg) + if progress_tracker and step_tracker: parse_msg = f"Image {index} failed: {result['error']}" step_tracker.add_response_step("PARSE", "error", parse_msg) @@ -311,11 +341,14 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): image.status = 'failed' image.save(update_fields=['status', 'updated_at']) - error_msg = f"Image {index} failed: No URL returned" + error_msg = f"[{function_name}] Image {index}/{total_images} failed: No URL returned" errors.append(error_msg) images_failed += 1 logger.error(f"No image URL returned for image {image.id}") + if console_tracker: + console_tracker.error('ImageGenerationError', error_msg) + if progress_tracker and step_tracker: parse_msg = f"Image {index} failed: No URL returned" step_tracker.add_response_step("PARSE", "error", parse_msg) @@ -336,6 +369,9 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): progress_pct = 70 + int((index - 1) / total_images * 15) # 70-85% for PARSE progress_tracker.update("PARSE", progress_pct, parse_msg, meta=meta) + if console_tracker: + console_tracker.parse(f"[{function_name}] Image {index}/{total_images} generated successfully: {image_url[:50]}...") + # Update image record with transaction.atomic(): image.image_url = image_url @@ -349,6 +385,9 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): images_generated += 1 logger.info(f"Image {image.id} ({image.image_type}) generated successfully: {image_url}") + if console_tracker: + console_tracker.save(f"[{function_name}] Saved image {index}/{total_images} to database (ID: {image.id})") + # Update progress: SAVE phase if progress_tracker and step_tracker: save_msg = f"Saved image {index} of {total_images}" @@ -360,21 +399,40 @@ class GenerateImagesFromPromptsFunction(BaseAIFunction): except Exception as e: # Mark as failed + queue_item['status'] = 'failed' + queue_item['progress'] = 100 + queue_item['error'] = str(e) with transaction.atomic(): image.status = 'failed' image.save(update_fields=['status', 'updated_at']) - error_msg = f"Image {index} failed: {str(e)}" + error_msg = f"[{function_name}] Image {index}/{total_images} exception: {str(e)}" errors.append(error_msg) images_failed += 1 logger.error(f"Exception generating image {image.id}: {str(e)}", exc_info=True) + + if console_tracker: + console_tracker.error('Exception', error_msg) + continue # Final progress update if progress_tracker and step_tracker: final_msg = f"Generated {images_generated} of {total_images} images" step_tracker.add_request_step("SAVE", "success", final_msg) - progress_tracker.update("SAVE", 98, final_msg, meta=step_tracker.get_meta()) + meta = step_tracker.get_meta() + meta['image_queue'] = image_queue + progress_tracker.update("SAVE", 98, final_msg, meta=meta) + + if console_tracker: + if images_generated > 0: + console_tracker.save(f"[{function_name}] SUCCESS: Generated {images_generated}/{total_images} image{'s' if images_generated != 1 else ''} successfully") + if images_failed > 0: + console_tracker.error('ImageGenerationError', f"[{function_name}] FAILED: {images_failed}/{total_images} image{'s' if images_failed != 1 else ''} failed") + if images_generated == total_images: + console_tracker.done(f"[{function_name}] All {total_images} image{'s' if total_images != 1 else ''} generated successfully") + else: + console_tracker.done(f"[{function_name}] Completed: {images_generated} succeeded, {images_failed} failed out of {total_images} total") return { 'count': images_generated, diff --git a/backend/igny8_core/modules/system/integration_views.py b/backend/igny8_core/modules/system/integration_views.py index eedc8a53..bef8fee0 100644 --- a/backend/igny8_core/modules/system/integration_views.py +++ b/backend/igny8_core/modules/system/integration_views.py @@ -1001,6 +1001,9 @@ class IntegrationSettingsViewSet(viewsets.ViewSet): response_meta['request_steps'] = meta['request_steps'] if 'response_steps' in meta: response_meta['response_steps'] = meta['response_steps'] + # Include image_queue if available (for image generation) + if 'image_queue' in meta: + response_meta['image_queue'] = meta['image_queue'] return Response({ 'state': task_state, 'meta': response_meta