File size: 3,098 Bytes
5d782cc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | from __future__ import annotations
import re
from copy import deepcopy
from typing import Any
PLACEHOLDER = re.compile(r"{{\s*([A-Za-z_][A-Za-z0-9_.-]*)\s*}}")
AUTOMATION_TEMPLATES: dict[str, dict[str, Any]] = {
"vertical-captioned-clip": {
"preset": "tiktok_9_16_fast",
"output_name": "{{output_name}}",
"scenes": "{{scenes}}",
"voiceover": "{{voiceover}}",
"background_music": "{{background_music}}",
"auto_subtitles": True,
"audio_normalize": True,
},
"podcast-clip": {
"preset": "podcast_square",
"output_name": "{{output_name}}",
"scenes": "{{scenes}}",
"auto_subtitles": True,
"audio_normalize": True,
},
"product-promo": {
"preset": "capcut_product_launch",
"output_name": "{{output_name}}",
"scenes": "{{scenes}}",
"watermark": "{{watermark}}",
"background_music": "{{background_music}}",
},
}
def list_automation_templates() -> list[str]:
return sorted(AUTOMATION_TEMPLATES)
def automation_template_catalog() -> dict[str, dict[str, Any]]:
return deepcopy(AUTOMATION_TEMPLATES)
def resolve_render_template(
template: str | dict[str, Any],
variables: dict[str, Any],
overrides: dict[str, Any] | None = None,
) -> dict[str, Any]:
if isinstance(template, str):
if template not in AUTOMATION_TEMPLATES:
raise ValueError(f"Unknown automation template: {template}")
source = deepcopy(AUTOMATION_TEMPLATES[template])
elif isinstance(template, dict):
source = deepcopy(template)
else:
raise ValueError("Template must be a registered name or JSON object")
rendered = _substitute(source, variables)
if not isinstance(rendered, dict):
raise ValueError("Rendered template must produce a JSON object")
return _deep_merge(rendered, overrides or {})
def _substitute(value: Any, variables: dict[str, Any]) -> Any:
if isinstance(value, dict):
return {key: _substitute(item, variables) for key, item in value.items()}
if isinstance(value, list):
return [_substitute(item, variables) for item in value]
if not isinstance(value, str):
return value
exact = PLACEHOLDER.fullmatch(value)
if exact:
return deepcopy(_lookup(variables, exact.group(1)))
return PLACEHOLDER.sub(lambda match: str(_lookup(variables, match.group(1))), value)
def _lookup(variables: dict[str, Any], key: str) -> Any:
value: Any = variables
for part in key.split("."):
if not isinstance(value, dict) or part not in value:
raise ValueError(f"Missing template variable: {key}")
value = value[part]
return value
def _deep_merge(base: dict[str, Any], overrides: dict[str, Any]) -> dict[str, Any]:
output = deepcopy(base)
for key, value in overrides.items():
if isinstance(value, dict) and isinstance(output.get(key), dict):
output[key] = _deep_merge(output[key], value)
else:
output[key] = deepcopy(value)
return output
|