"""History gallery tab component.""" import logging from pathlib import Path from typing import Optional import gradio as gr from src.storage.history import history_manager, HistoryItem logger = logging.getLogger(__name__) def get_history_gallery() -> list[tuple[str, str]]: """Get history items for gallery display.""" items = history_manager.get_recent(limit=100) gallery_items = [] for item in items: # Use output path for display output_path = Path(item.output_path) if output_path.exists() and item.type == "image": caption = f"{item.output_filename}\n{item.output_width}x{item.output_height}" gallery_items.append((str(output_path), caption)) return gallery_items def get_history_stats() -> str: """Get history statistics.""" stats = history_manager.get_statistics() return ( f"**History Statistics**\n\n" f"- Total Items: {stats['total_items']}\n" f"- Images: {stats['images']}\n" f"- Videos: {stats['videos']}\n" f"- Total Processing Time: {stats['total_processing_time']/60:.1f} min\n" f"- Total Input Size: {stats['total_input_size_mb']:.1f} MB\n" f"- Total Output Size: {stats['total_output_size_mb']:.1f} MB" ) def search_history(query: str) -> list[tuple[str, str]]: """Search history by filename.""" if not query: return get_history_gallery() items = history_manager.search(query) gallery_items = [] for item in items: output_path = Path(item.output_path) if output_path.exists() and item.type == "image": caption = f"{item.output_filename}\n{item.output_width}x{item.output_height}" gallery_items.append((str(output_path), caption)) return gallery_items def get_item_details(evt: gr.SelectData) -> tuple[Optional[tuple], str]: """Get details for selected history item.""" if evt.index is None: return None, "Select an item to view details" items = history_manager.get_recent(limit=100) # Filter to only images (same as gallery) image_items = [i for i in items if i.type == "image" and Path(i.output_path).exists()] if evt.index >= len(image_items): return None, "Item not found" item = image_items[evt.index] # Load images for slider input_path = Path(item.input_path) output_path = Path(item.output_path) slider_images = None if input_path.exists() and output_path.exists(): slider_images = (str(input_path), str(output_path)) # Format details details = ( f"**{item.output_filename}**\n\n" f"- **Type:** {item.type.title()}\n" f"- **Model:** {item.model}\n" f"- **Scale:** {item.scale}x\n" f"- **Face Enhancement:** {'Yes' if item.face_enhance else 'No'}\n" f"- **Input:** {item.input_width}x{item.input_height}\n" f"- **Output:** {item.output_width}x{item.output_height}\n" f"- **Processing Time:** {item.processing_time_seconds:.1f}s\n" f"- **Input Size:** {item.input_size_bytes/1024:.1f} KB\n" f"- **Output Size:** {item.output_size_bytes/1024:.1f} KB\n" f"- **Created:** {item.created_at.strftime('%Y-%m-%d %H:%M')}" ) return slider_images, details def delete_selected(evt: gr.SelectData) -> tuple[list, str]: """Delete selected history item.""" if evt.index is None: return get_history_gallery(), "No item selected" items = history_manager.get_recent(limit=100) image_items = [i for i in items if i.type == "image" and Path(i.output_path).exists()] if evt.index >= len(image_items): return get_history_gallery(), "Item not found" item = image_items[evt.index] history_manager.delete_item(item.id) return get_history_gallery(), f"Deleted: {item.output_filename}" def create_history_tab(): """Create the history gallery tab component.""" with gr.Tab("History", id="history-tab"): gr.Markdown("## Processing History") with gr.Row(): # Search search_box = gr.Textbox( label="Search", placeholder="Search by filename...", scale=2, ) filter_dropdown = gr.Dropdown( choices=["All", "Images", "Videos"], value="All", label="Filter", scale=1, ) with gr.Row(): # Gallery with gr.Column(scale=2): gallery = gr.Gallery( value=get_history_gallery(), label="History", columns=4, object_fit="cover", height=400, allow_preview=True, ) # Details panel with gr.Column(scale=1): stats_display = gr.Markdown( get_history_stats(), elem_classes=["info-card"], ) # Selected item details with gr.Row(): with gr.Column(scale=2): try: from gradio_imageslider import ImageSlider comparison_slider = ImageSlider( label="Before / After", type="filepath", ) except ImportError: comparison_slider = gr.Image( label="Selected Image", type="filepath", ) with gr.Column(scale=1): item_details = gr.Markdown( "Select an item to view details", elem_classes=["info-card"], ) with gr.Row(): download_btn = gr.Button("Download", variant="secondary") delete_btn = gr.Button("Delete", variant="stop") status_text = gr.Markdown("") # Event handlers search_box.change( fn=search_history, inputs=[search_box], outputs=[gallery], ) gallery.select( fn=get_item_details, outputs=[comparison_slider, item_details], ) delete_btn.click( fn=lambda: (get_history_gallery(), get_history_stats()), outputs=[gallery, stats_display], ) return { "gallery": gallery, "comparison_slider": comparison_slider, "item_details": item_details, "stats_display": stats_display, }