#!/usr/bin/env python3 """ Search functionality and statistics for PunimTag """ from typing import List, Dict, Tuple, Optional from database import DatabaseManager class SearchStats: """Handles search functionality and statistics generation""" def __init__(self, db_manager: DatabaseManager, verbose: int = 0): """Initialize search and stats manager""" self.db = db_manager self.verbose = verbose def search_faces(self, person_name: str) -> List[str]: """Search for photos containing a specific person""" # Get all people matching the name people = self.db.show_people_list() matching_people = [] for person in people: person_id, first_name, last_name, middle_name, maiden_name, date_of_birth, created_date = person full_name = f"{first_name} {last_name}".lower() search_name = person_name.lower() # Check if search term matches any part of the name if (search_name in full_name or search_name in first_name.lower() or search_name in last_name.lower() or (middle_name and search_name in middle_name.lower()) or (maiden_name and search_name in maiden_name.lower())): matching_people.append(person_id) if not matching_people: print(f"āŒ No people found matching '{person_name}'") return [] # Get photos for matching people photo_paths = [] for person_id in matching_people: # This would need to be implemented in the database module # For now, we'll use a placeholder pass if photo_paths: print(f"šŸ” Found {len(photo_paths)} photos with '{person_name}':") for path in photo_paths: print(f" šŸ“ø {path}") else: print(f"āŒ No photos found for '{person_name}'") return photo_paths def get_statistics(self) -> Dict: """Get comprehensive database statistics""" stats = self.db.get_statistics() # Add calculated statistics if stats['total_photos'] > 0: stats['processing_percentage'] = (stats['processed_photos'] / stats['total_photos']) * 100 else: stats['processing_percentage'] = 0 if stats['total_faces'] > 0: stats['identification_percentage'] = (stats['identified_faces'] / stats['total_faces']) * 100 else: stats['identification_percentage'] = 0 if stats['total_people'] > 0: stats['faces_per_person'] = stats['identified_faces'] / stats['total_people'] else: stats['faces_per_person'] = 0 if stats['total_photos'] > 0: stats['faces_per_photo'] = stats['total_faces'] / stats['total_photos'] else: stats['faces_per_photo'] = 0 if stats['total_photos'] > 0: stats['tags_per_photo'] = stats['total_photo_tags'] / stats['total_photos'] else: stats['tags_per_photo'] = 0 return stats def print_statistics(self): """Print formatted statistics to console""" stats = self.get_statistics() print("\nšŸ“Š PunimTag Database Statistics") print("=" * 50) print(f"šŸ“ø Photos:") print(f" Total photos: {stats['total_photos']}") print(f" Processed: {stats['processed_photos']} ({stats['processing_percentage']:.1f}%)") print(f" Unprocessed: {stats['total_photos'] - stats['processed_photos']}") print(f"\nšŸ‘¤ Faces:") print(f" Total faces: {stats['total_faces']}") print(f" Identified: {stats['identified_faces']} ({stats['identification_percentage']:.1f}%)") print(f" Unidentified: {stats['unidentified_faces']}") print(f"\nšŸ‘„ People:") print(f" Total people: {stats['total_people']}") print(f" Average faces per person: {stats['faces_per_person']:.1f}") print(f"\nšŸ·ļø Tags:") print(f" Total tags: {stats['total_tags']}") print(f" Total photo-tag links: {stats['total_photo_tags']}") print(f" Average tags per photo: {stats['tags_per_photo']:.1f}") print(f"\nšŸ“ˆ Averages:") print(f" Faces per photo: {stats['faces_per_photo']:.1f}") print(f" Tags per photo: {stats['tags_per_photo']:.1f}") print("=" * 50) def get_photo_statistics(self) -> Dict: """Get detailed photo statistics""" stats = self.get_statistics() # This could be expanded with more detailed photo analysis return { 'total_photos': stats['total_photos'], 'processed_photos': stats['processed_photos'], 'unprocessed_photos': stats['total_photos'] - stats['processed_photos'], 'processing_percentage': stats['processing_percentage'] } def get_face_statistics(self) -> Dict: """Get detailed face statistics""" stats = self.get_statistics() return { 'total_faces': stats['total_faces'], 'identified_faces': stats['identified_faces'], 'unidentified_faces': stats['unidentified_faces'], 'identification_percentage': stats['identification_percentage'], 'faces_per_photo': stats['faces_per_photo'] } def get_people_statistics(self) -> Dict: """Get detailed people statistics""" stats = self.get_statistics() return { 'total_people': stats['total_people'], 'faces_per_person': stats['faces_per_person'] } def get_tag_statistics(self) -> Dict: """Get detailed tag statistics""" stats = self.get_statistics() return { 'total_tags': stats['total_tags'], 'total_photo_tags': stats['total_photo_tags'], 'tags_per_photo': stats['tags_per_photo'] } def search_photos_by_date(self, date_from: str = None, date_to: str = None) -> List[Tuple]: """Search photos by date range""" # This would need to be implemented in the database module # For now, return empty list return [] def search_photos_by_tags(self, tags: List[str], match_all: bool = False) -> List[Tuple]: """Search photos by tags""" # This would need to be implemented in the database module # For now, return empty list return [] def search_photos_by_people(self, people: List[str]) -> List[Tuple]: """Search photos by people""" # This would need to be implemented in the database module # For now, return empty list return [] def get_most_common_tags(self, limit: int = 10) -> List[Tuple[str, int]]: """Get most commonly used tags""" # This would need to be implemented in the database module # For now, return empty list return [] def get_most_photographed_people(self, limit: int = 10) -> List[Tuple[str, int]]: """Get most photographed people""" # This would need to be implemented in the database module # For now, return empty list return [] def get_photos_without_faces(self) -> List[Tuple]: """Get photos that have no detected faces""" # This would need to be implemented in the database module # For now, return empty list return [] def get_photos_without_tags(self) -> List[Tuple]: """Get photos that have no tags""" # This would need to be implemented in the database module # For now, return empty list return [] def get_duplicate_faces(self, tolerance: float = 0.6) -> List[Dict]: """Get potential duplicate faces (same person, different photos)""" # This would need to be implemented using face matching # For now, return empty list return [] def get_face_quality_distribution(self) -> Dict: """Get distribution of face quality scores""" # This would need to be implemented in the database module # For now, return empty dict return {} def get_processing_timeline(self) -> List[Tuple[str, int]]: """Get timeline of photo processing (photos processed per day)""" # This would need to be implemented in the database module # For now, return empty list return [] def export_statistics(self, filename: str = "punimtag_stats.json"): """Export statistics to a JSON file""" import json stats = self.get_statistics() try: with open(filename, 'w') as f: json.dump(stats, f, indent=2) print(f"āœ… Statistics exported to {filename}") except Exception as e: print(f"āŒ Error exporting statistics: {e}") def generate_report(self) -> str: """Generate a text report of statistics""" stats = self.get_statistics() report = f""" PunimTag Database Report Generated: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')} PHOTO STATISTICS: - Total photos: {stats['total_photos']} - Processed: {stats['processed_photos']} ({stats['processing_percentage']:.1f}%) - Unprocessed: {stats['total_photos'] - stats['processed_photos']} FACE STATISTICS: - Total faces: {stats['total_faces']} - Identified: {stats['identified_faces']} ({stats['identification_percentage']:.1f}%) - Unidentified: {stats['unidentified_faces']} - Average faces per photo: {stats['faces_per_photo']:.1f} PEOPLE STATISTICS: - Total people: {stats['total_people']} - Average faces per person: {stats['faces_per_person']:.1f} TAG STATISTICS: - Total tags: {stats['total_tags']} - Total photo-tag links: {stats['total_photo_tags']} - Average tags per photo: {stats['tags_per_photo']:.1f} """ return report