from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, Boolean, Text, Float from sqlalchemy.orm import relationship from datetime import datetime from app.database import Base from app.models.user import User from app.models.lyrics import task_groups class Task(Base): __tablename__ = "tasks" id = Column(Integer, primary_key=True, index=True) task_id = Column(String, unique=True, index=True) user_id = Column(Integer, ForeignKey("users.id")) device_id = Column(String) song_name = Column(String) artist = Column(String, nullable=True, default=None) album = Column(String, nullable=True, default=None) cover_url = Column(String, nullable=True, default=None) stems = Column(Integer) status = Column(String, default="PENDING") created_at = Column(DateTime, default=datetime.utcnow) # Fecha en que el cliente confirmó que descargó todos los stems. downloaded_at = Column(DateTime, nullable=True, default=None) cloud_url = Column(Text, nullable=True, default=None) # JSON: {"vocals": "BQACAgIA...", "bass": "BQACAgIB..."} - file_ids de Telegram por stem telegram_file_ids = Column(Text, nullable=True, default=None) # JSON: {"vocals": 12345, "bass": 12346} - message_ids de Telegram (para borrar si el usuario elimina) telegram_message_ids = Column(Text, nullable=True, default=None) group_id = Column(Integer, ForeignKey("groups.id"), nullable=True) # JSON string con lista de acordes editados por el usuario [{"t": 0.5, "ch": "Am"}, ...] chords = Column(Text, nullable=True, default=None) # Fecha en que los archivos de Tebi (stems + voces corales) serán eliminados automáticamente # Normal: 3 días, Premium: 7 días desde la subida. NULL = ya expirado o tarea anterior al feature. cloud_expires_at = Column(DateTime, nullable=True, default=None) bpm = Column(Float, nullable=True, default=None) beats = Column(Text, nullable=True, default=None) # JSON array of beat timestamps in seconds tuning_info = Column(Text, nullable=True, default=None) # JSON: {"original_hz": 432.4, "target_hz": 440.0, "cents_offset": -30.2, "retuned": true} user = relationship("User", back_populates="tasks") group = relationship("Group", foreign_keys=[group_id]) groups_shared = relationship("Group", secondary=task_groups, back_populates="tasks_shared") @property def group_ids(self): return [g.id for g in self.groups_shared] class Worker(Base): __tablename__ = "workers" id = Column(Integer, primary_key=True, index=True) hostname = Column(String, unique=True, index=True) name = Column(String, nullable=True) # User-friendly custom name status = Column(String, default="offline") # online | offline | busy last_seen = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # BYOK / Local Worker user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True, unique=True) token = Column(String, unique=True, index=True, nullable=True) command = Column(String, default="none") # start | stop | none is_active = Column(Boolean, default=False) url = Column(String, nullable=True) # URL de despertar / HuggingFace Space URL