127 lines
4.1 KiB
Python
127 lines
4.1 KiB
Python
"""
|
|
scripts/fix_real_artist_images.py
|
|
Replaces placeholder star images and broken/stub avatars using:
|
|
1. MediaWiki Search & PageImages API (auto-resolves redirects and searches)
|
|
2. Deezer Public Artist API (official high-res portraits, picture_xl)
|
|
"""
|
|
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
|
|
|
|
LASTFM_STAR_HASH = "2a96cbd8b46e442fc41c2b86b821562f"
|
|
HEADERS = {"User-Agent": "HIFFIArtistIntelligence/1.0 (contact@hiffi.com)"}
|
|
|
|
def get_wikimedia_image(name: str):
|
|
"""Searches Wikipedia and retrieves the top matched artist page's thumbnail."""
|
|
url = "https://en.wikipedia.org/w/api.php"
|
|
params = {
|
|
"action": "query",
|
|
"format": "json",
|
|
"generator": "search",
|
|
"gsrsearch": f"{name} rapper musician",
|
|
"gsrlimit": 1,
|
|
"prop": "pageimages",
|
|
"piprop": "thumbnail",
|
|
"pithumbsize": 600
|
|
}
|
|
try:
|
|
r = requests.get(url, params=params, headers=HEADERS, timeout=8)
|
|
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 get_deezer_image(name: str):
|
|
"""Queries Deezer API for verified editorial artist portraits."""
|
|
url = "https://api.deezer.com/search/artist"
|
|
params = {"q": name, "limit": 1}
|
|
try:
|
|
r = requests.get(url, params=params, timeout=8)
|
|
if r.status_code == 200:
|
|
data = r.json().get("data", [])
|
|
if data:
|
|
artist = data[0]
|
|
img = artist.get("picture_xl") or artist.get("picture_big") or artist.get("picture_medium")
|
|
if img and "artist-default" not in img:
|
|
return img
|
|
except Exception:
|
|
pass
|
|
return None
|
|
|
|
def main():
|
|
print("=" * 65)
|
|
print("HIFFI INTELLIGENCE: HIGH-RES PORTRAIT ENRICHMENT ENGINE")
|
|
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()
|
|
|
|
flagged = []
|
|
for artist_id, name, img in rows:
|
|
# Flag any artist using the Last.fm star placeholder or an empty image
|
|
if not img or LASTFM_STAR_HASH in img:
|
|
flagged.append((artist_id, name))
|
|
|
|
print(f"Targeting {len(flagged)} artists needing verified portraits...\n")
|
|
|
|
resolved = 0
|
|
for idx, (artist_id, name) in enumerate(flagged, start=1):
|
|
# 1. Try Wikimedia action search
|
|
img_url = get_wikimedia_image(name)
|
|
source = "Wikimedia"
|
|
|
|
# 2. Fall back to Deezer if Wikimedia has no thumbnail
|
|
if not img_url:
|
|
img_url = get_deezer_image(name)
|
|
source = "Deezer"
|
|
|
|
if img_url:
|
|
cur.execute("""
|
|
UPDATE artists
|
|
SET image_url = ?,
|
|
image_verified_flag = 1
|
|
WHERE artist_id = ?
|
|
""", (img_url, artist_id))
|
|
resolved += 1
|
|
print(f"[{idx:>3}/{len(flagged)}] [OK] ({source}) Saved portrait for {name}")
|
|
else:
|
|
print(f"[{idx:>3}/{len(flagged)}] [FAIL] Could not locate image for {name}")
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
print("\n" + "=" * 65)
|
|
print(f"Successfully resolved high-resolution portraits for {resolved} / {len(flagged)} artists.")
|
|
print("=" * 65)
|
|
|
|
if __name__ == "__main__":
|
|
main() |