gateway/modules/methods/methodPowerpoint.py
2025-07-04 15:10:26 +02:00

639 lines
No EOL
24 KiB
Python

"""
PowerPoint method module.
Handles PowerPoint operations using the PowerPoint service.
"""
import logging
from typing import Dict, Any, List, Optional
from datetime import datetime, UTC
import json
import base64
from modules.workflow.methodBase import MethodBase, ActionResult, action
logger = logging.getLogger(__name__)
class PowerpointService:
"""Service for Microsoft PowerPoint operations using Graph API"""
def __init__(self, serviceContainer: Any):
self.serviceContainer = serviceContainer
def _getMicrosoftConnection(self, connectionReference: str) -> Optional[Dict[str, Any]]:
"""Get Microsoft connection from connection reference"""
try:
userConnection = self.serviceContainer.getUserConnectionFromConnectionReference(connectionReference)
if not userConnection or userConnection.authority != "msft" or userConnection.status != "active":
return None
# Get the corresponding token for this user and authority
token = self.serviceContainer.interfaceApp.getToken(userConnection.authority)
if not token:
logger.warning(f"No token found for user {userConnection.userId} and authority {userConnection.authority}")
return None
return {
"id": userConnection.id,
"accessToken": token.tokenAccess,
"refreshToken": token.tokenRefresh,
"scopes": ["Mail.ReadWrite", "User.Read"] # Default Microsoft scopes
}
except Exception as e:
logger.error(f"Error getting Microsoft connection: {str(e)}")
return None
async def readPresentation(self, fileId: str, connectionReference: str, includeSlides: bool = True) -> Dict[str, Any]:
"""Read PowerPoint presentation using Microsoft Graph API"""
try:
connection = self._getMicrosoftConnection(connectionReference)
if not connection:
return {
"error": "No valid Microsoft connection found for the provided connection reference",
"fileId": fileId,
"connectionReference": connectionReference
}
# Get file data from service container
file_data = self.serviceContainer.getFileData(fileId)
file_info = self.serviceContainer.getFileInfo(fileId)
if not file_data:
return {
"error": "File not found or empty",
"fileId": fileId
}
# For now, simulate PowerPoint reading with AI analysis
# In a real implementation, you would use Microsoft Graph API
ppt_prompt = f"""
Analyze this PowerPoint presentation and extract structured information.
File: {file_info.get('name', 'Unknown')}
Include slides: {includeSlides}
File content (first 5000 characters):
{file_data.decode('utf-8', errors='ignore')[:5000] if isinstance(file_data, bytes) else str(file_data)[:5000]}
Please extract:
1. Presentation title and theme
2. Slide structure and content
3. Text content from each slide
4. Images and media references
5. Charts and data visualizations
6. Speaker notes if available
7. Overall presentation flow and messaging
Return the data in a structured JSON format.
"""
# Use AI to analyze PowerPoint content
analysis_result = await self.serviceContainer.interfaceAiCalls.callAiTextAdvanced(ppt_prompt)
return {
"fileId": fileId,
"includeSlides": includeSlides,
"data": analysis_result,
"fileInfo": file_info,
"connection": {
"id": connection["id"],
"authority": "microsoft",
"reference": connectionReference
}
}
except Exception as e:
logger.error(f"Error reading presentation: {str(e)}")
return {
"error": str(e),
"fileId": fileId
}
async def writePresentation(self, fileId: str, connectionReference: str, slides: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Write to PowerPoint presentation using Microsoft Graph API"""
try:
connection = self._getMicrosoftConnection(connectionReference)
if not connection:
return {
"error": "No valid Microsoft connection found for the provided connection reference",
"fileId": fileId,
"connectionReference": connectionReference
}
# For now, simulate PowerPoint writing
# In a real implementation, you would use Microsoft Graph API
write_prompt = f"""
Prepare content for writing to PowerPoint presentation.
File: {fileId}
Number of slides: {len(slides)}
Slides data:
{json.dumps(slides, indent=2)}
Please format this content appropriately for PowerPoint and provide:
1. Slide layouts and structures
2. Text content and formatting
3. Image and media placement
4. Chart and visualization specifications
5. Animation and transition suggestions
"""
# Use AI to prepare PowerPoint content
prepared_content = await self.serviceContainer.interfaceAiCalls.callAiTextAdvanced(write_prompt)
return {
"fileId": fileId,
"slides": slides,
"content": prepared_content,
"status": "prepared",
"connection": {
"id": connection["id"],
"authority": "microsoft",
"reference": connectionReference
}
}
except Exception as e:
logger.error(f"Error writing to presentation: {str(e)}")
return {
"error": str(e),
"fileId": fileId
}
async def convertPresentation(self, fileId: str, connectionReference: str, format: str = "pdf") -> Dict[str, Any]:
"""Convert PowerPoint presentation to another format using Microsoft Graph API"""
try:
connection = self._getMicrosoftConnection(connectionReference)
if not connection:
return {
"error": "No valid Microsoft connection found for the provided connection reference",
"fileId": fileId,
"connectionReference": connectionReference
}
# For now, simulate conversion
# In a real implementation, you would use Microsoft Graph API
convert_prompt = f"""
Convert PowerPoint presentation to {format.upper()} format.
File: {fileId}
Target format: {format}
Please provide:
1. Conversion specifications
2. Format-specific optimizations
3. Quality settings and options
4. Any special considerations for the target format
"""
# Use AI to describe conversion process
conversion_result = await self.serviceContainer.interfaceAiCalls.callAiTextAdvanced(convert_prompt)
# Create converted file using service container
converted_file_id = self.serviceContainer.createFile(
fileName=f"converted_presentation.{format}",
mimeType=f"application/{format}",
content=conversion_result,
base64encoded=False
)
return {
"fileId": fileId,
"format": format,
"convertedFileId": converted_file_id,
"result": conversion_result,
"connection": {
"id": connection["id"],
"authority": "microsoft",
"reference": connectionReference
}
}
except Exception as e:
logger.error(f"Error converting presentation: {str(e)}")
return {
"error": str(e),
"fileId": fileId
}
async def createPresentation(self, fileName: str, connectionReference: str, template: str = None) -> Dict[str, Any]:
"""Create new PowerPoint presentation using Microsoft Graph API"""
try:
connection = self._getMicrosoftConnection(connectionReference)
if not connection:
return {
"error": "No valid Microsoft connection found for the provided connection reference",
"connectionReference": connectionReference
}
# For now, simulate presentation creation
# In a real implementation, you would use Microsoft Graph API
create_prompt = f"""
Create a new PowerPoint presentation structure.
File name: {fileName}
Template: {template or 'Standard'}
Please provide:
1. Initial slide structure
2. Default slide layouts
3. Theme and design elements
4. Sample content if template specified
5. Presentation guidelines
"""
# Use AI to create PowerPoint structure
presentation_structure = await self.serviceContainer.interfaceAiCalls.callAiTextAdvanced(create_prompt)
# Create file using service container
file_id = self.serviceContainer.createFile(
fileName=fileName,
mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation",
content=presentation_structure,
base64encoded=False
)
return {
"fileId": file_id,
"fileName": fileName,
"template": template,
"structure": presentation_structure,
"connection": {
"id": connection["id"],
"authority": "microsoft",
"reference": connectionReference
}
}
except Exception as e:
logger.error(f"Error creating presentation: {str(e)}")
return {
"error": str(e)
}
async def addSlide(self, fileId: str, connectionReference: str, layout: str = "title", content: Dict[str, Any] = None) -> Dict[str, Any]:
"""Add slide to presentation using Microsoft Graph API"""
try:
connection = self._getMicrosoftConnection(connectionReference)
if not connection:
return {
"error": "No valid Microsoft connection found for the provided connection reference",
"fileId": fileId,
"connectionReference": connectionReference
}
# For now, simulate slide addition
# In a real implementation, you would use Microsoft Graph API
slide_prompt = f"""
Add a new slide to PowerPoint presentation.
File: {fileId}
Layout: {layout}
Content: {json.dumps(content, indent=2) if content else 'Default content'}
Please provide:
1. Slide structure and layout
2. Content placement and formatting
3. Visual elements and design
4. Slide number and positioning
"""
# Use AI to create slide content
slide_content = await self.serviceContainer.interfaceAiCalls.callAiTextAdvanced(slide_prompt)
return {
"fileId": fileId,
"layout": layout,
"content": content,
"slideContent": slide_content,
"connection": {
"id": connection["id"],
"authority": "microsoft",
"reference": connectionReference
}
}
except Exception as e:
logger.error(f"Error adding slide: {str(e)}")
return {
"error": str(e),
"fileId": fileId
}
async def addContent(self, fileId: str, connectionReference: str, slideId: str, content: Dict[str, Any]) -> Dict[str, Any]:
"""Add content to slide using Microsoft Graph API"""
try:
connection = self._getMicrosoftConnection(connectionReference)
if not connection:
return {
"error": "No valid Microsoft connection found for the provided connection reference",
"fileId": fileId,
"connectionReference": connectionReference
}
# For now, simulate content addition
# In a real implementation, you would use Microsoft Graph API
content_prompt = f"""
Add content to PowerPoint slide.
File: {fileId}
Slide ID: {slideId}
Content: {json.dumps(content, indent=2)}
Please provide:
1. Content placement and formatting
2. Text styling and layout
3. Image and media integration
4. Chart and visualization setup
5. Animation and effects
"""
# Use AI to format slide content
formatted_content = await self.serviceContainer.interfaceAiCalls.callAiTextAdvanced(content_prompt)
return {
"fileId": fileId,
"slideId": slideId,
"content": content,
"formattedContent": formatted_content,
"connection": {
"id": connection["id"],
"authority": "microsoft",
"reference": connectionReference
}
}
except Exception as e:
logger.error(f"Error adding content: {str(e)}")
return {
"error": str(e),
"fileId": fileId
}
class MethodPowerpoint(MethodBase):
"""PowerPoint method implementation for presentation operations"""
def __init__(self, serviceContainer: Any):
"""Initialize the PowerPoint method"""
super().__init__(serviceContainer)
self.name = "powerpoint"
self.description = "Handle PowerPoint presentation operations like reading and creating slides"
self.powerpointService = PowerpointService(serviceContainer)
@action
async def read(self, parameters: Dict[str, Any]) -> ActionResult:
"""
Read PowerPoint presentation
Parameters:
fileId (str): The ID of the PowerPoint file to read
connectionReference (str): Reference to the Microsoft connection
includeSlides (bool, optional): Whether to include slide content (default: True)
"""
try:
fileId = parameters.get("fileId")
connectionReference = parameters.get("connectionReference")
includeSlides = parameters.get("includeSlides", True)
if not fileId or not connectionReference:
return self._createResult(
success=False,
data={},
error="File ID and connection reference are required"
)
# Read presentation
data = await self.powerpointService.readPresentation(
fileId=fileId,
connectionReference=connectionReference,
includeSlides=includeSlides
)
return self._createResult(
success=True,
data=data
)
except Exception as e:
logger.error(f"Error reading presentation: {str(e)}")
return self._createResult(
success=False,
data={},
error=str(e)
)
@action
async def write(self, parameters: Dict[str, Any]) -> ActionResult:
"""
Write to PowerPoint presentation
Parameters:
fileId (str): The ID of the PowerPoint file to write to
connectionReference (str): Reference to the Microsoft connection
slides (List[Dict[str, Any]]): List of slides to write
"""
try:
fileId = parameters.get("fileId")
connectionReference = parameters.get("connectionReference")
slides = parameters.get("slides", [])
if not fileId or not connectionReference:
return self._createResult(
success=False,
data={},
error="File ID and connection reference are required"
)
# Write to presentation
result = await self.powerpointService.writePresentation(
fileId=fileId,
connectionReference=connectionReference,
slides=slides
)
return self._createResult(
success=True,
data=result
)
except Exception as e:
logger.error(f"Error writing to presentation: {str(e)}")
return self._createResult(
success=False,
data={},
error=str(e)
)
@action
async def convert(self, parameters: Dict[str, Any]) -> ActionResult:
"""
Convert PowerPoint presentation to another format
Parameters:
fileId (str): The ID of the PowerPoint file to convert
connectionReference (str): Reference to the Microsoft connection
format (str, optional): Target format (default: "pdf")
"""
try:
fileId = parameters.get("fileId")
connectionReference = parameters.get("connectionReference")
format = parameters.get("format", "pdf")
if not fileId or not connectionReference:
return self._createResult(
success=False,
data={},
error="File ID and connection reference are required"
)
# Convert presentation
result = await self.powerpointService.convertPresentation(
fileId=fileId,
connectionReference=connectionReference,
format=format
)
return self._createResult(
success=True,
data=result
)
except Exception as e:
logger.error(f"Error converting presentation: {str(e)}")
return self._createResult(
success=False,
data={},
error=str(e)
)
@action
async def createPresentation(self, parameters: Dict[str, Any]) -> ActionResult:
"""
Create new PowerPoint presentation
Parameters:
fileName (str): Name of the new presentation file
connectionReference (str): Reference to the Microsoft connection
template (str, optional): Template to use for the new presentation
"""
try:
fileName = parameters.get("fileName")
connectionReference = parameters.get("connectionReference")
template = parameters.get("template")
if not fileName or not connectionReference:
return self._createResult(
success=False,
data={},
error="File name and connection reference are required"
)
# Create presentation
fileId = await self.powerpointService.createPresentation(
fileName=fileName,
connectionReference=connectionReference,
template=template
)
return self._createResult(
success=True,
data={"fileId": fileId}
)
except Exception as e:
logger.error(f"Error creating presentation: {str(e)}")
return self._createResult(
success=False,
data={},
error=str(e)
)
@action
async def addSlide(self, parameters: Dict[str, Any]) -> ActionResult:
"""
Add slide to presentation
Parameters:
fileId (str): The ID of the PowerPoint file
connectionReference (str): Reference to the Microsoft connection
layout (str, optional): Slide layout type (default: "title")
content (Dict[str, Any], optional): Content for the slide
"""
try:
fileId = parameters.get("fileId")
connectionReference = parameters.get("connectionReference")
layout = parameters.get("layout", "title")
content = parameters.get("content", {})
if not fileId or not connectionReference:
return self._createResult(
success=False,
data={},
error="File ID and connection reference are required"
)
# Add slide
slide = await self.powerpointService.addSlide(
fileId=fileId,
connectionReference=connectionReference,
layout=layout,
content=content
)
return self._createResult(
success=True,
data=slide
)
except Exception as e:
logger.error(f"Error adding slide: {str(e)}")
return self._createResult(
success=False,
data={},
error=str(e)
)
@action
async def addContent(self, parameters: Dict[str, Any]) -> ActionResult:
"""
Add content to slide
Parameters:
fileId (str): The ID of the PowerPoint file
connectionReference (str): Reference to the Microsoft connection
slideId (str): ID of the slide to add content to
content (Dict[str, Any]): Content to add to the slide
"""
try:
fileId = parameters.get("fileId")
connectionReference = parameters.get("connectionReference")
slideId = parameters.get("slideId")
content = parameters.get("content", {})
if not fileId or not connectionReference or not slideId:
return self._createResult(
success=False,
data={},
error="File ID, connection reference, and slide ID are required"
)
# Add content
result = await self.powerpointService.addContent(
fileId=fileId,
connectionReference=connectionReference,
slideId=slideId,
content=content
)
return self._createResult(
success=True,
data=result
)
except Exception as e:
logger.error(f"Error adding content: {str(e)}")
return self._createResult(
success=False,
data={},
error=str(e)
)