studio / renderer /automation /templates.py
Ava2lon's picture
Upload 52 files
5d782cc verified
Raw
History Blame Contribute Delete
3.1 kB
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