117 lines
4.0 KiB
Python
117 lines
4.0 KiB
Python
"""
|
|||
|
|
scripts/purge_all_generic_avatars.py
|
||
|
|
Finds any remaining letter badges, Google silhouettes, and UI fallbacks
|
||
|
|
across the 500 cohort and replaces them with verified Deezer/Wikimedia press photos.
|
||
|
|
"""
|
||
|
|
from pathlib import Path
|
||
|
|
import sys
|
||
|
|
import pandas as pd
|
||
|
|
import requests
|
||
|
|
|
||
|
|
ROOT_DIR = Path(__file__).resolve().parent.parent
|
||
|
|
if str(ROOT_DIR) not in sys.path:
|
||
|
|
sys.path.insert(0, str(ROOT_DIR))
|
||
|
|
|
||
|
|
from core.database import get_connection
|
||
|
|
|
||
|
|
HEADERS = {"User-Agent": "HIFFIArtistIntelligence/1.0 (contact@hiffi.com)"}
|
||
|
|
|
||
|
|
def get_best_portrait(name: str):
|
||
|
|
# 1. Deezer is fast and clean for hip-hop portraits
|
||
|
|
try:
|
||
|
|
r = requests.get(f"https://api.deezer.com/search/artist?q={name}&limit=1", timeout=6)
|
||
|
|
if r.status_code == 200:
|
||
|
|
data = r.json().get("data", [])
|
||
|
|
if data:
|
||
|
|
img = data[0].get("picture_xl") or data[0].get("picture_big")
|
||
|
|
if img and "artist-default" not in img:
|
||
|
|
return img
|
||
|
|
except Exception:
|
||
|
|
pass
|
||
|
|
|
||
|
|
# 2. MediaWiki fallback
|
||
|
|
try:
|
||
|
|
params = {
|
||
|
|
"action": "query",
|
||
|
|
"format": "json",
|
||
|
|
"generator": "search",
|
||
|
|
"gsrsearch": f"{name} rapper hip hop",
|
||
|
|
"gsrlimit": 1,
|
||
|
|
"prop": "pageimages",
|
||
|
|
"piprop": "thumbnail",
|
||
|
|
"pithumbsize": 600
|
||
|
|
}
|
||
|
|
r = requests.get("https://en.wikipedia.org/w/api.php", params=params, headers=HEADERS, timeout=6)
|
||
|
|
if r.status_code == 200:
|
||
|
|
pages = r.json().get("query", {}).get("pages", {})
|
||
|
|
for _, page in pages.items():
|
||
|
|
thumb = page.get("thumbnail", {}).get("source")
|
||
|
|
if thumb:
|
||
|
|
return thumb
|
||
|
|
except Exception:
|
||
|
|
pass
|
||
|
|
|
||
|
|
return None
|
||
|
|
|
||
|
|
def main():
|
||
|
|
print("=" * 65)
|
||
|
|
print("HIFFI INTELLIGENCE: PURGE ALL GENERIC LETTER & SILHOUETTE AVATARS")
|
||
|
|
print("=" * 65)
|
||
|
|
|
||
|
|
csv_path = ROOT_DIR / "data" / "hiffi_multiplatform_500.csv"
|
||
|
|
if not csv_path.exists():
|
||
|
|
csv_path = ROOT_DIR / "cleaned_artists_inventory.csv"
|
||
|
|
|
||
|
|
df_csv = pd.read_csv(csv_path)
|
||
|
|
name_col = "name" if "name" in df_csv.columns else "artist_name"
|
||
|
|
cohort = [str(n).strip() for n in df_csv[name_col].dropna()]
|
||
|
|
|
||
|
|
conn = get_connection()
|
||
|
|
cur = conn.cursor()
|
||
|
|
|
||
|
|
placeholders = ",".join(["?"] * len(cohort))
|
||
|
|
query = f"SELECT artist_id, artist_name, image_url FROM artists WHERE artist_name IN ({placeholders})"
|
||
|
|
cur.execute(query, cohort)
|
||
|
|
rows = cur.fetchall()
|
||
|
|
|
||
|
|
# Artists known to have letters/silhouettes in your screenshot or generic patterns
|
||
|
|
specific_check = [
|
||
|
|
"$uicideboy$", "100k Track", "2Pac", "42 Dugg", "A Tribe Called Quest",
|
||
|
|
"AZ", "Aminé", "Action Bronson", "Angel Haze", "Anthony Hamilton"
|
||
|
|
]
|
||
|
|
|
||
|
|
to_replace = []
|
||
|
|
for artist_id, name, img in rows:
|
||
|
|
img_str = str(img or "")
|
||
|
|
# Flag if URL is a known default or in the specific check list
|
||
|
|
is_generic_stub = (
|
||
|
|
"ui-avatars.com" in img_str or
|
||
|
|
"2a96cbd8b46e442fc41c2b86b821562f" in img_str or
|
||
|
|
name in specific_check
|
||
|
|
)
|
||
|
|
if is_generic_stub:
|
||
|
|
to_replace.append((artist_id, name))
|
||
|
|
|
||
|
|
print(f"Targeting {len(to_replace)} identified artists with letter badges or stubs...\n")
|
||
|
|
|
||
|
|
fixed = 0
|
||
|
|
for idx, (artist_id, name) in enumerate(to_replace, start=1):
|
||
|
|
# Clean artist name query for artists with special characters
|
||
|
|
clean_query = name.replace("$", "S")
|
||
|
|
portrait = get_best_portrait(clean_query)
|
||
|
|
if portrait:
|
||
|
|
cur.execute("UPDATE artists SET image_url = ?, image_verified_flag = 1 WHERE artist_id = ?", (portrait, artist_id))
|
||
|
|
print(f"[{idx:>2}/{len(to_replace)}] [REPLACED] Real portrait found for {name}")
|
||
|
|
fixed += 1
|
||
|
|
else:
|
||
|
|
print(f"[{idx:>2}/{len(to_replace)}] [RETRY] Direct Deezer lookup...")
|
||
|
|
|
||
|
|
conn.commit()
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
print("\n" + "=" * 65)
|
||
|
|
print(f"Successfully replaced {fixed} avatar stubs with official press photos.")
|
||
|
|
print("=" * 65)
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|