""" Compressor — collapses all sensory streams into one compact state. vision + motion + audio + diarization + retrieval → one compact state """ import json import time from .stream_state import SessionState, sha256_text def compress_state(state: SessionState) -> dict: """Compress rolling sensory state into a compact observer input. This is the shadow-dimensionality reduction step: many sensory streams → one dense state vector. """ frames = list(state.frames) recent_frames = frames[-4:] if frames else [] # Visual compression visual = { "frame_count": len(frames), "avg_entropy": round(sum(f.entropy for f in recent_frames) / max(1, len(recent_frames)), 4), "avg_motion": round(sum(f.motion_score for f in recent_frames) / max(1, len(recent_frames)), 4), "last_frame_hash": state.last_frame_hash, "frame_hashes": [f.sha256 for f in recent_frames], } # Audio compression — speaker-separated evidence ledger with full transcripts audio = { "speakers": {}, "chunk_count": len(state.audio_chunks), "recent_transcripts": [], } for speaker, info in state.speakers.items(): audio["speakers"][speaker] = { "transcript": info["transcript"][-500:], "confidence": info["confidence"], "chunk_count": info["chunk_count"], } # Include last 5 audio chunks as raw evidence recent_chunks = list(state.audio_chunks)[-5:] for c in recent_chunks: audio["recent_transcripts"].append({ "speaker": c.speaker, "text": c.transcript, "ts": round(c.ts, 2), }) # Intent — inferred by LLM, not typed by user intent = { "mode": state.mode, "note": "Intent must be inferred from camera + audio evidence, not from typed instructions.", } # Compressed state compact = { "timestamp": time.time(), "session_id": state.session_id, "visual": visual, "audio": audio, "intent": intent, "motion_score": state.motion_score, "novelty_score": state.novelty_score, "state_hash": "", } compact["state_hash"] = sha256_text(json.dumps(compact, sort_keys=True, default=str)) return compact