enhanced voice center

This commit is contained in:
ValueOn AG 2025-12-03 11:18:33 +01:00
parent 9f46ca3b03
commit 6d393f9cf3
8 changed files with 425 additions and 24 deletions

View file

@ -403,6 +403,61 @@ class ConnectorGoogleSpeech:
"error": str(e) "error": str(e)
} }
async def detectLanguage(self, text: str) -> Dict:
"""
Detect the language of text using Google Cloud Translation API.
Args:
text: Text to detect language for
Returns:
Dict containing detected language code and confidence
"""
try:
if not text.strip():
logger.warning("⚠️ Empty text provided for language detection")
return {
"success": False,
"language": "",
"error": "Empty text provided"
}
# Use a sample of the text (middle 1000 bytes or full text if smaller)
textBytes = text.encode('utf-8')
if len(textBytes) > 1000:
# Take 1000 bytes from the middle
startPos = (len(textBytes) - 1000) // 2
textSample = textBytes[startPos:startPos + 1000].decode('utf-8', errors='ignore')
else:
textSample = text
logger.info(f"🔍 Detecting language for text sample: '{textSample[:100]}...'")
# Use translation API with auto-detection (source_language=None)
result = self.translate_client.translate(
textSample,
source_language=None, # Auto-detect
target_language='en' # Dummy target, we only need detection
)
detectedLanguage = result.get('detectedSourceLanguage', '')
logger.info(f"✅ Language detected: {detectedLanguage}")
return {
"success": True,
"language": detectedLanguage,
"confidence": 1.0 # Google Translation API doesn't provide confidence, assume high
}
except Exception as e:
logger.error(f"❌ Google Cloud Language Detection error: {e}")
return {
"success": False,
"language": "",
"error": str(e)
}
async def speechToTranslatedText(self, audioContent: bytes, async def speechToTranslatedText(self, audioContent: bytes,
fromLanguage: str = "de-DE", fromLanguage: str = "de-DE",
toLanguage: str = "en") -> Dict: toLanguage: str = "en") -> Dict:

View file

@ -99,6 +99,44 @@ class VoiceObjects:
# Translation Operations # Translation Operations
async def detectLanguage(self, text: str) -> Dict[str, Any]:
"""
Detect the language of text using Google Cloud Translation API.
Args:
text: Text to detect language for
Returns:
Dict containing detected language code and confidence
"""
try:
logger.info(f"🔍 Language detection request: '{text[:100]}...'")
if not text.strip():
return {
"success": False,
"language": "",
"error": "Empty text provided"
}
connector = self._getGoogleSpeechConnector()
result = await connector.detectLanguage(text)
if result["success"]:
logger.info(f"✅ Language detected: {result['language']}")
else:
logger.warning(f"⚠️ Language detection failed: {result.get('error', 'Unknown error')}")
return result
except Exception as e:
logger.error(f"❌ Language detection error: {e}")
return {
"success": False,
"language": "",
"error": str(e)
}
async def translateText(self, text: str, sourceLanguage: str = "de", async def translateText(self, text: str, sourceLanguage: str = "de",
targetLanguage: str = "en") -> Dict[str, Any]: targetLanguage: str = "en") -> Dict[str, Any]:
""" """

View file

@ -115,6 +115,48 @@ async def speech_to_text(
detail=f"Speech-to-text processing failed: {str(e)}" detail=f"Speech-to-text processing failed: {str(e)}"
) )
@router.post("/detect-language")
async def detect_language(
text: str = Form(...),
currentUser: User = Depends(getCurrentUser)
):
"""Detect the language of text using Google Cloud Translation API."""
try:
logger.info(f"🔍 Language detection request: '{text[:100]}...'")
if not text.strip():
raise HTTPException(
status_code=400,
detail="Empty text provided for language detection"
)
# Get voice interface
voiceInterface = _getVoiceInterface(currentUser)
# Perform language detection
result = await voiceInterface.detectLanguage(text)
if result["success"]:
return {
"success": True,
"language": result["language"],
"confidence": result.get("confidence", 1.0)
}
else:
raise HTTPException(
status_code=400,
detail=f"Language detection failed: {result.get('error', 'Unknown error')}"
)
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Language detection error: {e}")
raise HTTPException(
status_code=500,
detail=f"Language detection processing failed: {str(e)}"
)
@router.post("/translate") @router.post("/translate")
async def translate_text( async def translate_text(
text: str = Form(...), text: str = Form(...),

View file

@ -172,11 +172,19 @@ class MethodAi(MethodBase):
if aiResponse.documents and len(aiResponse.documents) > 0: if aiResponse.documents and len(aiResponse.documents) > 0:
action_documents = [] action_documents = []
for doc in aiResponse.documents: for doc in aiResponse.documents:
validationMetadata = {
"actionType": "ai.process",
"resultType": normalized_result_type,
"outputFormat": output_format,
"hasDocuments": True,
"documentCount": len(aiResponse.documents)
}
action_documents.append(ActionDocument( action_documents.append(ActionDocument(
documentName=doc.documentName, documentName=doc.documentName,
documentData=doc.documentData, documentData=doc.documentData,
mimeType=doc.mimeType or output_mime_type, mimeType=doc.mimeType or output_mime_type,
sourceJson=getattr(doc, 'sourceJson', None) # Preserve source JSON for structure validation sourceJson=getattr(doc, 'sourceJson', None), # Preserve source JSON for structure validation
validationMetadata=validationMetadata
)) ))
final_documents = action_documents final_documents = action_documents
@ -188,10 +196,18 @@ class MethodAi(MethodBase):
extension=extension, extension=extension,
action_name="result" action_name="result"
) )
validationMetadata = {
"actionType": "ai.process",
"resultType": normalized_result_type,
"outputFormat": output_format,
"hasDocuments": False,
"contentType": "text"
}
action_document = ActionDocument( action_document = ActionDocument(
documentName=meaningful_name, documentName=meaningful_name,
documentData=aiResponse.content, documentData=aiResponse.content,
mimeType=output_mime_type mimeType=output_mime_type,
validationMetadata=validationMetadata
) )
final_documents = [action_document] final_documents = [action_document]
@ -288,10 +304,20 @@ class MethodAi(MethodBase):
) )
from modules.datamodels.datamodelChat import ActionDocument from modules.datamodels.datamodelChat import ActionDocument
validationMetadata = {
"actionType": "ai.webResearch",
"prompt": prompt,
"urlList": parameters.get("urlList", []),
"country": parameters.get("country"),
"language": parameters.get("language"),
"researchDepth": parameters.get("researchDepth", "general"),
"resultFormat": "json"
}
actionDocument = ActionDocument( actionDocument = ActionDocument(
documentName=meaningfulName, documentName=meaningfulName,
documentData=result, documentData=result,
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
) )
return ActionResult.isSuccess(documents=[actionDocument]) return ActionResult.isSuccess(documents=[actionDocument])
@ -490,11 +516,19 @@ class MethodAi(MethodBase):
rendered_content = self._applyCsvOptions(rendered_content, renderOptions) rendered_content = self._applyCsvOptions(rendered_content, renderOptions)
from modules.datamodels.datamodelChat import ActionDocument from modules.datamodels.datamodelChat import ActionDocument
validationMetadata = {
"actionType": "ai.convert",
"inputFormat": normalizedInputFormat,
"outputFormat": normalizedOutputFormat,
"hasSourceJson": True,
"conversionType": "direct_rendering"
}
actionDoc = ActionDocument( actionDoc = ActionDocument(
documentName=f"{doc.documentName.rsplit('.', 1)[0] if '.' in doc.documentName else doc.documentName}.{normalizedOutputFormat}", documentName=f"{doc.documentName.rsplit('.', 1)[0] if '.' in doc.documentName else doc.documentName}.{normalizedOutputFormat}",
documentData=rendered_content, documentData=rendered_content,
mimeType=mime_type, mimeType=mime_type,
sourceJson=jsonData # Preserve source JSON for structure validation sourceJson=jsonData, # Preserve source JSON for structure validation
validationMetadata=validationMetadata
) )
return ActionResult.isSuccess(documents=[actionDoc]) return ActionResult.isSuccess(documents=[actionDoc])

View file

@ -18,6 +18,19 @@ def action(func):
- success: bool - success: bool
- documents: List[ActionDocument] - documents: List[ActionDocument]
- error: str (if success=False) - error: str (if success=False)
REQUIRED: All ActionDocument instances MUST include validationMetadata for content validation
and refinement. Without validationMetadata, results cannot be approved.
Example validationMetadata structure:
validationMetadata = {
"actionType": "moduleName.actionName",
"param1": value1,
"param2": value2,
# ... other relevant parameters for validation
}
See MethodBase._createValidationMetadata() for a helper method to create standard metadata.
""" """
@wraps(func) @wraps(func)
async def wrapper(self, parameters: Dict[str, Any], *args, **kwargs): async def wrapper(self, parameters: Dict[str, Any], *args, **kwargs):
@ -26,7 +39,14 @@ def action(func):
return wrapper return wrapper
class MethodBase: class MethodBase:
"""Base class for all methods""" """Base class for all methods
IMPORTANT: All actions that return ActionDocument instances MUST include validationMetadata.
This metadata is required for content validation and refinement. Without it, results cannot
be approved by the validation system.
Use _createValidationMetadata() helper method to create standardized metadata structures.
"""
def __init__(self, services: Any): def __init__(self, services: Any):
"""Initialize method with services object""" """Initialize method with services object"""
@ -168,6 +188,44 @@ class MethodBase:
else: else:
return str(type_annotation) return str(type_annotation)
def _createValidationMetadata(self, actionName: str, **kwargs) -> Dict[str, Any]:
"""
Helper method to create standardized validationMetadata for ActionDocument instances.
This method ensures all actions include the required validationMetadata structure
for content validation and refinement. Without metadata, results cannot be approved.
Args:
actionName: Name of the action (e.g., "readEmails", "uploadDocument")
**kwargs: Additional action-specific metadata fields
Returns:
Dictionary with validationMetadata structure including:
- actionType: Full action identifier (moduleName.actionName)
- All provided kwargs as additional metadata fields
Example:
validationMetadata = self._createValidationMetadata(
"readEmails",
connectionReference=connectionReference,
folder=folder,
limit=limit,
emailCount=len(emails)
)
ActionDocument(
documentName="emails.json",
documentData=json.dumps(data),
mimeType="application/json",
validationMetadata=validationMetadata # REQUIRED
)
"""
metadata = {
"actionType": f"{self.name}.{actionName}"
}
metadata.update(kwargs)
return metadata
def _generateMeaningfulFileName(self, base_name: str, extension: str, workflow_context: Dict[str, Any] = None, action_name: str = None) -> str: def _generateMeaningfulFileName(self, base_name: str, extension: str, workflow_context: Dict[str, Any] = None, action_name: str = None) -> str:
""" """
Generate a meaningful file name with round/task/action information. Generate a meaningful file name with round/task/action information.

View file

@ -78,11 +78,19 @@ class MethodContext(MethodBase):
"getDocumentIndex" "getDocumentIndex"
) )
validationMetadata = {
"actionType": "context.getDocumentIndex",
"resultType": resultType,
"workflowId": getattr(workflow, 'id', 'unknown'),
"totalDocuments": indexData.get("totalDocuments", 0) if isinstance(indexData, dict) else 0
}
# Create ActionDocument # Create ActionDocument
document = ActionDocument( document = ActionDocument(
documentName=filename, documentName=filename,
documentData=indexContent, documentData=indexContent,
mimeType="application/json" if resultType == "json" else "text/plain" mimeType="application/json" if resultType == "json" else "text/plain",
validationMetadata=validationMetadata
) )
return ActionResult.isSuccess(documents=[document]) return ActionResult.isSuccess(documents=[document])
@ -313,10 +321,18 @@ class MethodContext(MethodBase):
documentName = f"document_{i+1:03d}_extracted_{extracted.id}.json" documentName = f"document_{i+1:03d}_extracted_{extracted.id}.json"
# Store ContentExtracted object in ActionDocument.documentData # Store ContentExtracted object in ActionDocument.documentData
validationMetadata = {
"actionType": "context.extractContent",
"documentIndex": i,
"extractedId": extracted.id,
"partCount": len(extracted.parts) if extracted.parts else 0,
"originalFileName": originalDoc.fileName if originalDoc and hasattr(originalDoc, 'fileName') else None
}
actionDoc = ActionDocument( actionDoc = ActionDocument(
documentName=documentName, documentName=documentName,
documentData=extracted, # ContentExtracted object documentData=extracted, # ContentExtracted object
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
) )
actionDocuments.append(actionDoc) actionDocuments.append(actionDoc)

View file

@ -465,11 +465,22 @@ class MethodOutlook(MethodBase):
"timestamp": self.services.utils.timestampGetUtc() "timestamp": self.services.utils.timestampGetUtc()
} }
validationMetadata = {
"actionType": "outlook.readEmails",
"connectionReference": connectionReference,
"folder": folder,
"limit": limit,
"filter": filter,
"emailCount": email_data.get("count", 0),
"outputMimeType": outputMimeType
}
return ActionResult.isSuccess( return ActionResult.isSuccess(
documents=[ActionDocument( documents=[ActionDocument(
documentName=f"outlook_emails_{self._format_timestamp_for_filename()}.json", documentName=f"outlook_emails_{self._format_timestamp_for_filename()}.json",
documentData=json.dumps(result_data, indent=2), documentData=json.dumps(result_data, indent=2),
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
)] )]
) )
@ -695,12 +706,23 @@ class MethodOutlook(MethodBase):
"timestamp": self.services.utils.timestampGetUtc() "timestamp": self.services.utils.timestampGetUtc()
} }
validationMetadata = {
"actionType": "outlook.searchEmails",
"connectionReference": connectionReference,
"query": query,
"folder": folder,
"limit": limit,
"resultCount": search_result.get("count", 0),
"outputMimeType": outputMimeType
}
return ActionResult( return ActionResult(
success=True, success=True,
documents=[ActionDocument( documents=[ActionDocument(
documentName=f"outlook_email_search_{self._format_timestamp_for_filename()}.json", documentName=f"outlook_email_search_{self._format_timestamp_for_filename()}.json",
documentData=json.dumps(result_data, indent=2), documentData=json.dumps(result_data, indent=2),
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
)] )]
) )
@ -818,12 +840,22 @@ class MethodOutlook(MethodBase):
"timestamp": self.services.utils.timestampGetUtc() "timestamp": self.services.utils.timestampGetUtc()
} }
validationMetadata = {
"actionType": "outlook.listDrafts",
"connectionReference": connectionReference,
"folder": folder,
"limit": limit,
"draftCount": drafts_result.get("count", 0),
"outputMimeType": outputMimeType
}
return ActionResult( return ActionResult(
success=True, success=True,
documents=[ActionDocument( documents=[ActionDocument(
documentName=f"outlook_drafts_list_{self._format_timestamp_for_filename()}.json", documentName=f"outlook_drafts_list_{self._format_timestamp_for_filename()}.json",
documentData=json.dumps(result_data, indent=2), documentData=json.dumps(result_data, indent=2),
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
)] )]
) )
@ -928,12 +960,21 @@ class MethodOutlook(MethodBase):
"timestamp": self.services.utils.timestampGetUtc() "timestamp": self.services.utils.timestampGetUtc()
} }
validationMetadata = {
"actionType": "outlook.findDrafts",
"connectionReference": connectionReference,
"limit": limit,
"totalDrafts": drafts_result.get("totalDrafts", 0),
"outputMimeType": outputMimeType
}
return ActionResult( return ActionResult(
success=True, success=True,
documents=[ActionDocument( documents=[ActionDocument(
documentName=f"outlook_drafts_found_{self._format_timestamp_for_filename()}.json", documentName=f"outlook_drafts_found_{self._format_timestamp_for_filename()}.json",
documentData=json.dumps(result_data, indent=2), documentData=json.dumps(result_data, indent=2),
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
)] )]
) )
@ -1069,12 +1110,22 @@ class MethodOutlook(MethodBase):
"timestamp": self.services.utils.timestampGetUtc() "timestamp": self.services.utils.timestampGetUtc()
} }
validationMetadata = {
"actionType": "outlook.checkDraftsFolder",
"connectionReference": connectionReference,
"limit": limit,
"totalDrafts": drafts_result.get("totalDrafts", 0),
"draftsFolderId": drafts_result.get("draftsFolderId"),
"outputMimeType": outputMimeType
}
return ActionResult( return ActionResult(
success=True, success=True,
documents=[ActionDocument( documents=[ActionDocument(
documentName=f"outlook_drafts_folder_check_{self._format_timestamp_for_filename()}.json", documentName=f"outlook_drafts_folder_check_{self._format_timestamp_for_filename()}.json",
documentData=json.dumps(result_data, indent=2), documentData=json.dumps(result_data, indent=2),
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
)] )]
) )
@ -1624,34 +1675,61 @@ Return JSON:
# Determine overall success status # Determine overall success status
if successfulEmails == 0: if successfulEmails == 0:
validationMetadata = {
"actionType": "outlook.sendDraftEmail",
"connectionReference": connectionReference,
"totalEmails": totalEmails,
"successfulEmails": successfulEmails,
"failedEmails": failedEmails,
"status": "all_failed"
}
return ActionResult.isFailure( return ActionResult.isFailure(
error=f"Failed to send all {totalEmails} email(s)", error=f"Failed to send all {totalEmails} email(s)",
documents=[ActionDocument( documents=[ActionDocument(
documentName=f"sent_mail_confirmation_{self._format_timestamp_for_filename()}.json", documentName=f"sent_mail_confirmation_{self._format_timestamp_for_filename()}.json",
documentData=json.dumps(resultData, indent=2), documentData=json.dumps(resultData, indent=2),
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
)] )]
) )
elif failedEmails > 0: elif failedEmails > 0:
# Partial success # Partial success
logger.warning(f"Sent {successfulEmails} out of {totalEmails} emails. {failedEmails} failed.") logger.warning(f"Sent {successfulEmails} out of {totalEmails} emails. {failedEmails} failed.")
validationMetadata = {
"actionType": "outlook.sendDraftEmail",
"connectionReference": connectionReference,
"totalEmails": totalEmails,
"successfulEmails": successfulEmails,
"failedEmails": failedEmails,
"status": "partial_success"
}
return ActionResult( return ActionResult(
success=True, success=True,
documents=[ActionDocument( documents=[ActionDocument(
documentName=f"sent_mail_confirmation_{self._format_timestamp_for_filename()}.json", documentName=f"sent_mail_confirmation_{self._format_timestamp_for_filename()}.json",
documentData=json.dumps(resultData, indent=2), documentData=json.dumps(resultData, indent=2),
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
)] )]
) )
else: else:
# All successful # All successful
logger.info(f"Successfully sent all {totalEmails} email(s)") logger.info(f"Successfully sent all {totalEmails} email(s)")
validationMetadata = {
"actionType": "outlook.sendDraftEmail",
"connectionReference": connectionReference,
"totalEmails": totalEmails,
"successfulEmails": successfulEmails,
"failedEmails": failedEmails,
"status": "all_successful"
}
return ActionResult( return ActionResult(
success=True, success=True,
documents=[ActionDocument( documents=[ActionDocument(
documentName=f"sent_mail_confirmation_{self._format_timestamp_for_filename()}.json", documentName=f"sent_mail_confirmation_{self._format_timestamp_for_filename()}.json",
documentData=json.dumps(resultData, indent=2), documentData=json.dumps(resultData, indent=2),
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
)] )]
) )
@ -1693,12 +1771,19 @@ Return JSON:
"status": "ready" "status": "ready"
} }
validationMetadata = {
"actionType": "outlook.checkPermissions",
"connectionReference": connectionReference,
"permissionsStatus": "ready",
"hasPermissions": True
}
return ActionResult( return ActionResult(
success=True, success=True,
documents=[ActionDocument( documents=[ActionDocument(
documentName=f"outlook_permissions_check_{self._format_timestamp_for_filename()}.json", documentName=f"outlook_permissions_check_{self._format_timestamp_for_filename()}.json",
documentData=json.dumps(result_data, indent=2), documentData=json.dumps(result_data, indent=2),
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
)] )]
) )
else: else:
@ -1711,12 +1796,19 @@ Return JSON:
"message": "Please re-authenticate your Microsoft connection to get updated permissions." "message": "Please re-authenticate your Microsoft connection to get updated permissions."
} }
validationMetadata = {
"actionType": "outlook.checkPermissions",
"connectionReference": connectionReference,
"permissionsStatus": "needs_reauthentication",
"hasPermissions": False
}
return ActionResult( return ActionResult(
success=False, success=False,
documents=[ActionDocument( documents=[ActionDocument(
documentName=f"outlook_permissions_check_{self._format_timestamp_for_filename()}.json", documentName=f"outlook_permissions_check_{self._format_timestamp_for_filename()}.json",
documentData=json.dumps(result_data, indent=2), documentData=json.dumps(result_data, indent=2),
mimeType="application/json" mimeType="application/json",
validationMetadata=validationMetadata
)], )],
error="Connection lacks necessary permissions for Outlook operations" error="Connection lacks necessary permissions for Outlook operations"
) )

View file

@ -1072,6 +1072,13 @@ class MethodSharepoint(MethodBase):
outputExtension = ".json" # Default outputExtension = ".json" # Default
outputMimeType = "application/json" # Default outputMimeType = "application/json" # Default
validationMetadata = {
"actionType": "sharepoint.findDocumentPath",
"searchQuery": searchQuery,
"maxResults": maxResults,
"totalResults": len(foundDocuments),
"hasResults": len(foundDocuments) > 0
}
return ActionResult( return ActionResult(
success=True, success=True,
@ -1079,7 +1086,8 @@ class MethodSharepoint(MethodBase):
ActionDocument( ActionDocument(
documentName=f"sharepoint_find_path_{self._format_timestamp_for_filename()}{outputExtension}", documentName=f"sharepoint_find_path_{self._format_timestamp_for_filename()}{outputExtension}",
documentData=json.dumps(resultData, indent=2), documentData=json.dumps(resultData, indent=2),
mimeType=outputMimeType mimeType=outputMimeType,
validationMetadata=validationMetadata
) )
] ]
) )
@ -1336,19 +1344,40 @@ class MethodSharepoint(MethodBase):
if fileContent and isinstance(fileContent, bytes): if fileContent and isinstance(fileContent, bytes):
# Encode binary content as Base64 string # Encode binary content as Base64 string
base64Content = base64.b64encode(fileContent).decode('utf-8') base64Content = base64.b64encode(fileContent).decode('utf-8')
validationMetadata = {
"actionType": "sharepoint.readDocuments",
"fileName": fileName,
"sharepointFileId": resultItem.get("sharepointFileId"),
"siteName": resultItem.get("siteName"),
"mimeType": mimeType,
"contentType": "binary",
"size": len(fileContent),
"includeMetadata": includeMetadata
}
actionDoc = ActionDocument( actionDoc = ActionDocument(
documentName=fileName, documentName=fileName,
documentData=base64Content, # Base64 string for binary files documentData=base64Content, # Base64 string for binary files
mimeType=mimeType mimeType=mimeType,
validationMetadata=validationMetadata
) )
actionDocuments.append(actionDoc) actionDocuments.append(actionDoc)
logger.info(f"Stored binary file {fileName} ({len(fileContent)} bytes) as Base64 in ActionDocument") logger.info(f"Stored binary file {fileName} ({len(fileContent)} bytes) as Base64 in ActionDocument")
elif fileContent: elif fileContent:
# Text content - store directly in documentData # Text content - store directly in documentData
validationMetadata = {
"actionType": "sharepoint.readDocuments",
"fileName": fileName,
"sharepointFileId": resultItem.get("sharepointFileId"),
"siteName": resultItem.get("siteName"),
"mimeType": mimeType,
"contentType": "text",
"includeMetadata": includeMetadata
}
actionDoc = ActionDocument( actionDoc = ActionDocument(
documentName=fileName, documentName=fileName,
documentData=fileContent if isinstance(fileContent, str) else str(fileContent), documentData=fileContent if isinstance(fileContent, str) else str(fileContent),
mimeType=mimeType mimeType=mimeType,
validationMetadata=validationMetadata
) )
actionDocuments.append(actionDoc) actionDocuments.append(actionDoc)
else: else:
@ -1366,10 +1395,20 @@ class MethodSharepoint(MethodBase):
if resultItem.get("metadata"): if resultItem.get("metadata"):
docData["metadata"] = resultItem["metadata"] docData["metadata"] = resultItem["metadata"]
validationMetadata = {
"actionType": "sharepoint.readDocuments",
"fileName": fileName,
"sharepointFileId": resultItem.get("sharepointFileId"),
"siteName": resultItem.get("siteName"),
"mimeType": mimeType,
"contentType": "metadata_only",
"includeMetadata": includeMetadata
}
actionDoc = ActionDocument( actionDoc = ActionDocument(
documentName=fileName, documentName=fileName,
documentData=json.dumps(docData, indent=2), documentData=json.dumps(docData, indent=2),
mimeType=mimeType mimeType=mimeType,
validationMetadata=validationMetadata
) )
actionDocuments.append(actionDoc) actionDocuments.append(actionDoc)
@ -1583,6 +1622,13 @@ class MethodSharepoint(MethodBase):
outputExtension = ".json" # Default outputExtension = ".json" # Default
outputMimeType = "application/json" # Default outputMimeType = "application/json" # Default
validationMetadata = {
"actionType": "sharepoint.readDocuments",
"connectionReference": connectionReference,
"documentCount": len(readResults),
"includeMetadata": includeMetadata,
"sitesSearched": len(sites)
}
return ActionResult( return ActionResult(
success=True, success=True,
@ -1590,7 +1636,8 @@ class MethodSharepoint(MethodBase):
ActionDocument( ActionDocument(
documentName=f"sharepoint_documents_{self._format_timestamp_for_filename()}{outputExtension}", documentName=f"sharepoint_documents_{self._format_timestamp_for_filename()}{outputExtension}",
documentData=json.dumps(resultData, indent=2), documentData=json.dumps(resultData, indent=2),
mimeType=outputMimeType mimeType=outputMimeType,
validationMetadata=validationMetadata
) )
] ]
) )
@ -1998,6 +2045,15 @@ class MethodSharepoint(MethodBase):
outputExtension = ".json" # Default outputExtension = ".json" # Default
outputMimeType = "application/json" # Default outputMimeType = "application/json" # Default
validationMetadata = {
"actionType": "sharepoint.uploadDocument",
"connectionReference": connectionReference,
"uploadPath": uploadPath,
"fileNames": fileNames,
"uploadCount": len(uploadResults),
"successfulUploads": len([r for r in uploadResults if r.get("uploadStatus") == "success"]),
"failedUploads": len([r for r in uploadResults if r.get("uploadStatus") == "failed"])
}
return ActionResult( return ActionResult(
success=True, success=True,
@ -2005,7 +2061,8 @@ class MethodSharepoint(MethodBase):
ActionDocument( ActionDocument(
documentName=f"sharepoint_upload_{self._format_timestamp_for_filename()}{outputExtension}", documentName=f"sharepoint_upload_{self._format_timestamp_for_filename()}{outputExtension}",
documentData=json.dumps(resultData, indent=2), documentData=json.dumps(resultData, indent=2),
mimeType=outputMimeType mimeType=outputMimeType,
validationMetadata=validationMetadata
) )
] ]
) )
@ -2459,6 +2516,14 @@ class MethodSharepoint(MethodBase):
outputExtension = ".json" # Default outputExtension = ".json" # Default
outputMimeType = "application/json" # Default outputMimeType = "application/json" # Default
validationMetadata = {
"actionType": "sharepoint.listDocuments",
"pathQuery": listQuery,
"includeSubfolders": includeSubfolders,
"sitesSearched": len(sites),
"folderCount": len(listResults),
"totalItems": sum(len(result.get("siteResults", [])) for result in listResults)
}
return ActionResult( return ActionResult(
success=True, success=True,
@ -2466,7 +2531,8 @@ class MethodSharepoint(MethodBase):
ActionDocument( ActionDocument(
documentName=f"sharepoint_document_list_{self._format_timestamp_for_filename()}{outputExtension}", documentName=f"sharepoint_document_list_{self._format_timestamp_for_filename()}{outputExtension}",
documentData=json.dumps(resultData, indent=2), documentData=json.dumps(resultData, indent=2),
mimeType=outputMimeType mimeType=outputMimeType,
validationMetadata=validationMetadata
) )
] ]
) )