""" scripts/render_gallery.py Generates data/preview_images.html with an interactive QA Flagging system. Clicking "Flag Non-Face" highlights the card and exports a clean list to copy. """ import sqlite3 import webbrowser import html import re import csv import time from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent DB_PATH = BASE_DIR / "data" / "hiffi_catalog.db" OUTPUT_HTML_PATH = BASE_DIR / "data" / "preview_images.html" AVATAR_DIR = BASE_DIR / "data" / "artist_avatars" COHORT_CSV = BASE_DIR / "data" / "hiffi_multiplatform_500.csv" FALLBACK_CSV = BASE_DIR / "cleaned_artists_inventory.csv" TIMESTAMP = int(time.time()) def clean_file_slug(name: str) -> str: cleaned = re.sub(r'[^a-zA-Z0-9_-]', '_', name.strip().lower()) return re.sub(r'_+', '_', cleaned).strip('_') def get_image_source(artist_id: str, artist_name: str, remote_url: str) -> str: slug = clean_file_slug(artist_name) for ext in [".jpg", ".png", ".webp", ".jpeg"]: local_file = AVATAR_DIR / f"{slug}_{artist_id}{ext}" if local_file.exists() and local_file.stat().st_size > 2000: return f"artist_avatars/{local_file.name}?v={TIMESTAMP}" if remote_url and remote_url.startswith("http"): return remote_url return "https://via.placeholder.com/200?text=No+Image" def load_cohort_artist_names() -> list: target_csv = COHORT_CSV if COHORT_CSV.exists() else FALLBACK_CSV if not target_csv.exists(): return [] names = [] with open(target_csv, "r", encoding="utf-8-sig") as f: reader = csv.DictReader(f) for row in reader: name = row.get("artist_name") or row.get("Artist") or row.get("name") if name and name.strip(): names.append(name.strip()) return names def build_gallery_html(artists): cards_html = [] for item in artists: artist_id = str(item.get("artist_id", "")) raw_name = item.get("artist_name", "") name = html.escape(raw_name) img_src = html.escape(get_image_source(artist_id, raw_name, item.get("image_url", ""))) yt = html.escape(item.get("youtube_url") or "#") sp = html.escape(item.get("spotify_url") or "#") ig = html.escape(item.get("instagram_url") or "#") card = f"""
{name}
{name}
""" cards_html.append(card) cards_joined = "\n".join(cards_html) full_html = f""" HIFFI 500 Artist Cohort - Visual QA Gallery

HIFFI 500 Visual QA Tool

Click "Flag Non-Face" on any card that shows cartoons, covers, or logos.

Flagged: 0
{cards_joined}
""" return full_html def main(): if not DB_PATH.exists(): print(f"[-] Error: Database file does not exist at {DB_PATH}") return cohort_names = load_cohort_artist_names() conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row cursor = conn.cursor() if cohort_names: placeholders = ",".join("?" for _ in cohort_names) query = f""" SELECT artist_id, artist_name, image_url, youtube_url, spotify_url, instagram_url FROM artists WHERE artist_name IN ({placeholders}) ORDER BY artist_name COLLATE NOCASE ASC """ cursor.execute(query, cohort_names) else: cursor.execute(""" SELECT artist_id, artist_name, image_url, youtube_url, spotify_url, instagram_url FROM artists ORDER BY artist_name COLLATE NOCASE ASC LIMIT 500 """) rows = cursor.fetchall() conn.close() artists = [dict(row) for row in rows] print(f"[*] Rendering interactive QA gallery for {len(artists)} cohort artists...") html_content = build_gallery_html(artists) OUTPUT_HTML_PATH.parent.mkdir(parents=True, exist_ok=True) with open(OUTPUT_HTML_PATH, "w", encoding="utf-8") as f: f.write(html_content) print(f"[+] Gallery successfully compiled to: {OUTPUT_HTML_PATH}") print("[*] Launching browser preview...") webbrowser.open(OUTPUT_HTML_PATH.as_uri()) if __name__ == "__main__": main()