From f1d9a89d382f2bfb8e55fb6fc707a98922b576d5 Mon Sep 17 00:00:00 2001 From: Bhavesh Mandalapu Date: Sun, 26 Apr 2026 14:26:39 -0500 Subject: [PATCH 1/3] Fix verified claims count --- app/api/v1/endpoints/claims.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/v1/endpoints/claims.py b/app/api/v1/endpoints/claims.py index df8ed6f..6164430 100644 --- a/app/api/v1/endpoints/claims.py +++ b/app/api/v1/endpoints/claims.py @@ -102,7 +102,7 @@ def list_claims( verified = session.exec( select(func.count()) .select_from(Claim) - .where(col(Claim.fact_check_status).ilike("verified")) + .where(col(Claim.fact_check_status).ilike("verified%")) ).one() disputed = session.exec( select(func.count()) From 0f2f4813286ae384895819aaf1f2a4eb3318d25b Mon Sep 17 00:00:00 2001 From: Bhavesh Mandalapu Date: Sun, 26 Apr 2026 14:38:17 -0500 Subject: [PATCH 2/3] Fix executive page graph API --- app/api/v1/endpoints/overview.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/api/v1/endpoints/overview.py b/app/api/v1/endpoints/overview.py index 0230f17..5285a43 100644 --- a/app/api/v1/endpoints/overview.py +++ b/app/api/v1/endpoints/overview.py @@ -92,15 +92,12 @@ def executive_overview(session: Session = Depends(get_session)): ) ).all() - # Bucket into 2-week intervals + # Bucket by day buckets: dict[str, dict[str, int]] = defaultdict( lambda: {label: 0 for label in top_labels} ) for created_at, label in rows: - bucket_start = ninety_days_ago + timedelta( - weeks=2 * ((created_at - ninety_days_ago).days // 14) - ) - bucket_key = bucket_start.strftime("%Y-%m-%d") + bucket_key = created_at.strftime("%Y-%m-%d") buckets[bucket_key][label] += 1 for date_key in sorted(buckets): From 18a4f32e4997f168ac1ae1881724b8fa0ba99690 Mon Sep 17 00:00:00 2001 From: Bhavesh Mandalapu Date: Sun, 26 Apr 2026 14:51:45 -0500 Subject: [PATCH 3/3] Trend analytics sentiment shift bug fix --- app/api/v1/endpoints/sentiment.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app/api/v1/endpoints/sentiment.py b/app/api/v1/endpoints/sentiment.py index d5f3f10..dd083a1 100644 --- a/app/api/v1/endpoints/sentiment.py +++ b/app/api/v1/endpoints/sentiment.py @@ -13,8 +13,7 @@ from __future__ import annotations from collections import defaultdict -from datetime import datetime, timedelta, timezone -from typing import Optional +from datetime import UTC, datetime, timedelta from fastapi import APIRouter, HTTPException, Query from supabase import create_client @@ -43,7 +42,7 @@ } -def _normalize_sentiment_label(raw: Optional[str]) -> Optional[str]: +def _normalize_sentiment_label(raw: str | None) -> str | None: """Map misinfo_checker's labels (POSITIVE / NEGATIVE / NEUTRAL) to canonical lowercase keys. Tolerant of stray casing / variants.""" if raw is None: @@ -58,7 +57,7 @@ def _normalize_sentiment_label(raw: Optional[str]) -> Optional[str]: return None -def _parse_created_at(raw: Optional[str]) -> Optional[datetime]: +def _parse_created_at(raw: str | None) -> datetime | None: """Supabase returns timestamps as ISO strings; normalize to UTC datetime.""" if not raw: return None @@ -67,8 +66,8 @@ def _parse_created_at(raw: Optional[str]) -> Optional[datetime]: except (ValueError, TypeError): return None if dt.tzinfo is None: - dt = dt.replace(tzinfo=timezone.utc) - return dt.astimezone(timezone.utc) + dt = dt.replace(tzinfo=UTC) + return dt.astimezone(UTC) @router.get("/overview/sentiment-shift", response_model=SentimentShiftResponse) @@ -89,7 +88,10 @@ def sentiment_shift( raise HTTPException(status_code=503, detail="Supabase not configured") window_days, bucket_size_days = _RANGE_CONFIG[range_] - now = datetime.now(timezone.utc) + # Truncate to midnight UTC so bucket boundaries fall on calendar dates, + # preventing a single day's claims from being split across two buckets + # when the window boundary lands mid-day. + now = datetime.now(UTC).replace(hour=0, minute=0, second=0, microsecond=0) window_start = now - timedelta(days=window_days) sb = create_client(settings.SUPABASE_URL, settings.SUPABASE_SERVICE_ROLE_KEY)