Add COMPOUND node execution and S-expression API
- Execute COMPOUND nodes with combined FFmpeg filter chain - Handle TRANSFORM, RESIZE, SEGMENT filters in chain - Migrate orchestrator to S-expression recipes (remove YAML) - Update API endpoints to use recipe_sexp parameter - Extract analysis nodes from recipe for dynamic analysis Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,6 @@ import uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import yaml
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -26,9 +25,8 @@ RUNS_KEY_PREFIX = "artdag:run:"
|
||||
|
||||
|
||||
class PlanRequest(BaseModel):
|
||||
recipe_yaml: str
|
||||
recipe_sexp: str
|
||||
input_hashes: Dict[str, str]
|
||||
features: List[str] = ["beats", "energy"]
|
||||
|
||||
|
||||
class ExecutePlanRequest(BaseModel):
|
||||
@@ -37,9 +35,8 @@ class ExecutePlanRequest(BaseModel):
|
||||
|
||||
|
||||
class RecipeRunRequest(BaseModel):
|
||||
recipe_yaml: str
|
||||
recipe_sexp: str
|
||||
input_hashes: Dict[str, str]
|
||||
features: List[str] = ["beats", "energy"]
|
||||
|
||||
|
||||
def compute_run_id(input_hashes: List[str], recipe: str, recipe_hash: str = None) -> str:
|
||||
@@ -68,9 +65,8 @@ async def generate_plan_endpoint(
|
||||
|
||||
try:
|
||||
task = generate_plan.delay(
|
||||
recipe_yaml=request.recipe_yaml,
|
||||
recipe_sexp=request.recipe_sexp,
|
||||
input_hashes=request.input_hashes,
|
||||
features=request.features,
|
||||
)
|
||||
|
||||
# Wait for result (plan generation is usually fast)
|
||||
@@ -136,15 +132,16 @@ async def run_recipe_endpoint(
|
||||
Returns immediately with run_id. Poll /api/run/{run_id} for status.
|
||||
"""
|
||||
from tasks.orchestrate import run_recipe
|
||||
from artdag.sexp import compile_string
|
||||
import database
|
||||
|
||||
redis = get_redis_client()
|
||||
cache = get_cache_manager()
|
||||
|
||||
# Parse recipe name
|
||||
# Parse recipe name from S-expression
|
||||
try:
|
||||
recipe_data = yaml.safe_load(request.recipe_yaml)
|
||||
recipe_name = recipe_data.get("name", "unknown")
|
||||
compiled = compile_string(request.recipe_sexp)
|
||||
recipe_name = compiled.name or "unknown"
|
||||
except Exception:
|
||||
recipe_name = "unknown"
|
||||
|
||||
@@ -152,7 +149,7 @@ async def run_recipe_endpoint(
|
||||
run_id = compute_run_id(
|
||||
list(request.input_hashes.values()),
|
||||
recipe_name,
|
||||
hashlib.sha3_256(request.recipe_yaml.encode()).hexdigest()
|
||||
hashlib.sha3_256(request.recipe_sexp.encode()).hexdigest()
|
||||
)
|
||||
|
||||
# Check if already completed
|
||||
@@ -171,9 +168,8 @@ async def run_recipe_endpoint(
|
||||
# Submit to Celery
|
||||
try:
|
||||
task = run_recipe.delay(
|
||||
recipe_yaml=request.recipe_yaml,
|
||||
recipe_sexp=request.recipe_sexp,
|
||||
input_hashes=request.input_hashes,
|
||||
features=request.features,
|
||||
run_id=run_id,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user