feat: filter tackle analytics by role
This commit is contained in:
@@ -4,7 +4,7 @@ from collections import defaultdict
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from math import exp, log
|
||||
|
||||
from fastapi import APIRouter, Query
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session, joinedload, selectinload
|
||||
|
||||
@@ -27,10 +27,13 @@ def tackle_combinations(
|
||||
waterbody: str | None = None,
|
||||
fish: str | None = None,
|
||||
method: str | None = None,
|
||||
role: str | None = None,
|
||||
hours: int = Query(72, ge=24, le=168),
|
||||
min_samples: int = Query(3, ge=1, le=100),
|
||||
min_players: int = Query(2, ge=1, le=100),
|
||||
) -> list[TackleCombinationOut]:
|
||||
if role is not None and role not in {"lure", "bait", "rig", "rod", "reel", "line", "hook", "float", "sinker"}:
|
||||
raise HTTPException(status_code=422, detail="invalid tackle role")
|
||||
now = datetime.now(timezone.utc)
|
||||
query = select(CatchReport).options(
|
||||
joinedload(CatchReport.fish), joinedload(CatchReport.waterbody),
|
||||
@@ -50,23 +53,25 @@ def tackle_combinations(
|
||||
groups: dict[tuple[str, str], list[CatchReport]] = defaultdict(list)
|
||||
for report in db.scalars(query):
|
||||
for component in report.tackle_components:
|
||||
if role and component.role != role:
|
||||
continue
|
||||
if component.raw_value.strip():
|
||||
groups[(component.role, component.raw_value.strip())].append(report)
|
||||
|
||||
result = []
|
||||
for (role, value), reports in groups.items():
|
||||
for (component_role, value), reports in groups.items():
|
||||
unique_reports = {report.id: report for report in reports}
|
||||
item_ids = {
|
||||
component.tackle_item_id
|
||||
for report in unique_reports.values()
|
||||
for component in report.tackle_components
|
||||
if component.role == role and component.raw_value.strip() == value and component.tackle_item_id is not None
|
||||
if component.role == component_role and component.raw_value.strip() == value and component.tackle_item_id is not None
|
||||
}
|
||||
rig_ids = {
|
||||
component.rig_id
|
||||
for report in unique_reports.values()
|
||||
for component in report.tackle_components
|
||||
if component.role == role and component.raw_value.strip() == value and component.rig_id is not None
|
||||
if component.role == component_role and component.raw_value.strip() == value and component.rig_id is not None
|
||||
}
|
||||
canonical_item_id = next(iter(item_ids)) if len(item_ids) == 1 and not rig_ids else None
|
||||
canonical_rig_id = next(iter(rig_ids)) if len(rig_ids) == 1 and not item_ids else None
|
||||
@@ -80,7 +85,7 @@ def tackle_combinations(
|
||||
) / catches * 100)
|
||||
enough = catches >= min_samples and unique_players >= min_players
|
||||
result.append(TackleCombinationOut(
|
||||
role=role, value=value, tackle_item_id=canonical_item_id, rig_id=canonical_rig_id,
|
||||
role=component_role, value=value, tackle_item_id=canonical_item_id, rig_id=canonical_rig_id,
|
||||
catches=catches, unique_players=unique_players,
|
||||
last_seen_at=last_seen, freshness_score=freshness_score,
|
||||
status="recommendation" if enough else "insufficient_data",
|
||||
|
||||
Reference in New Issue
Block a user