import datetime from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, Text from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Media(Base): __tablename__ = 'media' id = Column(Integer, primary_key=True) file_path = Column(String, unique=True, nullable=False) file_type = Column(String) # 'image' or 'audio' artist_id = Column(String) is_used = Column(Boolean, default=False) description = Column(Text) source_url = Column(String) thumbnail_path = Column(String) # NUOVO created_at = Column(DateTime, default=datetime.datetime.utcnow) last_used_at = Column(DateTime) class Draft(Base): __tablename__ = 'drafts' id = Column(Integer, primary_key=True) artist_id = Column(String) title = Column(String) caption = Column(Text) hashtags = Column(Text) image_path = Column(String) image_paths = Column(Text) # JSON list of local paths image_url = Column(String) # NUOVA COLONNA PER ANTEPRIMA DIRETTA video_url = Column(String) video_path = Column(String) # NUOVO audio_analysis = Column(Text) focus_points = Column(Text) # NUOVO: Coordinate JSON per la regia AI status = Column(String, default='pending') # pending, approved, published created_at = Column(DateTime, default=datetime.datetime.utcnow) class Database: def __init__(self, db_url="sqlite:///data/redazione.db"): self.engine = create_engine(db_url) Base.metadata.create_all(self.engine) self.Session = sessionmaker(bind=self.engine) def add_media(self, file_path, file_type, artist_id, description=None, source_url=None, thumbnail_path=None): session = self.Session() try: media = session.query(Media).filter_by(file_path=file_path).first() if not media: media = Media( file_path=file_path, file_type=file_type, artist_id=artist_id, description=description, source_url=source_url, thumbnail_path=thumbnail_path ) session.add(media) session.commit() elif thumbnail_path and not media.thumbnail_path: media.thumbnail_path = thumbnail_path session.commit() return media finally: session.close() def get_unused_image(self, artist_id): from sqlalchemy.sql.expression import func session = self.Session() try: return session.query(Media).filter_by( artist_id=artist_id, file_type='image', is_used=False ).order_by(func.random()).first() finally: session.close() def get_media_by_artist(self, artist_id, file_type): session = self.Session() try: return session.query(Media).filter_by( artist_id=artist_id, file_type=file_type ).first() finally: session.close() def get_audio_for_artist(self, artist_id): return self.get_media_by_artist(artist_id, 'audio') def mark_as_used(self, media_id): session = self.Session() try: media = session.query(Media).get(media_id) if media: media.is_used = True media.last_used_at = datetime.datetime.utcnow() session.commit() finally: session.close() def get_audio_for_artist(self, artist_id): # We assume one main audio track per session or the latest added session = self.Session() try: return session.query(Media).filter_by( artist_id=artist_id, file_type='audio' ).order_by(Media.created_at.desc()).first() finally: session.close() def save_draft(self, artist_id, title, caption, hashtags, image_path, audio_analysis, image_url=None, video_url=None, image_paths=None, video_path=None, focus_points=None): session = self.Session() try: draft = Draft( artist_id=artist_id, title=title, caption=caption, hashtags=hashtags, image_path=image_path, image_paths=image_paths, image_url=image_url, video_url=video_url, video_path=video_path, audio_analysis=audio_analysis, focus_points=focus_points # SALVATAGGIO ) session.add(draft) session.commit() return draft.id finally: session.close() def get_recent_media(self, artist_id, limit=10): session = self.Session() try: return session.query(Media).filter( Media.artist_id == artist_id, Media.file_type.in_(['image', 'video']) ).order_by(Media.created_at.desc()).limit(limit).all() finally: session.close() def get_mixed_assets(self, artist_id, total=12): from sqlalchemy.sql.expression import func session = self.Session() try: # 1. Seleziona una copertina (preferibilmente immagine mai usata) cover = session.query(Media).filter_by( artist_id=artist_id, file_type='image', is_used=False ).order_by(func.random()).first() if not cover: cover = session.query(Media).filter_by( artist_id=artist_id, file_type='image' ).order_by(func.random()).first() if not cover: # Se proprio non ci sono immagini, prendi un video come cover cover = session.query(Media).filter_by( artist_id=artist_id, file_type='video' ).order_by(func.random()).first() if not cover: return [] # 2. Seleziona un mix di altre immagini e video others = session.query(Media).filter( Media.artist_id == artist_id, Media.file_type.in_(['image', 'video']), Media.id != cover.id ).order_by(func.random()).limit(total - 1).all() return [cover] + others finally: session.close() def get_pending_drafts(self, artist_id=None): session = self.Session() try: query = session.query(Draft).filter_by(status='pending') if artist_id: query = query.filter_by(artist_id=artist_id) return query.all() finally: session.close() def get_media_by_path(self, file_path): session = self.Session() try: return session.query(Media).filter_by(file_path=file_path).first() finally: session.close() def delete_draft(self, draft_id): session = self.Session() try: draft = session.query(Draft).filter_by(id=draft_id).first() if draft: session.delete(draft) session.commit() finally: session.close() def update_draft(self, draft_id, title=None, caption=None, hashtags=None, image_path=None, status=None, audio_analysis=None, video_url=None, video_path=None, image_paths=None, focus_points=None): session = self.Session() try: draft = session.query(Draft).get(draft_id) if draft: if title is not None: draft.title = title if caption is not None: draft.caption = caption if hashtags is not None: draft.hashtags = hashtags if image_path is not None: draft.image_path = image_path if status is not None: draft.status = status if audio_analysis is not None: draft.audio_analysis = audio_analysis if video_url is not None: draft.video_url = video_url if video_path is not None: draft.video_path = video_path if image_paths is not None: draft.image_paths = image_paths if focus_points is not None: draft.focus_points = focus_points # AGGIORNAMENTO session.commit() return True return False finally: session.close() def mark_as_published(self, draft_id): session = self.Session() try: draft = session.query(Draft).filter_by(id=draft_id).first() if draft: draft.status = 'published' session.commit() finally: session.close()