$ cat node-template.py

Infographic Renderer

// Renders AntV Infographic DSL syntax into an image. Accepts the declarative DSL format (starting with 'infographic <template-name>') and produces a PNG or SVG output. Use this to render manually written or LLM-generated infographic syntax.

Process
Document
template.py
1import os2import sys3import json4import traceback56try:7    import requests8except ImportError:9    import subprocess10    subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"])11    import requests1213EMBLEMA_API_BASE_URL = os.getenv("EMBLEMA_API_BASE_URL", "http://localhost:3000")14USER_TOKEN = os.getenv("USER_TOKEN")15OUTPUT_DIR = "/data/output"161718def render_infographic(syntax, fmt="png", width=1920, height=1080, scale=2):19    """Call the Emblema infographic rendering API."""20    url = f"{EMBLEMA_API_BASE_URL}/api/v2/helpers/infographic/render"2122    headers = {23        "Content-Type": "application/json",24    }25    if USER_TOKEN:26        headers["Authorization"] = f"Bearer {USER_TOKEN}"2728    payload = {29        "syntax": syntax,30        "format": fmt,31        "width": width,32        "height": height,33        "scale": scale,34    }3536    print(f"Calling render API: {url}", file=sys.stderr)37    print(f"Payload: format={fmt}, width={width}, height={height}, scale={scale}, syntax_length={len(syntax)}", file=sys.stderr)3839    response = requests.post(url, headers=headers, json=payload, timeout=60)4041    if response.status_code != 200:42        try:43            error_detail = response.json()44            error_msg = error_detail.get("message", response.text)45        except Exception:46            error_msg = response.text47        raise RuntimeError(f"Render API returned {response.status_code}: {error_msg}")4849    return response.content, response.headers.get("Content-Type", "image/png")505152def main():53    try:54        input_json = sys.stdin.read()55        execution_input = json.loads(input_json)56        inputs = execution_input.get("inputs", {})5758        syntax = inputs.get("syntax", "")59        fmt = inputs.get("format", "png")60        width = int(inputs.get("width", 1920))61        height = int(inputs.get("height", 1080))62        scale = int(inputs.get("scale", 2))6364        if not syntax or not syntax.strip():65            raise ValueError("Infographic DSL syntax is required")6667        if not syntax.strip().startswith("infographic "):68            raise ValueError("DSL syntax must start with 'infographic <template-name>'")6970        os.makedirs(OUTPUT_DIR, exist_ok=True)7172        # Call rendering API73        image_data, content_type = render_infographic(syntax, fmt, width, height, scale)7475        # Determine file extension from format76        ext = "svg" if fmt == "svg" else "png"77        out_filename = f"infographic.{ext}"78        out_path = os.path.join(OUTPUT_DIR, out_filename)7980        with open(out_path, "wb") as f:81            f.write(image_data)8283        print(f"Rendered infographic: {out_filename} ({len(image_data)} bytes)", file=sys.stderr)8485        output = {86            "image": out_filename,87        }88        print(json.dumps(output, indent=2))8990    except Exception as e:91        error_output = {92            "error": str(e),93            "errorType": type(e).__name__,94            "traceback": traceback.format_exc(),95        }96        print(json.dumps(error_output), file=sys.stderr)97        sys.exit(1)9899100if __name__ == "__main__":101    main()