""" database/models.py - SQLAlchemy ORM models for Surveillance System """ import uuid from datetime import datetime from sqlalchemy import Column, String, DateTime, Float, Text, Integer, ForeignKey, JSON, Enum from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship from database.session import Base import enum class ActivityType(str, enum.Enum): DETECTED = "detected" TRACKED = "tracked" REID_MATCH = "reid_match" ANOMALY = "anomaly" LOITERING = "loitering" RUNNING = "running" FIGHTING = "fighting" TRESPASSING = "trespassing" class AnalysisSession(Base): __tablename__ = "analysis_sessions" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True) timestamp = Column(DateTime, default=datetime.utcnow, nullable=False, index=True) video_filename = Column(String(255), nullable=False) thumbnail_path = Column(String(500), nullable=True) # Analysis Summary Stats duration_sec = Column(Float, nullable=False, default=0.0) frames_processed = Column(Integer, nullable=False, default=0) unique_persons = Column(Integer, nullable=False, default=0) peak_count = Column(Integer, nullable=False, default=0) def __repr__(self): return f"" class Person(Base): __tablename__ = "persons" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True) first_seen = Column(DateTime, default=datetime.utcnow, nullable=False) last_seen = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) # ReID embedding reference faiss_id = Column(Integer, nullable=True, unique=True) embedding_version = Column(String(50), default="vit-base-patch16-224") # Attributes from CLIP attributes = Column(JSON, nullable=True) # {"clothing": [...], "colors": [...]} thumbnail_path = Column(String(500), nullable=True) track_ids = Column(JSON, default=list) # list of all track IDs assigned cross-camera events = relationship("Event", back_populates="person", cascade="all, delete-orphan") def __repr__(self): return f"" class Event(Base): __tablename__ = "events" event_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True) person_id = Column(UUID(as_uuid=True), ForeignKey("persons.id", ondelete="CASCADE"), nullable=False, index=True) camera_id = Column(String(64), nullable=False, index=True) timestamp = Column(DateTime, default=datetime.utcnow, nullable=False, index=True) activity_type = Column(Enum(ActivityType), default=ActivityType.DETECTED, nullable=False) # Spatial & tracking info bounding_box = Column(JSON, nullable=True) # {"x1": f, "y1": f, "x2": f, "y2": f} confidence = Column(Float, nullable=True) track_id = Column(Integer, nullable=True) location_zone = Column(String(128), nullable=True) # Additional metadata anomaly_score = Column(Float, default=0.0) raw_metadata = Column(JSON, nullable=True) description = Column(Text, nullable=True) # NLP-generated description person = relationship("Person", back_populates="events") def __repr__(self): return f"" class IncidentReport(Base): __tablename__ = "incident_reports" report_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True) person_id = Column(UUID(as_uuid=True), ForeignKey("persons.id", ondelete="SET NULL"), nullable=True) generated_at = Column(DateTime, default=datetime.utcnow) report_text = Column(Text, nullable=False) summary = Column(Text, nullable=True) severity = Column(String(20), default="medium") # low / medium / high / critical camera_ids = Column(JSON, default=list) model_version = Column(String(50), default="flan-t5-base")