AI Generator Loop with context added
This commit is contained in:
parent
1917c00721
commit
6b7094c84d
3 changed files with 103 additions and 5 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue