diff --git a/semantica/explorer/routes/analytics.py b/semantica/explorer/routes/analytics.py index 1b8b13f9..39d08e5a 100644 --- a/semantica/explorer/routes/analytics.py +++ b/semantica/explorer/routes/analytics.py @@ -1,11 +1,11 @@ -""" +""" Analytics routes for graph metrics and validation. """ import asyncio from typing import Optional -from fastapi import APIRouter, Depends, Query +from fastapi import APIRouter, Depends, Query, HTTPException, Response from ..dependencies import get_session from ..schemas import AnalyticsResponse, ValidationIssue, ValidationReportResponse @@ -16,6 +16,7 @@ router = APIRouter(prefix="/api/analytics", tags=["Analytics"]) @router.get("", response_model=AnalyticsResponse) async def get_analytics( + response: Response, metrics: Optional[str] = Query( None, description="Comma-separated metrics to compute: centrality,community,connectivity", @@ -25,6 +26,7 @@ async def get_analytics( requested = set((metrics or "centrality,community,connectivity").split(",")) graph_dict = await asyncio.to_thread(session.build_graph_dict) result: dict = {} + any_failed = False if "centrality" in requested and session.centrality is not None: try: @@ -34,6 +36,7 @@ async def get_analytics( ) except Exception as exc: result["centrality"] = {"error": str(exc)} + any_failed = True if "community" in requested and session.community is not None: try: @@ -43,6 +46,7 @@ async def get_analytics( ) except Exception as exc: result["community"] = {"error": str(exc)} + any_failed = True if "connectivity" in requested and session.connectivity is not None: try: @@ -52,6 +56,10 @@ async def get_analytics( ) except Exception as exc: result["connectivity"] = {"error": str(exc)} + any_failed = True + + if any_failed: + response.status_code = 207 return AnalyticsResponse(**result) diff --git a/semantica/explorer/routes/ontology.py b/semantica/explorer/routes/ontology.py index 411a6bb4..6ce0470f 100644 --- a/semantica/explorer/routes/ontology.py +++ b/semantica/explorer/routes/ontology.py @@ -1402,6 +1402,7 @@ async def create_ontology( except Exception as exc: logger.exception("Failed to generate ontology from sample data; falling back to minimal ontology.") logger.warning(f"OntologyEngine.from_data error: {exc}") + raise HTTPException(status_code=500, detail=str(exc)) elif body.mode == "text" and body.schema_text: try: @@ -1472,6 +1473,7 @@ async def create_ontology( except Exception as exc: logger.exception("Failed to generate ontology from schema text; falling back to minimal ontology.") logger.warning(f"OntologyEngine.from_text error: {exc}") + raise HTTPException(status_code=500, detail=str(exc)) nodes_added = await asyncio.to_thread(session.add_nodes, nodes) edges_added = await asyncio.to_thread(session.add_edges, edges) diff --git a/semantica/explorer/routes/temporal.py b/semantica/explorer/routes/temporal.py index 31cca479..71c47e52 100644 --- a/semantica/explorer/routes/temporal.py +++ b/semantica/explorer/routes/temporal.py @@ -1,4 +1,4 @@ -""" +""" Temporal routes for snapshots, diffs, and pattern detection. """ @@ -8,7 +8,7 @@ import re from datetime import datetime, timedelta, timezone, UTC from typing import List, Optional -from fastapi import APIRouter, Depends, Query +from fastapi import APIRouter, Depends, Query, HTTPException from pydantic import BaseModel from ..dependencies import get_session @@ -117,7 +117,7 @@ async def temporal_patterns( return TemporalPatternResponse(patterns=[]) except Exception as exc: logger.warning("temporal_patterns failed: %s", exc, exc_info=True) - return TemporalPatternResponse(patterns=[]) + raise HTTPException(status_code=500, detail=str(exc)) @router.get("/bounds", response_model=TemporalBoundsResponse)