118 lines
4.5 KiB
Python
118 lines
4.5 KiB
Python
# Copyright (c) 2025 Patrick Motsch
|
|
# All rights reserved.
|
|
"""
|
|
Utility functions for automation feature.
|
|
|
|
Moved from interfaces/interfaceDbChatbot.py.
|
|
"""
|
|
|
|
import json
|
|
from typing import Dict, Any
|
|
from datetime import datetime, UTC
|
|
|
|
|
|
def parseScheduleToCron(schedule: str) -> Dict[str, Any]:
|
|
"""Parse schedule string to cron kwargs for APScheduler"""
|
|
parts = schedule.split()
|
|
if len(parts) != 5:
|
|
raise ValueError(f"Invalid schedule format: {schedule}")
|
|
|
|
return {
|
|
"minute": parts[0],
|
|
"hour": parts[1],
|
|
"day": parts[2],
|
|
"month": parts[3],
|
|
"day_of_week": parts[4]
|
|
}
|
|
|
|
|
|
def planToPrompt(plan: Dict) -> str:
|
|
"""Convert plan structure to prompt string for workflow execution"""
|
|
return plan.get("userMessage", plan.get("overview", "Execute automation workflow"))
|
|
|
|
|
|
def replacePlaceholders(template: str, placeholders: Dict[str, str]) -> str:
|
|
"""Replace placeholders in template with actual values. Placeholder format: {{KEY:PLACEHOLDER_NAME}} or {{TIMESTAMP}}"""
|
|
result = template
|
|
|
|
# Replace TIMESTAMP placeholder first (calculated placeholder, not from parameters)
|
|
timestampPattern = "{{TIMESTAMP}}"
|
|
if timestampPattern in result:
|
|
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
|
|
result = result.replace(timestampPattern, timestamp)
|
|
|
|
for placeholderName, value in placeholders.items():
|
|
pattern = f"{{{{KEY:{placeholderName}}}}}"
|
|
|
|
# Check if placeholder is in an array context like ["{{KEY:...}}"]
|
|
# If value is a JSON array/dict, we should replace the entire ["{{KEY:...}}"] with the array
|
|
arrayPattern = f'["{pattern}"]'
|
|
if arrayPattern in result:
|
|
# Check if value is a JSON array/dict
|
|
isArrayValue = False
|
|
arrayValue = None
|
|
|
|
if isinstance(value, (list, dict)):
|
|
isArrayValue = True
|
|
arrayValue = json.dumps(value)
|
|
elif isinstance(value, str):
|
|
try:
|
|
parsed = json.loads(value)
|
|
if isinstance(parsed, (list, dict)):
|
|
isArrayValue = True
|
|
arrayValue = value # Already valid JSON string
|
|
except (json.JSONDecodeError, ValueError):
|
|
pass
|
|
|
|
if isArrayValue:
|
|
# Replace ["{{KEY:...}}"] with the array value
|
|
result = result.replace(arrayPattern, arrayValue)
|
|
continue # Skip the regular replacement below
|
|
|
|
# Regular replacement - check if in quoted context
|
|
patternStart = result.find(pattern)
|
|
isQuoted = False
|
|
if patternStart > 0:
|
|
charBefore = result[patternStart - 1] if patternStart > 0 else None
|
|
patternEnd = patternStart + len(pattern)
|
|
charAfter = result[patternEnd] if patternEnd < len(result) else None
|
|
if charBefore == '"' and charAfter == '"':
|
|
isQuoted = True
|
|
|
|
# Handle different value types
|
|
if isinstance(value, (list, dict)):
|
|
# Python list/dict - convert to JSON
|
|
replacement = json.dumps(value)
|
|
elif isinstance(value, str):
|
|
# String value - check if it's a JSON string representing list/dict
|
|
try:
|
|
parsed = json.loads(value)
|
|
if isinstance(parsed, (list, dict)):
|
|
# It's a JSON string of a list/dict
|
|
if isQuoted:
|
|
# In quoted context, escape the JSON string
|
|
escaped = json.dumps(value)
|
|
replacement = escaped[1:-1] # Remove outer quotes
|
|
else:
|
|
# In unquoted context, use JSON directly
|
|
replacement = value
|
|
else:
|
|
# It's a JSON string of a primitive
|
|
if isQuoted:
|
|
escaped = json.dumps(value)
|
|
replacement = escaped[1:-1]
|
|
else:
|
|
replacement = value
|
|
except (json.JSONDecodeError, ValueError):
|
|
# Not valid JSON - treat as plain string
|
|
if isQuoted:
|
|
escaped = json.dumps(value)
|
|
replacement = escaped[1:-1]
|
|
else:
|
|
replacement = value
|
|
else:
|
|
# Numbers, booleans, None - convert to string
|
|
replacement = str(value)
|
|
result = result.replace(pattern, replacement)
|
|
return result
|
|
|