SPB Git forge
28commits 1branches 0releases
7.7 MBsize
maindefault branch
10 days agolast push
Python 66.3% TypeScript 22.7% JavaScript 8.6% HTML 1.4% CSS 0.7%
4.0 KB · 61 lines python
Raw Blame History
1"""Industry Atlas: `/industries`, `/industries/{slug}` (cached 300 s)."""2from __future__ import annotations34from typing import Any56from fastapi import APIRouter, HTTPException, Request78from companyatlas.api import aggregates as agg9from companyatlas.api import queries as q10from companyatlas.api import serializers as ser11from companyatlas.api.common import cached, cached_response12from companyatlas.db import connection, fetch_all, fetch_one1314ORDER = 2015router = APIRouter(prefix="/api/v1", tags=["industries"])161718@router.get("/industries", summary="Living index per industry")19async def industries(request: Request) -> Any:20    return cached_response(request, {"items": await agg.cached_industry_rows()}, 300)212223@router.get("/industries/{slug}", summary="Industry detail")24async def industry_detail(slug: str, request: Request) -> Any:25    slug = slug.strip().lower()[:80]2627    async def produce() -> dict[str, Any] | None:28        rows = await agg.cached_industry_rows()29        row = next((r for r in rows if r["slug"] == slug), None)30        async with connection() as conn:31            if row is None:32                tax = await fetch_one(conn, "select slug, name, parent_slug, description from industries where slug = :s", s=slug)33                if tax is None:34                    return None35                row = {**tax, "companies": 0, "events_7d": 0, "events_30d": 0, "hiring_momentum_30d": None, "activity_score": None, "ai_adoption": None,36                       "top_event_types": []}37            where, params = q.company_filters(industry=slug, status="ACTIVE")38            ids, _total = await q.company_page_ids(conn, where, params, sort="activity", limit=24)39            companies = [ser.company_card(r) for r in await q.fetch_cards_by_ids(conn, ids, sparkline=True)]40            events = await agg.live_events(conn, 20, industry=slug)41            d30 = q.days_ago(30)42            h = await fetch_one(conn, "select count(*) filter (where j.status = 'open') as open, count(*) filter (where j.first_seen_at >= :d) as new_30d, "43                                      "count(*) filter (where j.removed_at >= :d) as removed_30d from jobs j join companies c on c.id = j.company_id "44                                      "where cast(:s as text) = any(c.industries)", d=d30, s=slug) or {}45            series = await fetch_all(conn, "select ms.day, avg(ms.value) as value, avg(ms.confidence) as confidence from metric_series ms "46                                           "join companies c on c.id = ms.company_id where ms.metric = 'activity_score' and cast(:s as text) = any(c.industries) "47                                           "and ms.day >= :d group by ms.day order by ms.day", s=slug, d=q.days_ago(90).date())48            countries = await fetch_all(conn, "select country, count(*) as companies from companies c where cast(:s as text) = any(c.industries) and "49                                              "country is not null and status = 'ACTIVE' group by country order by companies desc limit 50", s=slug)50            children = await fetch_all(conn, "select slug, name from industries where parent_slug = :s order by sort_order, name", s=slug)51            signals = await fetch_all(conn, "select * from signals where scope = 'industry' and scope_key = :s and status = 'active' order by detected_at desc limit 10", s=slug)52        return {**row, "companies_total": row["companies"], "companies": companies, "events": events,53                "hiring": {"open": int(h.get("open") or 0), "new_30d": int(h.get("new_30d") or 0), "removed_30d": int(h.get("removed_30d") or 0),54                           "momentum_30d": row.get("hiring_momentum_30d")},55                "series": [ser.metric_point(r) for r in series], "countries": [{"country": r["country"], "companies": int(r["companies"])} for r in countries],56                "trending": [], "children": children, "signals": [ser.signal(s) for s in signals]}57    payload = await cached(f"industry:{slug}", 300, produce)58    if payload is None:59        raise HTTPException(status_code=404, detail="industry not found")60    return cached_response(request, payload, 300)61