diff --git a/server.py b/server.py index f56abdc..3be7ff7 100644 --- a/server.py +++ b/server.py @@ -30,6 +30,7 @@ from tasks import render_effect # L2 server for auth verification L2_SERVER = os.environ.get("L2_SERVER", "http://localhost:8200") +L2_DOMAIN = os.environ.get("L2_DOMAIN", "artdag.rose-ash.com") # Cache directory (use /data/cache in Docker, ~/.artdag/cache locally) CACHE_DIR = Path(os.environ.get("CACHE_DIR", str(Path.home() / ".artdag" / "cache"))) @@ -96,7 +97,8 @@ class RunStatus(BaseModel): celery_task_id: Optional[str] = None effects_commit: Optional[str] = None effect_url: Optional[str] = None # URL to effect source code - username: Optional[str] = None # Owner of the run + username: Optional[str] = None # Owner of the run (ActivityPub actor ID) + infrastructure: Optional[dict] = None # Hardware/software used for rendering # ============ Auth ============ @@ -274,6 +276,9 @@ async def create_run(request: RunRequest, username: str = Depends(get_required_u # Generate output name if not provided output_name = request.output_name or f"{request.recipe}-{run_id[:8]}" + # Format username as ActivityPub actor ID + actor_id = f"@{username}@{L2_DOMAIN}" + # Create run record run = RunStatus( run_id=run_id, @@ -282,7 +287,7 @@ async def create_run(request: RunRequest, username: str = Depends(get_required_u inputs=request.inputs, output_name=output_name, created_at=datetime.now(timezone.utc).isoformat(), - username=username + username=actor_id ) # Submit to Celery @@ -324,6 +329,9 @@ async def get_run(run_id: str): run.effects_commit = effects[0].get("repo_commit") run.effect_url = effects[0].get("repo_url") + # Extract infrastructure info + run.infrastructure = result.get("infrastructure") + # Cache the output output_path = Path(result.get("output", {}).get("local_path", "")) if output_path.exists(): @@ -900,6 +908,8 @@ async def ui_detail_page(run_id: str): if effects: run.effects_commit = effects[0].get("repo_commit") run.effect_url = effects[0].get("repo_url") + # Extract infrastructure info + run.infrastructure = result.get("infrastructure") output_path = Path(result.get("output", {}).get("local_path", "")) if output_path.exists(): cache_file(output_path) @@ -979,10 +989,18 @@ async def ui_detail_page(run_id: str): html += f'''

Provenance

+
+
Owner
+
{run.username or "anonymous"}
+
Effect
+
+
Effects Commit
+
{run.effects_commit or "N/A"}
+
Input(s)
@@ -1002,6 +1020,20 @@ async def ui_detail_page(run_id: str):
''' + # Infrastructure section + if run.infrastructure: + software = run.infrastructure.get("software", {}) + hardware = run.infrastructure.get("hardware", {}) + html += f''' +
+
Infrastructure
+
+ Software: {software.get("name", "unknown")} ({software.get("content_hash", "unknown")[:16]}...)
+ Hardware: {hardware.get("name", "unknown")} ({hardware.get("content_hash", "unknown")[:16]}...) +
+
+ ''' + html += f'''
Run ID
@@ -1042,6 +1074,7 @@ async def ui_detail_page(run_id: str): "created_at": run.created_at, "completed_at": run.completed_at, "username": run.username, + "infrastructure": run.infrastructure, "error": run.error }, indent=2) @@ -1077,6 +1110,8 @@ async def ui_run_partial(run_id: str): if effects: run.effects_commit = effects[0].get("repo_commit") run.effect_url = effects[0].get("repo_url") + # Extract infrastructure info + run.infrastructure = result.get("infrastructure") output_path = Path(result.get("output", {}).get("local_path", "")) if output_path.exists(): cache_file(output_path) diff --git a/tasks.py b/tasks.py index 73b8906..5f0df0c 100644 --- a/tasks.py +++ b/tasks.py @@ -17,6 +17,7 @@ from celery_app import app # Add effects to path (use env var in Docker, fallback to home dir locally) EFFECTS_PATH = Path(os.environ.get("EFFECTS_PATH", str(Path.home() / "artdag-effects"))) +ARTDAG_PATH = Path(os.environ.get("ARTDAG_PATH", str(Path.home() / "art" / "artdag"))) def get_effects_commit() -> str: @@ -35,6 +36,22 @@ def get_effects_commit() -> str: return "unknown" +def get_artdag_commit() -> str: + """Get current git commit hash of artdag repo.""" + try: + result = subprocess.run( + ["git", "rev-parse", "HEAD"], + cwd=ARTDAG_PATH, + capture_output=True, + text=True + ) + if result.returncode == 0: + return result.stdout.strip() + except Exception: + pass + return "unknown" + + sys.path.insert(0, str(EFFECTS_PATH / "dog")) @@ -128,11 +145,13 @@ def render_effect(self, input_hash: str, effect_name: str, output_name: str) -> # Build effect info based on source if effect_name == "identity": # Identity is from artdag package on GitHub + artdag_commit = get_artdag_commit() effect_info = { "name": f"effect:{effect_name}", "content_hash": REGISTRY[f"effect:{effect_name}"]["hash"], "repo": "github", - "repo_url": "https://github.com/gilesbradshaw/art-dag/blob/main/artdag/nodes/effect.py" + "repo_commit": artdag_commit, + "repo_url": f"https://github.com/gilesbradshaw/art-dag/blob/{artdag_commit}/artdag/nodes/effect.py" } else: # Other effects from rose-ash effects repo