$ cat node-template.py
S
SVG Generator
// Generate a vector SVG illustration or icon from a text prompt, or vectorize a connected raster image.
AI
Image
#svg#vector#illustration#icon#vectorize
template.py
1"""svg-generator — text-to-SVG or raster-to-SVG (gais-svg-creation).23Two modes, picked by what is connected:4- an ``image`` is connected -> vectorize that raster image (prompt ignored);5- otherwise -> generate from the ``prompt`` (required).67Writes the SVG to /data/output/image.svg (``svg`` port, Image family, so the8canvas previews it) and also returns the raw markup on ``svg_code`` for9chaining into text/LLM/slide nodes. Privileged transport lives in the gais10SDK; no os/pathlib/HTTP here (lint-blocked).11"""1213from __future__ import annotations1415import json16import sys17import traceback18from typing import Any1920from gais import Gais2122INPUT_DIR = "/data/input"23OUTPUT_DIR = "/data/output"2425OUTPUT_FILENAME = "image.svg"2627TEMPERATURE_MIN = 0.128TEMPERATURE_MAX = 1.0293031def _input_file_path(inputs: dict[str, Any], key: str) -> str | None:32 """Upstream file ports deliver a bare filename under /data/input."""33 name = inputs.get(key)34 if not name or not isinstance(name, str):35 return None36 base = name.replace("\\", "/").rsplit("/", 1)[-1].strip()37 if not base or base in (".", ".."):38 return None39 return f"{INPUT_DIR}/{base}"404142def _parse_temperature(raw: Any) -> float | None:43 """None/empty -> backend default; otherwise clamp into [0.1, 1.0]."""44 if raw is None or (isinstance(raw, str) and not raw.strip()):45 return None46 try:47 value = float(raw)48 except (TypeError, ValueError):49 raise ValueError(f"Temperature must be a number, got {raw!r}") from None50 return min(max(value, TEMPERATURE_MIN), TEMPERATURE_MAX)515253def _parse_seed(raw: Any) -> int | None:54 """None/empty/negative -> None (random seed); otherwise an int."""55 if raw is None or isinstance(raw, bool):56 return None57 if isinstance(raw, str) and not raw.strip():58 return None59 try:60 value = int(float(raw))61 except (TypeError, ValueError):62 raise ValueError(f"Seed must be an integer, got {raw!r}") from None63 return value if value >= 0 else None646566def process(inputs: dict[str, Any]) -> dict[str, Any]:67 image_path = _input_file_path(inputs, "image")68 prompt_raw = inputs.get("prompt")69 prompt = prompt_raw.strip() if isinstance(prompt_raw, str) else ""70 temperature = _parse_temperature(inputs.get("temperature"))71 seed = _parse_seed(inputs.get("seed"))7273 if image_path is not None:74 if prompt:75 print(76 "[svg-generator] image connected: vectorizing it, prompt ignored",77 file=sys.stderr,78 )79 mode = "vectorize"80 result = Gais.svg.vectorize(image=image_path, temperature=temperature, seed=seed)81 else:82 if not prompt:83 raise ValueError(84 "Provide a prompt to generate an SVG, or connect an image to vectorize"85 )86 mode = "create"87 result = Gais.svg.create(prompt=prompt, temperature=temperature, seed=seed)8889 svg_bytes = result.content or b""90 svg_code = result.text or svg_bytes.decode("utf-8", errors="replace")91 if not svg_bytes and svg_code:92 svg_bytes = svg_code.encode("utf-8")93 if not svg_bytes:94 raise RuntimeError("gais-svg-creation returned an empty SVG")9596 with open(f"{OUTPUT_DIR}/{OUTPUT_FILENAME}", "wb") as fh:97 fh.write(svg_bytes)9899 meta = result.metadata or {}100 print(101 f"[svg-generator] mode={mode} "102 f"time={meta.get('inference_time_ms', 'unknown')}ms "103 f"model_size={meta.get('model_size', 'unknown')} "104 f"seed={meta.get('seed', 'unknown')} "105 f"subtype={meta.get('subtype', 'unknown')} "106 f"candidates_valid={meta.get('candidates_valid', 'unknown')} "107 f"bytes={len(svg_bytes)}",108 file=sys.stderr,109 )110111 return {"svg": OUTPUT_FILENAME, "svg_code": svg_code}112113114def main() -> None:115 try:116 envelope = json.loads(sys.stdin.read() or "{}")117 if not isinstance(envelope, dict):118 envelope = {}119 inputs = envelope.get("inputs", {}) or {}120 json.dump(process(inputs), sys.stdout)121 except Exception as e:122 print(123 json.dumps({124 "error": str(e),125 "errorType": type(e).__name__,126 "traceback": traceback.format_exc(),127 }),128 file=sys.stderr,129 )130 sys.exit(1)131132133if __name__ == "__main__":134 main()135$ git log --oneline
v1.0.0
HEAD
2026-09-28New: text-to-SVG / image-to-SVG via the gais svg.create / svg.vectorize ops (PR #1340 feat/svg-creation)