From fa91016e1659d41fc7f7329dbff8268bfb760f10 Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Sun, 2 Nov 2025 15:36:02 +0100 Subject: [PATCH] fixed ui harmonization --- modules/services/serviceAi/mainServiceAi.py | 69 +++++++++++++++---- .../subPromptBuilderGeneration.py | 10 ++- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/modules/services/serviceAi/mainServiceAi.py b/modules/services/serviceAi/mainServiceAi.py index bd9919d5..52d53c33 100644 --- a/modules/services/serviceAi/mainServiceAi.py +++ b/modules/services/serviceAi/mainServiceAi.py @@ -197,6 +197,7 @@ Respond with ONLY a JSON object in this exact format: iteration = 0 allSections = [] # Accumulate all sections across iterations lastRawResponse = None # Store last raw JSON response for continuation + documentMetadata = None # Store document metadata (title, filename) from first iteration while iteration < maxIterations: iteration += 1 @@ -276,7 +277,11 @@ Respond with ONLY a JSON object in this exact format: pass # Flag detected, will stop in _shouldContinueGeneration # Extract sections from response (handles both valid and broken JSON) - extractedSections, wasJsonComplete = self._extractSectionsFromResponse(result, iteration, debugPrefix) + extractedSections, wasJsonComplete, parsedResult = self._extractSectionsFromResponse(result, iteration, debugPrefix) + + # Extract document metadata from first iteration if available + if iteration == 1 and parsedResult and not documentMetadata: + documentMetadata = self._extractDocumentMetadata(parsedResult) # Update progress after parsing if operationId: @@ -313,7 +318,7 @@ Respond with ONLY a JSON object in this exact format: logger.warning(f"AI call stopped after maximum iterations ({maxIterations})") # Build final result from accumulated sections - final_result = self._buildFinalResultFromSections(allSections) + final_result = self._buildFinalResultFromSections(allSections, documentMetadata) # Write final result to debug file self.services.utils.writeDebugFile(final_result, f"{debugPrefix}_final_result") @@ -325,12 +330,12 @@ Respond with ONLY a JSON object in this exact format: result: str, iteration: int, debugPrefix: str - ) -> Tuple[List[Dict[str, Any]], bool]: + ) -> Tuple[List[Dict[str, Any]], bool, Optional[Dict[str, Any]]]: """ Extract sections from AI response, handling both valid and broken JSON. Uses repair mechanism for broken JSON. Checks for "complete_response": true flag to determine completion. - Returns (sections, wasJsonComplete) + Returns (sections, wasJsonComplete, parsedResult) """ # First, try to parse as valid JSON try: @@ -345,18 +350,18 @@ Respond with ONLY a JSON object in this exact format: # If AI marked as complete, always return as complete if isComplete: - return sections, True + return sections, True, parsed_result # If in continuation mode (iteration > 1), continuation responses are expected to be fragments # A fragment with 0 extractable sections means JSON is incomplete - need another iteration if len(sections) == 0 and iteration > 1: - return sections, False # Mark as incomplete so loop continues + return sections, False, parsed_result # Mark as incomplete so loop continues # First iteration with 0 sections means empty response - stop if len(sections) == 0: - return sections, True # Complete but empty + return sections, True, parsed_result # Complete but empty - return sections, True # JSON was complete with sections + return sections, True, parsed_result # JSON was complete with sections except json.JSONDecodeError as e: # Broken JSON - try repair mechanism (normal in iterative generation) @@ -368,15 +373,15 @@ Respond with ONLY a JSON object in this exact format: if repaired_json: # Extract sections from repaired JSON sections = extractSectionsFromDocument(repaired_json) - return sections, False # JSON was broken but repaired + return sections, False, repaired_json # JSON was broken but repaired else: # Repair failed - log error logger.error(f"Iteration {iteration}: All repair strategies failed") - return [], False + return [], False, None except Exception as e: logger.error(f"Iteration {iteration}: Unexpected error during parsing: {str(e)}") - return [], False + return [], False, None def _shouldContinueGeneration( self, @@ -414,22 +419,58 @@ Respond with ONLY a JSON object in this exact format: # JSON was incomplete/broken - continue return True + def _extractDocumentMetadata( + self, + parsedResult: Dict[str, Any] + ) -> Optional[Dict[str, Any]]: + """ + Extract document metadata (title, filename) from parsed AI response. + Returns dict with 'title' and 'filename' keys if found, None otherwise. + """ + if not isinstance(parsedResult, dict): + return None + + # Try to get from documents array (preferred structure) + if "documents" in parsedResult and isinstance(parsedResult["documents"], list) and len(parsedResult["documents"]) > 0: + firstDoc = parsedResult["documents"][0] + if isinstance(firstDoc, dict): + title = firstDoc.get("title") + filename = firstDoc.get("filename") + if title or filename: + return { + "title": title, + "filename": filename + } + + return None + def _buildFinalResultFromSections( self, - allSections: List[Dict[str, Any]] + allSections: List[Dict[str, Any]], + documentMetadata: Optional[Dict[str, Any]] = None ) -> str: """ Build final JSON result from accumulated sections. + Uses AI-provided metadata (title, filename) if available. """ if not allSections: return "" + # Extract metadata from AI response if available + title = "Generated Document" + filename = "document.json" + if documentMetadata: + if documentMetadata.get("title"): + title = documentMetadata["title"] + if documentMetadata.get("filename"): + filename = documentMetadata["filename"] + # Build documents structure # Assuming single document for now documents = [{ "id": "doc_1", - "title": "Generated Document", # This should come from prompt - "filename": "document.json", + "title": title, + "filename": filename, "sections": allSections }] diff --git a/modules/services/serviceGeneration/subPromptBuilderGeneration.py b/modules/services/serviceGeneration/subPromptBuilderGeneration.py index 8c21b4e7..78e79eaa 100644 --- a/modules/services/serviceGeneration/subPromptBuilderGeneration.py +++ b/modules/services/serviceGeneration/subPromptBuilderGeneration.py @@ -74,6 +74,8 @@ async def buildGenerationPrompt( continuationText = "\n".join(continuationGuidance) if continuationGuidance else "Continue from where it stopped." + # PROMPT FOR CONTINUATION + generationPrompt = f"""User request: "{userPrompt}" The user already received part of the response. Continue generating the remaining content. @@ -93,7 +95,7 @@ Instructions: - Arrays must contain ONLY JSON values; do not include comments or ellipses. - Use ONLY the element structures shown in the template. - Continue from where it stopped — add NEW items only; do not repeat existing items. -- Generate remaining content to complete the user request. +- Generate remaining content to complete the user request. Do NOT just give an instruction or comments. Deliver the complete response. - Fill with actual content (no placeholders or instructional text such as "Add more..."). - IMPORTANT: Ensure "filename" in each document has meaningful name with appropriate extension matching the content. - When the request is fully satisfied, add "complete_response": true at root level. @@ -104,7 +106,9 @@ IMPORTANT: Before responding, analyse the remaining data to fully satisfy user r Continue generating: """ else: - # FIRST CALL - initial generation + + # PROMPT FOR FIRST CALL + generationPrompt = f"""User request: "{userPrompt}" Generate a VALID JSON response for the user request. The template below shows ONLY the structure pattern - it is NOT existing content. @@ -116,7 +120,7 @@ Instructions: - Start with {{"metadata": ...}} — return COMPLETE, STRICT JSON. - Return ONLY valid JSON (strict). No comments. No trailing commas. Use double quotes. - Do NOT reuse example section IDs; create your own. -- Generate complete content based on the user request. +- Generate complete content based on the user request. Do NOT just give an instruction or comments. Deliver the complete response. - IMPORTANT: Set a meaningful "filename" in each document with appropriate file extension (e.g., "prime_numbers.txt", "report.docx", "data.json"). The filename should reflect the content and task objective. - When the request is fully satisfied, add "complete_response": true at root level. - Output JSON only; no markdown fences or extra text.