gateway/modules/workflows/methods/methodJira/actions/createExcelContent.py
2026-01-23 01:10:00 +01:00

138 lines
5.5 KiB
Python

# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
import logging
import json
import base64
import pandas as pd
import csv as csv_module
from io import BytesIO
from datetime import datetime, UTC
from typing import Dict, Any
from modules.datamodels.datamodelChat import ActionResult, ActionDocument
logger = logging.getLogger(__name__)
async def createExcelContent(self, parameters: Dict[str, Any]) -> ActionResult:
try:
dataParam = parameters.get("data")
if not dataParam:
return ActionResult.isFailure(error="data parameter is required")
headersParam = parameters.get("headers")
columnsParam = parameters.get("columns")
taskSyncDefinitionParam = parameters.get("taskSyncDefinition")
# Get data from document
dataJson = self.documentParsing.parseJsonFromDocument(dataParam)
if dataJson is None:
return ActionResult.isFailure(error="Could not parse data from document reference")
# Extract data array if wrapped in object
if isinstance(dataJson, dict) and "data" in dataJson:
dataList = dataJson["data"]
elif isinstance(dataJson, list):
dataList = dataJson
else:
return ActionResult.isFailure(error="Data must be a JSON array or object with 'data' field")
# Get headers
headers = {"header1": "Header 1", "header2": "Header 2"}
if headersParam:
headersJson = self.documentParsing.parseJsonFromDocument(headersParam)
if headersJson and isinstance(headersJson, dict) and "headers" in headersJson:
headers = headersJson["headers"]
elif headersJson and isinstance(headersJson, dict):
headers = headersJson
# Get columns
if columnsParam:
if isinstance(columnsParam, str):
try:
columns = json.loads(columnsParam) if columnsParam.startswith('[') or columnsParam.startswith('{') else columnsParam.split(',')
except:
columns = columnsParam.split(',')
elif isinstance(columnsParam, list):
columns = columnsParam
else:
columns = None
elif taskSyncDefinitionParam:
# Extract columns from taskSyncDefinition
if isinstance(taskSyncDefinitionParam, str):
taskSyncDefinition = json.loads(taskSyncDefinitionParam)
else:
taskSyncDefinition = taskSyncDefinitionParam
columns = list(taskSyncDefinition.keys())
elif dataList and len(dataList) > 0:
columns = list(dataList[0].keys())
else:
columns = []
# Create DataFrame
if not dataList:
df = pd.DataFrame(columns=columns)
else:
df = pd.DataFrame(dataList)
# Ensure all columns exist
for col in columns:
if col not in df.columns:
df[col] = ""
# Reorder columns
df = df[columns]
# Clean data
for column in df.columns:
df[column] = df[column].astype("object").fillna("")
df[column] = df[column].astype(str).str.replace('\n', '\\n', regex=False).str.replace('"', '""', regex=False)
# Create headers with timestamp
timestamp = datetime.fromtimestamp(self.services.utils.timestampGetUtc(), UTC).strftime("%Y-%m-%d %H:%M:%S UTC")
header1Row = next(csv_module.reader([headers.get("header1", "Header 1")]), [])
header2Row = next(csv_module.reader([headers.get("header2", "Header 2")]), [])
if len(header2Row) > 1:
header2Row[1] = timestamp
headerRow1 = pd.DataFrame([header1Row + [""] * (len(df.columns) - len(header1Row))], columns=df.columns)
headerRow2 = pd.DataFrame([header2Row + [""] * (len(df.columns) - len(header2Row))], columns=df.columns)
tableHeaders = pd.DataFrame([df.columns.tolist()], columns=df.columns)
finalDf = pd.concat([headerRow1, headerRow2, tableHeaders, df], ignore_index=True)
# Convert to Excel bytes
buf = BytesIO()
finalDf.to_excel(buf, index=False, header=False, engine='openpyxl')
excelBytes = buf.getvalue()
logger.info(f"Created Excel content: {len(dataList)} rows, {len(columns)} columns")
# Generate filename
workflowContext = self.services.chat.getWorkflowContext() if hasattr(self.services, 'chat') else None
filename = self._generateMeaningfulFileName(
"ticket_sync",
"xlsx",
workflowContext,
"createExcelContent"
)
validationMetadata = self._createValidationMetadata(
"createExcelContent",
rowCount=len(dataList),
columnCount=len(columns)
)
# Store as base64 for document
excelBase64 = base64.b64encode(excelBytes).decode('utf-8')
document = ActionDocument(
documentName=filename,
documentData=excelBase64,
mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
validationMetadata=validationMetadata
)
return ActionResult.isSuccess(documents=[document])
except Exception as e:
errorMsg = f"Error creating Excel content: {str(e)}"
logger.error(errorMsg)
return ActionResult.isFailure(error=errorMsg)