AI Generator Loop with context added

This commit is contained in:
ValueOn AG 2025-10-18 02:49:56 +02:00
parent 1917c00721
commit 6b7094c84d
3 changed files with 103 additions and 5 deletions

View file

@ -119,9 +119,9 @@ class SubDocumentGeneration:
# Update progress - starting AI processing
progressLogger.updateProgress(operationId, 0.3, "AI processing")
# Process documents with format-specific prompt using JSON mode
# This ensures structured JSON output instead of text
aiResponseJson = await self._callAiJson(extractionPrompt, documents, options)
# Process documents with format-specific prompt using JSON mode with chunking
# This ensures structured JSON output instead of text and handles large documents
aiResponseJson = await self._callAiJsonWithChunking(extractionPrompt, documents, options, progressLogger, operationId)
# Update progress - AI processing completed
progressLogger.updateProgress(operationId, 0.6, "Processing done")
@ -648,6 +648,90 @@ class SubDocumentGeneration:
# Process documents with JSON merging
return await self.documentProcessor.processDocumentsPerChunkJson(documents, prompt, options)
async def _callAiJsonWithChunking(
self,
prompt: str,
documents: Optional[List[ChatDocument]],
options: AiCallOptions,
progressLogger,
operationId: str
) -> Dict[str, Any]:
"""
Handle AI calls with document processing for JSON output using chunking for large documents.
Supports continuation when documents are too large for single AI call.
"""
# Initialize the document structure
completeDocument = {
"metadata": {"title": "Generated Document"},
"sections": [],
"continue": True
}
continuationContext = None
chunkCount = 0
maxChunks = 10 # Prevent infinite loops
while completeDocument.get("continue", False) and chunkCount < maxChunks:
chunkCount += 1
logger.info(f"Processing generation chunk {chunkCount}")
# Update progress
progressLogger.updateProgress(operationId, 0.3 + (chunkCount * 0.3 / maxChunks), f"Generating chunk {chunkCount}")
# Prepare the chunk prompt
if continuationContext:
chunkPrompt = f"""
{prompt}
CONTINUATION CONTEXT:
- Last completed section: {continuationContext.get('last_section_id', 'none')}
- Last completed element index: {continuationContext.get('last_element_index', 0)}
- Remaining requirements: {continuationContext.get('remaining_requirements', 'complete the document')}
Continue generating the document from where you left off. Include all previously generated content and add the remaining sections.
"""
else:
chunkPrompt = prompt
# Call AI for this chunk using the existing document processor
aiResponseJson = await self.documentProcessor.processDocumentsPerChunkJson(documents, chunkPrompt, options)
# Validate JSON response
if not isinstance(aiResponseJson, dict):
raise Exception("AI response is not valid JSON document structure")
# Merge the chunk with the complete document
if chunkCount == 1:
# First chunk - use as base
completeDocument = aiResponseJson
else:
# Subsequent chunks - merge sections
if "sections" in aiResponseJson:
# Find the last section ID from continuation context
lastSectionId = continuationContext.get('last_section_id', '') if continuationContext else ''
# Add new sections after the last completed one
newSections = []
for section in aiResponseJson["sections"]:
if section.get("id") != lastSectionId:
newSections.append(section)
completeDocument["sections"].extend(newSections)
# Check if we need to continue
if aiResponseJson.get("continue", False):
continuationContext = aiResponseJson.get("continuation_context", {})
logger.info(f"Document generation needs continuation: {continuationContext}")
else:
completeDocument["continue"] = False
logger.info("Document generation completed")
if chunkCount >= maxChunks:
logger.warning(f"Document generation stopped after {maxChunks} chunks (max limit reached)")
completeDocument["continue"] = False
return completeDocument
async def _analyzePromptIntent(self, prompt: str, ai_service=None) -> Dict[str, Any]:
"""Use AI to analyze user prompt and determine processing requirements."""
if not ai_service:

View file

@ -581,9 +581,19 @@ CRITICAL: The AI MUST generate content using the CANONICAL JSON FORMAT with this
],
"order": 3
}}
]
],
"continue": false
}}
IMPORTANT CHUNKING LOGIC:
- If the document is too large to generate completely in one response, set "continue": true
- When "continue": true, include a "continuation_context" field with:
- "last_section_id": "id of the last completed section"
- "last_element_index": "index of the last completed element in that section"
- "remaining_requirements": "brief description of what still needs to be generated"
- The AI will be called again with this context to continue generation
- Only set "continue": false when the document is completely generated
The AI should NOT create format-specific structures like "sheets" or "columns" - only use the canonical format with "sections" and "elements".
Write the instructions as plain text, not JSON. Start with "Generate JSON content that..." and provide clear, actionable instructions for creating structured JSON data in the canonical format.

View file

@ -18,10 +18,14 @@ logger = logging.getLogger(__name__)
def generateTaskPlanningPrompt(services, context: Any) -> PromptBundle:
"""Define placeholders first, then the template; return PromptBundle."""
# Extract user language from services
userLanguage = getattr(services, 'currentUserLanguage', None) or 'en'
placeholders: List[PromptPlaceholder] = [
PromptPlaceholder(label="USER_PROMPT", content=extractUserPrompt(context), summaryAllowed=False),
PromptPlaceholder(label="AVAILABLE_DOCUMENTS_SUMMARY", content=extractAvailableDocumentsSummary(services, context), summaryAllowed=True),
PromptPlaceholder(label="WORKFLOW_HISTORY", content=extractWorkflowHistory(services, context), summaryAllowed=True),
PromptPlaceholder(label="USER_LANGUAGE", content=userLanguage, summaryAllowed=False),
]
template = """# Task Planning
@ -71,7 +75,7 @@ Break down user requests into logical, executable task steps.
```json
{
"overview": "Brief description of the overall plan",
"userMessage": "User-friendly message explaining the task plan (use the user's detected language from intent)",
"userMessage": "User-friendly message explaining the task plan (use {{KEY:USER_LANGUAGE}} language)",
"tasks": [
{
"id": "task_1",