diff --git a/modules/workflows/methods/methodAi/actions/process.py b/modules/workflows/methods/methodAi/actions/process.py index ee1079fb..b8f81465 100644 --- a/modules/workflows/methods/methodAi/actions/process.py +++ b/modules/workflows/methods/methodAi/actions/process.py @@ -60,21 +60,28 @@ async def process(self, parameters: Dict[str, Any]) -> ActionResult: logger.error(f"Invalid documentList type: {type(documentListParam)}") documentList = DocumentReferenceList(references=[]) - resultType = parameters.get("resultType", "txt") + # Optional: if omitted, formats determined from prompt. Default "txt" is validation fallback only. + resultType = parameters.get("resultType") simpleMode = parameters.get("simpleMode", False) - if not aiPrompt: logger.error(f"aiPrompt is missing or empty. Parameters: {parameters}") return ActionResult.isFailure( error="AI prompt is required" ) - # Determine output extension and default MIME type without duplicating service logic - normalized_result_type = (str(resultType).strip().lstrip('.').lower() or "txt") - output_extension = f".{normalized_result_type}" - output_mime_type = "application/octet-stream" # Prefer service-provided mimeType when available - logger.info(f"Using result type: {resultType} -> {output_extension}, simpleMode: {simpleMode}") + # Handle optional resultType: if None, formats determined from prompt by AI + if resultType: + normalized_result_type = (str(resultType).strip().lstrip('.').lower() or "txt") + output_extension = f".{normalized_result_type}" + output_format = output_extension.replace('.', '') or 'txt' + logger.info(f"Using result type: {resultType} -> {output_extension}, simpleMode: {simpleMode}") + else: + # No format specified - AI will determine formats from prompt + normalized_result_type = None + output_extension = None + output_format = None + logger.debug("resultType not provided - formats will be determined from prompt by AI") output_mime_type = "application/octet-stream" # Prefer service-provided mimeType when available @@ -96,8 +103,8 @@ async def process(self, parameters: Dict[str, Any]) -> ActionResult: # Update progress - preparing AI call self.services.chat.progressLogUpdate(operationId, 0.4, "Preparing AI call") - # Build options - output_format = output_extension.replace('.', '') or 'txt' + # Build output format for simple mode + output_format_for_call = output_extension.replace('.', '') if output_extension else (output_format or 'txt') # Simple mode: fast path without document generation pipeline if simpleMode: @@ -132,7 +139,7 @@ async def process(self, parameters: Dict[str, Any]) -> ActionResult: prompt=aiPrompt, context=context_text if context_text else None, options=AiCallOptions( - resultFormat=output_format, + resultFormat=output_format_for_call, operationType=OperationTypeEnum.DATA_ANALYSE, processingMode=ProcessingModeEnum.BASIC ) @@ -158,50 +165,45 @@ async def process(self, parameters: Dict[str, Any]) -> ActionResult: ) else: # Full mode: use unified callAiContent method - # For document generation (xlsx, docx, pdf, etc.), use DATA_GENERATE with document intent - from modules.datamodels.datamodelAi import OperationTypeEnum + # Detect image generation from resultType (if provided) + imageFormats = ["png", "jpg", "jpeg", "gif", "webp"] + isImageGeneration = normalized_result_type in imageFormats if normalized_result_type else False - # Always use DATA_GENERATE with document intent for ai.process - # This ensures proper document generation pipeline is used + # Build options with correct operationType + from modules.datamodels.datamodelAi import OperationTypeEnum + # resultFormat in options can be None - formats will be determined by AI if not provided options = AiCallOptions( - resultFormat=output_format, - operationType=OperationTypeEnum.DATA_GENERATE + resultFormat=output_format, # Can be None - formats determined by AI + operationType=OperationTypeEnum.IMAGE_GENERATE if isImageGeneration else OperationTypeEnum.DATA_GENERATE ) - generation_intent = "document" + + # Get generationIntent from parameters (required for DATA_GENERATE) + # Default to "document" if not provided (most common use case) + # For code generation, use ai.generateCode action or explicitly pass generationIntent="code" + generationIntent = parameters.get("generationIntent", "document") # Update progress - calling AI self.services.chat.progressLogUpdate(operationId, 0.6, "Calling AI") - # Use unified callAiContent method - # If contentParts provided (pre-extracted), use them directly - # Otherwise, pass documentList and let callAiContent handle Phases 5A-5E internally + # Use unified callAiContent method with BOTH documentList and contentParts + # Extraction is handled by AI service - no extraction here + # outputFormat: Optional - if None, formats determined from prompt by AI # Note: ContentExtracted documents (from context.extractContent) are now handled # automatically in _extractAndPrepareContent() (Phase 5B) - if contentParts: - # Pre-extracted ContentParts - use them directly - aiResponse = await self.services.ai.callAiContent( - prompt=aiPrompt, - options=options, - contentParts=contentParts, # Pre-extracted ContentParts - outputFormat=output_format, - parentOperationId=operationId, - generationIntent=generation_intent - ) - else: - # Pass documentList - callAiContent handles Phases 5A-5E internally - # This includes automatic detection of ContentExtracted documents - logger.info(f"ai.process: Calling callAiContent with {len(documentList.references)} document references") - if documentList.references: - for idx, ref in enumerate(documentList.references): - logger.info(f" Passing reference {idx + 1}: documentId={ref.documentId}") - aiResponse = await self.services.ai.callAiContent( - prompt=aiPrompt, - options=options, - documentList=documentList, # callAiContent macht Phasen 5A-5E - outputFormat=output_format, - parentOperationId=operationId, - generationIntent=generation_intent - ) + logger.info(f"ai.process: Calling callAiContent with {len(documentList.references)} document references") + if documentList.references: + for idx, ref in enumerate(documentList.references): + logger.info(f" Passing reference {idx + 1}: documentId={ref.documentId}") + + aiResponse = await self.services.ai.callAiContent( + prompt=aiPrompt, + options=options, + documentList=documentList, # Pass documentList - AI service handles extraction + contentParts=contentParts, # Pass contentParts if provided (or None) + outputFormat=output_format, # Can be None - AI determines from prompt + parentOperationId=operationId, + generationIntent=generationIntent # REQUIRED for DATA_GENERATE + ) # Update progress - processing result self.services.chat.progressLogUpdate(operationId, 0.8, "Processing result")