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.