62 lines
2.1 KiB
Python
62 lines
2.1 KiB
Python
"""Sentiment router — sentiment data endpoints."""
|
|
|
|
import json
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.dependencies import get_db, require_access
|
|
from app.schemas.common import APIEnvelope
|
|
from app.schemas.sentiment import CitationItem, SentimentResponse, SentimentScoreResult
|
|
from app.services.sentiment_service import (
|
|
compute_sentiment_dimension_score,
|
|
get_sentiment_scores,
|
|
)
|
|
|
|
router = APIRouter(tags=["sentiment"])
|
|
|
|
|
|
def _parse_citations(citations_json: str) -> list[CitationItem]:
|
|
"""Deserialize citations_json, defaulting to [] on invalid JSON."""
|
|
try:
|
|
raw = json.loads(citations_json)
|
|
except (json.JSONDecodeError, TypeError):
|
|
return []
|
|
if not isinstance(raw, list):
|
|
return []
|
|
return [CitationItem(**item) for item in raw if isinstance(item, dict)]
|
|
|
|
|
|
@router.get("/sentiment/{symbol}", response_model=APIEnvelope)
|
|
async def read_sentiment(
|
|
symbol: str,
|
|
lookback_hours: float = Query(24, gt=0, description="Lookback window in hours"),
|
|
_user=Depends(require_access),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> APIEnvelope:
|
|
"""Get recent sentiment scores and computed dimension score for a symbol."""
|
|
scores = await get_sentiment_scores(db, symbol, lookback_hours)
|
|
dimension_score = await compute_sentiment_dimension_score(
|
|
db, symbol, lookback_hours
|
|
)
|
|
|
|
data = SentimentResponse(
|
|
symbol=symbol.strip().upper(),
|
|
scores=[
|
|
SentimentScoreResult(
|
|
id=s.id,
|
|
classification=s.classification,
|
|
confidence=s.confidence,
|
|
source=s.source,
|
|
timestamp=s.timestamp,
|
|
reasoning=s.reasoning,
|
|
citations=_parse_citations(s.citations_json),
|
|
)
|
|
for s in scores
|
|
],
|
|
count=len(scores),
|
|
dimension_score=round(dimension_score, 2) if dimension_score is not None else None,
|
|
lookback_hours=lookback_hours,
|
|
)
|
|
return APIEnvelope(status="success", data=data.model_dump())
|