import json from fastapi import APIRouter, HTTPException from app.config import STATE_PATH, BACKGROUND_PATH, energy_axis, NUM_CHANNELS import numpy as np router = APIRouter() @router.get("/current") async def get_current_spectrum(): """Current accumulated spectrum with energy axis.""" if not STATE_PATH.exists(): raise HTTPException(status_code=503, detail="Monitor not started yet") try: with open(STATE_PATH) as f: state = json.load(f) except (json.JSONDecodeError, OSError): raise HTTPException(status_code=503, detail="Monitor state file corrupt") return { "timestamp": state.get("timestamp", ""), "connected": state.get("connected", False), "cumulated_live_time_s": state.get("cumulated_live_time_s", 0), "cumulated_live_time_h": state.get("cumulated_live_time_h", 0), "cps": state.get("cps", 0), "total_counts": state.get("total_counts", 0), "background_subtracted": state.get("background_subtracted", False), "isotopes_detected": state.get("isotopes_detected", []), "channels": list(range(NUM_CHANNELS)), "energy_kev": energy_axis(), "counts": state.get("counts", [0] * 1024)[:NUM_CHANNELS], } @router.get("/difference") async def get_difference_spectrum(): """Background-subtracted spectrum (net signal).""" if not STATE_PATH.exists(): raise HTTPException(status_code=503, detail="Monitor not started yet") try: with open(STATE_PATH) as f: state = json.load(f) except (json.JSONDecodeError, OSError): raise HTTPException(status_code=503, detail="Monitor state file corrupt") counts = np.array(state.get("counts", [0] * 1024), dtype=np.float64)[:NUM_CHANNELS] live_time = state.get("cumulated_live_time_s", 0) if live_time <= 0: raise HTTPException(status_code=503, detail="No live time data yet") rate = counts / live_time if BACKGROUND_PATH.exists(): bg_data = np.load(str(BACKGROUND_PATH), allow_pickle=True).item() bg_counts = bg_data["counts"].astype(np.float64)[:NUM_CHANNELS] bg_live_time = float(bg_data["duration"]) bg_rate = bg_counts / bg_live_time net_rate = np.clip(rate - bg_rate, 0, None) net_counts = net_rate * live_time bg_available = True else: net_counts = counts bg_available = False return { "timestamp": state.get("timestamp", ""), "cumulated_live_time_s": live_time, "background_subtracted": bg_available, "channels": list(range(NUM_CHANNELS)), "energy_kev": energy_axis(), "counts": [round(float(c), 1) for c in net_counts], "raw_counts": state.get("counts", [])[:NUM_CHANNELS], }