diff --git a/tests/test_session_report.py b/tests/test_session_report.py index 8311e93..117a0a8 100644 --- a/tests/test_session_report.py +++ b/tests/test_session_report.py @@ -59,4 +59,36 @@ def test_export_json_writes_expected_structure(): assert "summary" in data assert "records" in data assert data["records"][0]["timestamp"] == "ts1" - assert data["summary"]["readings"] == 1 \ No newline at end of file + assert data["summary"]["readings"] == 1 + + +def test_add_record_exposes_recovery_eta_per_window(): + report = SessionReport() + report.add_record("ts1", "chunks/ts1.wav", 100, elapsed_seconds=0) + record = report.records[0] + + assert "recovery_eta_sec" in record + assert "acute_load" in record + assert "chronic_load" in record + assert "readiness_experimental" in record + assert "smoothed_score" in record + assert record["recovery_eta_sec"] > 0 + + +def test_recovery_eta_decreases_as_session_recovers(): + report = SessionReport() + report.add_record("ts1", "chunks/ts1.wav", 100, elapsed_seconds=0) + first_eta = report.records[0]["recovery_eta_sec"] + + # a long pause with low scores should let the acute load decay, + # reducing the estimated recovery time on the next reading + report.add_record("ts2", "chunks/ts2.wav", 0, elapsed_seconds=120) + second_eta = report.records[1]["recovery_eta_sec"] + + assert second_eta < first_eta + + +def test_recovery_eta_is_zero_for_low_scores(): + report = SessionReport() + report.add_record("ts1", "chunks/ts1.wav", 5, elapsed_seconds=0) + assert report.records[0]["recovery_eta_sec"] == 0 \ No newline at end of file diff --git a/voiceMonitor/session.py b/voiceMonitor/session.py index 891710d..3f783b0 100644 --- a/voiceMonitor/session.py +++ b/voiceMonitor/session.py @@ -1,20 +1,12 @@ import json from .analytics import SessionAnalytics - class SessionReport: def __init__(self): self.analytics = SessionAnalytics() self.records = [] - def add_record( - self, - timestamp, - chunk_file, - score, - elapsed_seconds=None, - features=None, - ): + def add_record(self, timestamp, chunk_file, score, elapsed_seconds=None, features=None): """ features: acoustic markers (jitter, shimmer, HNR, CPPS) collected alongside the primary auralis_vfs score. These are currently @@ -23,13 +15,19 @@ def add_record( computed in this module. Integrating them into the fatigue model itself is planned as future work, not part of this change. """ + smoothed, impulse_state = self.analytics.add(score, timestamp, elapsed_seconds) + self.records.append({ "timestamp": timestamp, "chunk": chunk_file, "score": score, "features": features or {}, + "smoothed_score": smoothed, + "acute_load": impulse_state["acute"], + "chronic_load": impulse_state["chronic"], + "readiness_experimental": impulse_state["readiness_experimental"], + "recovery_eta_sec": impulse_state["recovery_eta_sec"], }) - self.analytics.add(score, timestamp, elapsed_seconds) def export_json(self, path): data = {