csc-engine / src /stream_state.py
josephrw's picture
Upload folder using huggingface_hub
ab27fab verified
Raw
History Blame Contribute Delete
4.43 kB
"""
Stream State — SESSION_STATE_V1
Rolling session state that tracks camera, audio, observer, and builder
across the five loops.
"""
import time
import uuid
import hashlib
import json
from collections import deque
from dataclasses import dataclass, field
from typing import Any, Optional
@dataclass
class FrameEvidence:
ts: float
sha256: str
phash: str
entropy: float
motion_score: float
width: int
height: int
jpeg_b64: str
@dataclass
class AudioChunk:
ts: float
chunk_id: str
duration_ms: int
speaker: str
transcript: str
confidence: float
sha256: str
is_speech: bool
@dataclass
class SessionState:
session_id: str = field(default_factory=lambda: str(uuid.uuid4()))
created_at: float = field(default_factory=time.time)
# Camera
camera_source: str = "webcam"
frame_rate_sampled: float = 1.0
frames: deque = field(default_factory=lambda: deque(maxlen=16))
last_frame_hash: str = ""
motion_score: float = 0.0
# Audio
audio_chunks: deque = field(default_factory=lambda: deque(maxlen=30))
speakers: dict = field(default_factory=dict)
# Observer
scene_summary: str = ""
intent_summary: str = ""
novelty_score: float = 0.0
code_relevance_score: float = 0.0
observer_state: dict = field(default_factory=dict)
last_observer_ts: float = 0.0
# Builder
current_artifact: str = ""
last_patch_hash: str = ""
builder_state: dict = field(default_factory=dict)
last_builder_ts: float = 0.0
# QVD
qvd: float = 0.0
qvd_threshold: float = 0.08
# Receipts
receipt_count: int = 0
# User
user_instruction: str = ""
mode: str = "continuous_code"
def add_frame(self, frame: FrameEvidence):
self.frames.append(frame)
self.last_frame_hash = frame.sha256
self.motion_score = frame.motion_score
def add_audio_chunk(self, chunk: AudioChunk):
self.audio_chunks.append(chunk)
if chunk.speaker not in self.speakers:
self.speakers[chunk.speaker] = {
"transcript": "",
"confidence": 0.0,
"chunk_count": 0,
}
s = self.speakers[chunk.speaker]
s["transcript"] = (s["transcript"] + " " + chunk.transcript).strip()[-2000:]
s["confidence"] = chunk.confidence
s["chunk_count"] += 1
def frame_hashes(self) -> list:
return [f.sha256 for f in self.frames]
def audio_chunk_hashes(self) -> list:
return [c.sha256 for c in self.audio_chunks]
def speaker_segments(self) -> list:
return [
{"speaker": c.speaker, "text": c.transcript, "confidence": c.confidence}
for c in self.audio_chunks if c.is_speech
]
def to_dict(self) -> dict:
return {
"session_id": self.session_id,
"created_at": self.created_at,
"camera": {
"source": self.camera_source,
"frame_rate_sampled": self.frame_rate_sampled,
"last_frame_hash": self.last_frame_hash,
"motion_score": round(self.motion_score, 4),
"frames_buffered": len(self.frames),
},
"audio": {
"chunks_buffered": len(self.audio_chunks),
"speakers": self.speakers,
},
"observer": {
"scene_summary": self.scene_summary,
"intent_summary": self.intent_summary,
"novelty_score": round(self.novelty_score, 4),
"code_relevance_score": round(self.code_relevance_score, 4),
"state": self.observer_state,
"last_ts": self.last_observer_ts,
},
"builder": {
"current_artifact": self.current_artifact[:500],
"last_patch_hash": self.last_patch_hash,
"state": self.builder_state,
"last_ts": self.last_builder_ts,
},
"qvd": round(self.qvd, 4),
"qvd_threshold": self.qvd_threshold,
"receipt_count": self.receipt_count,
"user_instruction": self.user_instruction,
"mode": self.mode,
}
def sha256_bytes(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
def sha256_text(text: str) -> str:
return hashlib.sha256(text.encode()).hexdigest()