""" Art-DAG fragment endpoints. Exposes HTML fragments at ``/internal/fragments/{type}`` for consumption by coop apps via the fragment client. """ import os from fastapi import APIRouter, Request, Response router = APIRouter() # Registry of fragment handlers: type -> async callable(request) returning HTML str _handlers: dict[str, object] = {} FRAGMENT_HEADER = "X-Fragment-Request" @router.get("/internal/fragments/{fragment_type}") async def get_fragment(fragment_type: str, request: Request): if not request.headers.get(FRAGMENT_HEADER): return Response(content="", status_code=403) handler = _handlers.get(fragment_type) if handler is None: return Response(content="", media_type="text/html", status_code=200) html = await handler(request) return Response(content=html, media_type="text/html", status_code=200) # --- nav-item fragment --- async def _nav_item_handler(request: Request) -> str: from artdag_common import render_fragment templates = request.app.state.templates artdag_url = os.getenv("APP_URL_ARTDAG", "https://celery-artdag.rose-ash.com") return render_fragment(templates, "fragments/nav_item.html", artdag_url=artdag_url) _handlers["nav-item"] = _nav_item_handler # --- link-card fragment --- async def _link_card_handler(request: Request) -> str: from artdag_common import render_fragment import database templates = request.app.state.templates cid = request.query_params.get("cid", "") content_type = request.query_params.get("type", "media") slug = request.query_params.get("slug", "") keys_raw = request.query_params.get("keys", "") # Batch mode: return multiple cards separated by markers if keys_raw: keys = [k.strip() for k in keys_raw.split(",") if k.strip()] parts = [] for key in keys: parts.append(f"") card_html = await _render_single_link_card( templates, key, content_type, ) parts.append(card_html) return "\n".join(parts) # Single mode: use cid or slug lookup_cid = cid or slug if not lookup_cid: return "" return await _render_single_link_card(templates, lookup_cid, content_type) async def _render_single_link_card(templates, cid: str, content_type: str) -> str: import database from artdag_common import render_fragment if not cid: return "" artdag_url = os.getenv("APP_URL_ARTDAG", "https://celery-artdag.rose-ash.com") # Try item_types first (has metadata) item = await database.get_item_types(cid) # get_item_types returns a list; pick best match for content_type meta = None if item: for it in item: if it.get("type") == content_type: meta = it break if not meta: meta = item[0] # Try friendly name for display friendly = None if meta and meta.get("actor_id"): friendly = await database.get_friendly_name_by_cid(meta["actor_id"], cid) # Try run cache if type is "run" run = None if content_type == "run": run = await database.get_run_cache(cid) title = "" description = "" link = "" if friendly: title = friendly.get("display_name") or friendly.get("base_name", cid[:12]) elif meta: title = meta.get("filename") or meta.get("description", cid[:12]) elif run: title = f"Run {cid[:12]}" else: title = cid[:16] if meta: description = meta.get("description", "") if content_type == "run": link = f"{artdag_url}/runs/{cid}" elif content_type == "recipe": link = f"{artdag_url}/recipes/{cid}" elif content_type == "effect": link = f"{artdag_url}/effects/{cid}" else: link = f"{artdag_url}/cache/{cid}" return render_fragment( templates, "fragments/link_card.html", title=title, description=description, link=link, cid=cid, content_type=content_type, artdag_url=artdag_url, ) _handlers["link-card"] = _link_card_handler