File size: 6,474 Bytes
5f39c5f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | #!/usr/bin/env python3
import base64
import json
import os
import re
import sys
import tempfile
import urllib.request
from datetime import datetime
from gradio_client import Client, handle_file
import contextlib
import io
def get_itunes_top10():
"""Fetches top 10 tracks, metadata, and audio preview URLs directly from iTunes RSS."""
url = "https://itunes.apple.com/us/rss/topsongs/limit=10/json"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
try:
with urllib.request.urlopen(req) as resp:
data = json.loads(resp.read().decode("utf-8"))
entries = data["feed"]["entry"]
entries = entries if isinstance(entries, list) else [entries]
songs = []
for idx, entry in enumerate(entries[:10], 1):
title = entry["im:name"]["label"]
artist = entry["im:artist"]["label"]
genre = entry["category"]["attributes"]["label"]
# Extract 30s audio preview URL
links = entry.get("link", [])
preview_url = None
if isinstance(links, list):
for l in links:
attrs = l.get("attributes", {})
if attrs.get("title") == "Preview" or attrs.get("type", "").startswith("audio"):
preview_url = attrs.get("href")
break
elif isinstance(links, dict):
preview_url = links.get("attributes", {}).get("href")
songs.append({
"rank": idx,
"title": title,
"artist": artist,
"genre": genre,
"preview_url": preview_url,
})
return songs
except Exception as e:
print(f"Error fetching iTunes top tracks: {e}", file=sys.stderr)
return []
def extract_embedded_chart(res, max_width=220):
"""
Extracts plot data from Gradio's response (file path, raw SVG, or dict)
and formats it into a self-contained inline element for Markdown tables.
"""
# 1. Unpack list/tuple wrappers returned by gradio_client
if isinstance(res, (tuple, list)):
for item in res:
if isinstance(item, (dict, str)):
res = item
break
plot_data = None
if isinstance(res, dict):
plot_data = res.get("plot") or res.get("value") or res.get("name") or res.get("path")
elif isinstance(res, str):
plot_data = res
if not plot_data or not isinstance(plot_data, str):
return "No plot payload"
# 2. Handle temporary file paths created on disk by gradio_client
if os.path.isfile(plot_data):
try:
if plot_data.lower().endswith(".svg"):
with open(plot_data, "r", encoding="utf-8") as f:
svg_content = f.read()
svg_clean = re.sub(r"<\?xml.*?\?>", "", svg_content, flags=re.DOTALL).strip()
svg_single_line = re.sub(r"\s+", " ", svg_clean)
return f'<div style="max-width: {max_width}px; max-height: 150px; display: inline-block;">{svg_single_line}</div>'
else:
# Base64-encode PNG/JPEG files directly into an inline <img> tag
with open(plot_data, "rb") as f:
encoded = base64.b64encode(f.read()).decode("utf-8")
ext = os.path.splitext(plot_data)[1].lstrip(".").lower() or "png"
return f'<img src="data:image/{ext};base64,{encoded}" width="{max_width}" alt="Classification Plot" />'
except Exception as e:
return f"Error reading chart file: {e}"
# 3. Handle raw in-memory SVG string
if "<svg" in plot_data:
svg_clean = re.sub(r"<\?xml.*?\?>", "", plot_data, flags=re.DOTALL).strip()
svg_single_line = re.sub(r"\s+", " ", svg_clean)
return f'<div style="max-width: {max_width}px; max-height: 150px; display: inline-block;">{svg_single_line}</div>'
# 4. Handle raw Base64 data URI string
if plot_data.startswith("data:image"):
return f'<img src="{plot_data}" width="{max_width}" alt="Classification Plot" />'
return f"Unsupported payload: {plot_data[:40]}..."
def main():
print("Fetching iTunes Top 10 tracks...", file=sys.stderr)
songs = get_itunes_top10()
if not songs:
print("Error: Could not retrieve iTunes top tracks.", file=sys.stderr)
sys.exit(1)
print("Connecting to Hugging Face Space (dkappe/AISong)...", file=sys.stderr)
# Mute stdout while connecting to the Space
with contextlib.redirect_stdout(io.StringIO()):
client = Client("dkappe/AISong")
date_str = datetime.now().strftime("%Y-%m-%d")
results = []
for song in songs:
rank = song["rank"]
title = song["title"]
artist = song["artist"]
genre = song["genre"]
preview_url = song["preview_url"]
if not preview_url:
print(f"[{rank}/10] '{title}' - No audio preview available.", file=sys.stderr)
results.append((rank, title, artist, genre, "No Preview Available"))
continue
print(f"[{rank}/10] Analyzing '{title}' by {artist}...", file=sys.stderr)
with tempfile.NamedTemporaryFile(suffix=".m4a", delete=False) as tmp:
tmp_path = tmp.name
try:
urllib.request.urlretrieve(preview_url, tmp_path)
res = client.predict(handle_file(tmp_path), api_name="/predict")
chart_html = extract_embedded_chart(res, max_width=220)
results.append((rank, title, artist, genre, chart_html))
except Exception as e:
print(f"Error evaluating '{title}': {e}", file=sys.stderr)
results.append((rank, title, artist, genre, f"Error: {e}"))
finally:
if os.path.exists(tmp_path):
os.remove(tmp_path)
# Output Markdown
print("# iTunes Weekly Top 10 Audio Classification Report")
print(f"**Date:** {date_str}\n")
print("Classifier Model: [`dkappe/AISong`](https://huggingface.co/spaces/dkappe/AISong)\n")
print("| Rank | Song Name | Artist | Genre | Classification Plot |")
print("| :---: | :--- | :--- | :--- | :---: |")
for r, t, a, g, p in results:
clean_title = t.replace("|", "/")
clean_artist = a.replace("|", "/")
print(f"| {r} | {clean_title} | {clean_artist} | {g} | {p} |")
if __name__ == "__main__":
main()
|