SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%
4.2 KB · 91 lines python
Raw Blame History
1"""/explore/types · /explore/{type} — generic listing for every entity type, plus /frameworks, /datasets, /tools aliases."""2from __future__ import annotations34from typing import Any56from fastapi import APIRouter, Query, Request78from aiatlas.api.common import (9    ENTITY_COLS,10    ENTITY_FROM,11    PAGINATION,12    TYPE_LABELS,13    ApiError,14    Pagination,15    cached,16    entity_summary,17    page,18)19from aiatlas.api.routers.entities import detail_for_type20from aiatlas.db import connection, fetch_all, fetch_val21from aiatlas.ids import ENTITY_TYPES2223router = APIRouter(prefix="/api/v1", tags=["explore"])24SORTS = {"updated": "e.updated_at desc", "name": "e.canonical_name asc", "quality": "coalesce((e.quality->>'score')::float, 0) desc", "first_seen": "e.first_seen_at desc",25         "release": "coalesce(e.attributes->>'release_date', e.attributes->>'published_at', e.attributes->>'latest_release_at') desc nulls last",26         "stars": "(case when e.attributes->>'metric.stars' ~ '^[0-9]+$' then (e.attributes->>'metric.stars')::bigint end) desc nulls last"}272829@router.get("/explore/types")30@cached(300)31async def explore_types(request: Request) -> dict[str, Any]:32    async with connection() as conn:33        rows = await fetch_all(conn, "select entity_type, count(*) as count from entities where merged_into is null group by 1 order by 2 desc, 1")34    return {"items": [{"entity_type": r["entity_type"], "count": int(r["count"]), "label": TYPE_LABELS.get(r["entity_type"], r["entity_type"].replace("_", " ").title())} for r in rows]}353637@router.get("/explore/{type}")38@cached(300)39async def explore_type(request: Request, type: str, p: Pagination = PAGINATION, q: str | None = Query(None, max_length=200), org: str | None = None, status: str | None = None,40                       sort: str = "updated") -> dict[str, Any]:41    etype = type.strip().lower().rstrip("s") if type not in ENTITY_TYPES else type42    aliases = {"companie": "company", "librarie": "library", "universitie": "university", "regulations": "regulation", "hardware": "hardware"}43    etype = aliases.get(etype, etype)44    if etype not in ENTITY_TYPES:45        raise ApiError(404, f"unknown entity type {type!r}")46    if sort not in SORTS:47        raise ApiError(400, f"sort must be one of {', '.join(SORTS)}")48    where = ["e.entity_type = :t", "e.merged_into is null"]49    params: dict[str, Any] = {"t": etype}50    if q:51        where.append("(e.canonical_name ilike :qlike or e.search @@ plainto_tsquery('simple', :q) or exists (select 1 from entity_aliases a where a.entity_id = e.id and a.alias ilike :qlike))")52        params["q"], params["qlike"] = q, f"%{q}%"53    if org:54        where.append("(eo.slug = :org or eo.id = :org or eo.canonical_name ilike :org)")55        params["org"] = org56    if status:57        where.append("e.status = any(cast(:status as text[]))")58        params["status"] = [s.strip() for s in status.split(",") if s.strip()]59    where_sql = " and ".join(where)60    async with connection() as conn:61        rows = await fetch_all(conn, f"select {ENTITY_COLS} from {ENTITY_FROM} where {where_sql} order by {SORTS[sort]}, e.id limit :lim offset :off", lim=p.limit, off=p.offset, **params)62        total = await fetch_val(conn, f"select count(*) from {ENTITY_FROM} where {where_sql}", **params)63    items = []64    for r in rows:65        s = entity_summary(r) or {}66        if etype in ("framework", "library", "runtime", "tool", "agent"):67            s["kind"] = (s.get("attributes") or {}).get("kind")  # canonical framework kind (normalised on read), null when the source did not say68        items.append(s)69    out = page(items, int(total or 0), p)70    out["entity_type"] = etype71    out["label"] = TYPE_LABELS.get(etype, etype.title())72    return out737475@router.get("/frameworks/{slug}")76@cached(300)77async def get_framework(request: Request, slug: str) -> dict[str, Any]:78    return await detail_for_type(slug, ("framework", "library", "runtime"))798081@router.get("/datasets/{slug}")82@cached(300)83async def get_dataset(request: Request, slug: str) -> dict[str, Any]:84    return await detail_for_type(slug, ("dataset",))858687@router.get("/tools/{slug}")88@cached(300)89async def get_tool(request: Request, slug: str) -> dict[str, Any]:90    return await detail_for_type(slug, ("tool", "agent", "application", "product", "mcp_server"))91