VIDEO NOT IMAGES + history4all

This commit is contained in:
lda committed 2026-03-01 14:17:41 +07:00
1 parent c716d23151
commit 4201a3cbb1
6 files changed
+66 -13

No files matched your search

+2
View File
@@ -14,6 +14,8 @@ wheels/
# artifacts/logs i forgor what are the paths uhhhhhhh
alerts.jsonl
output.jsonl
output.mp4
static/alerts/
screenshots/
events/
+5 -2
View File
@@ -122,10 +122,13 @@ class MySQLRepository:
conn.close()
return [DetectionRecord(**r) for r in rows]
def clear_detections(self, user_id: int) -> int:
def clear_detections(self, user_id: Optional[int] = None) -> int:
conn = self._connect()
cursor = conn.cursor()
cursor.execute("DELETE FROM detections WHERE user_id = %s", (user_id,))
if user_id is None:
cursor.execute("DELETE FROM detections")
else:
cursor.execute("DELETE FROM detections WHERE user_id = %s", (user_id,))
conn.commit()
count = cursor.rowcount
conn.close()
+2 -2
View File
@@ -59,8 +59,8 @@ class Repository(Protocol):
"""Get detection history, optionally filtered by user. Newest first."""
...
def clear_detections(self, user_id: int) -> int:
"""Delete all detections for a user. Returns number of rows deleted."""
def clear_detections(self, user_id: Optional[int] = None) -> int:
"""Delete detections, optionally filtered by user. Returns rows deleted."""
...
def close(self) -> None:
+7 -2
View File
@@ -109,9 +109,14 @@ class SQLiteRepository:
).fetchall()
return [DetectionRecord(**dict(r)) for r in rows]
def clear_detections(self, user_id: int) -> int:
def clear_detections(self, user_id: Optional[int] = None) -> int:
conn = self._get_conn()
cursor = conn.execute("DELETE FROM detections WHERE user_id = ?", (user_id,))
if user_id is None:
cursor = conn.execute("DELETE FROM detections")
else:
cursor = conn.execute(
"DELETE FROM detections WHERE user_id = ?", (user_id,)
)
conn.commit()
return cursor.rowcount
+49 -6
View File
@@ -32,7 +32,7 @@ from pipeline.config import PipelineConfig
from pipeline.core import SmokingDetectionPipeline
from pipeline.models import YoloCigaretteDetector, YoloClassifier, YoloPersonDetector
from pipeline.protocols import Sink
from pipeline.sinks import DatabaseSink, FileAlertStore, MetricsSink
from pipeline.sinks import FileAlertStore, MetricsSink, SmartEventSink
from pipeline.sources.stream import ThreadedStreamSource
from pipeline.staged_core import StageBasedPipeline
from pipeline.types import Frame
@@ -62,6 +62,48 @@ class LiveFrameSink(Sink):
pass
class DatabaseSmartEventSink(SmartEventSink):
"""Records event clips and stores clip path in DB as alert evidence."""
def __init__(
self,
db_repo: Repository,
fps: float,
user_id: int = 1,
camera_source: str = "Pipeline",
output_dir: str = "static/events",
):
super().__init__(output_dir=output_dir, fps=fps)
self.db_repo = db_repo
self.user_id = user_id
self.camera_source = camera_source
def _trigger_event(self, trigger_frame: Frame):
was_recording = self.recording
super()._trigger_event(trigger_frame)
# Save one DB row per newly started event clip
if was_recording or not self.recording or self.current_event_id is None:
return
ticket = trigger_frame.ticket
if not ticket:
return
filename = f"event_{self.current_event_id}.mp4"
web_path = f"/static/events/{filename}"
try:
self.db_repo.save_detection(
user_id=self.user_id,
image_path=web_path,
confidence=ticket.confidence,
camera_source=self.camera_source,
)
logger.info("Saved event alert to DB: %s", web_path)
except Exception as e:
logger.error("Failed to save event alert to DB: %s", e)
def _get_lan_address() -> tuple[str, str]:
"""Return (ip, hostname) for the primary LAN interface."""
ip = "127.0.0.1"
@@ -160,7 +202,7 @@ async def app_lifespan(_app: FastAPI):
# 4. Sinks
sinks: list[Sink] = [
LiveFrameSink(),
DatabaseSink(db, image_dir="static/alerts"),
DatabaseSmartEventSink(db, fps=source.fps, output_dir="static/events"),
MetricsSink(log_interval=200),
FileAlertStore("alerts.jsonl"),
]
@@ -231,6 +273,7 @@ app = FastAPI(title="Smoking Detection", lifespan=app_lifespan) # type: ignore
# Serve static assets (alert images, CSS/JS, etc.)
Path("static/alerts").mkdir(parents=True, exist_ok=True)
Path("static/events").mkdir(parents=True, exist_ok=True)
app.mount("/static", StaticFiles(directory="static"), name="static")
@@ -269,7 +312,7 @@ def login(username: str = Form(...), password: str = Form(...)):
@app.get("/history")
def get_history(user_id: int):
def get_history(user_id: int | None = None):
try:
records = db.get_detections(user_id)
return [
@@ -288,10 +331,10 @@ def get_history(user_id: int):
@app.post("/clear_history")
def clear_history(user_id: int = Form(...)):
def clear_history():
try:
deleted = db.clear_detections(user_id)
logger.info("Cleared %d records for user %d", deleted, user_id)
deleted = db.clear_detections()
logger.info("Cleared %d records", deleted)
return {"status": "success", "message": "History cleared"}
except Exception as e:
return {"status": "error", "message": str(e)}