基于情绪的音乐推荐系统突发Spotify API 404错误排查求助
基于情绪的Spotify音乐推荐系统持续返回404错误排查方案
问题概述
我开发的基于情绪的音乐推荐系统此前运行完全正常,但近期通过情绪获取音乐推荐时,持续返回404状态码错误,无法定位问题根源。核心代码如下:
Music.py
import requests import random from ai_ml.src.utils import get_spotify_access_token from ai_ml.src.config import CONFIG def get_music_recommendation(emotion, market=None): try: access_token = get_spotify_access_token() except Exception as e: print(f"Error retrieving access token: {e}") return [] emotion_to_genre = { "happy": [ "acoustic", "afrobeat", "alt-rock", "alternative", "ambient", "blues", "bossa nova", "brazil", "chill", "classical", "club", "comedy", "dance", "disco", "drum-and-bass", "edm", "electro", "electronic", "folk", "funk", "garage", "gospel", "groove", "grunge", "happy", "house", "idm", "indie", "indie-pop", "industrial", "j-dance", "j-idol", "j-pop", "j-rock", "jazz", "k-pop", "kids", "latin", "latino", "pop", "pop-film", "post-dubstep", "power-pop", "progressive-house", "reggae", "reggaeton", "rock", "rock-n-roll", "salsa", "samba", "show-tunes", "singer-songwriter", "ska", "summer", "swedish", "synth-pop", "tango", "techno", "trance", "world-music" ], "sad": [ "blues", "classical", "emo", "folk", "indie-pop", "jazz", "latin", "latino", "metalcore", "post-dubstep", "punk", "r-n-b", "rainy-day", "rock", "sad", "singer-songwriter", "soul" ], "angry": [ "black-metal", "death-metal", "grindcore", "hardcore", "heavy-metal", "industrial", "metal", "metal-misc", "metalcore", "punk-rock", "punk" ], "surprise": [ "anime", "electro", "experimental", "idm", "j-dance", "j-idol", "j-pop", "j-rock", "post-dubstep", "psych-rock", "trip-hop", "turkish" ], "neutral": [ "acoustic", "ambient", "chill", "classical", "country", "dancehall", "deep-house", "detroit-techno", "dub", "dubstep", "edm", "electro", "electronic", "folk", "french", "groove", "hard-rock", "honky-tonk", "house", "idm", "indie", "indie-pop", "industrial", "j-pop", "kids", "latin", "mpb", "new-age", "new-release", "opera", "party", "pop", "reggae", "reggaeton", "rockabilly", "singer-songwriter", "soul", "soundtracks", "study", "synth-pop", "techno" ] } genre = emotion_to_genre.get(emotion.lower(), "pop") headers = { "Authorization": f"Bearer {access_token}" } available_markets = [ "AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PR", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW" ] selected_market = market if market in available_markets else random.choice(available_markets) params = { "seed_genres": genre, "limit": 25, "market": selected_market } if emotion == "happy": params["target_valence"] = 0.8 params["target_energy"] = 0.7 elif emotion == "sad": params["target_valence"] = 0.2 params["target_energy"] = 0.2 elif emotion == "angry": params["target_valence"] = 0.2 params["target_energy"] = 0.9 elif emotion == "surprise": params["target_valence"] = 0.6 params["target_energy"] = 0.8 else: params["target_valence"] = 0.5 params["target_energy"] = 0.5 response = requests.get("https://api.spotify.com/v1/recommendations", headers=headers, params=params) if response.status_code == 401: print("Access token expired. Please refresh the token.") return [] elif response.status_code != 200: print(f"Failed to fetch music recommendations. Status code: {response.status_code}") return [] tracks = response.json().get("tracks", []) recommended_tracks = [ { "name": track["name"], "artist": ", ".join([artist["name"] for artist in track["artists"]]), "preview_url": track.get("preview_url"), "external_url": track.get("external_urls", {}).get("spotify"), "image_url": next((img["url"] for img in track["album"]["images"]), None), "album_name": track["album"]["name"], "release_date": track["album"].get("release_date"), "track_duration": track.get("duration_ms") // 1000 if track.get("duration_ms") else None, "popularity": track.get("popularity"), "explicit": track.get("explicit"), } for track in tracks ] if not recommended_tracks: print(f"No tracks found for genre: {genre}") return recommended_tracks
utils.py
import base64 import requests from ai_ml.src.config import CONFIG def get_spotify_access_token(): client_id = CONFIG["spotify_client_id"] client_secret = CONFIG["spotify_client_secret"] token_url = "https://accounts.spotify.com/api/token" # Create the authorization header auth_header = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode() headers = { "Authorization": f"Basic {auth_header}" } data = { "grant_type": "client_credentials" } response = requests.post(token_url, headers=headers, data=data) if response.status_code != 200: raise Exception("Failed to retrieve Spotify access token") return response.json().get("access_token")
config为独立Python脚本,存储Spotify的client_id与client_secret。
排查与修复方案
1. 核心问题:seed_genres参数格式错误
Spotify的/v1/recommendations API要求seed_genres参数传入逗号分隔的字符串,但当前代码直接将genre列表赋值给该参数,导致请求参数格式不合法,API无法识别,返回404错误。同时默认值"pop"是字符串类型,和其他情绪的列表类型不一致,会引发后续处理错误。
修复步骤:
- 修改genre获取逻辑,默认值改为列表类型,保持统一:
genre = emotion_to_genre.get(emotion.lower(), ["pop"]) - 将genre列表转为逗号分隔的字符串传入params:
params = { "seed_genres": ",".join(genre), "limit": 25, "market": selected_market }
2. 其他排查方向
- 验证API端点:确认
https://api.spotify.com/v1/recommendations拼写正确,可通过curl或Postman直接测试该端点,传入合法参数验证是否正常返回。 - 检查市场参数:打印
selected_market值,确认是Spotify支持的有效市场代码。 - 确认令牌有效性:打印
access_token,用该令牌在测试工具中访问API,验证权限是否正常。 - 种子参数数量:确保
seed_genres对应的字符串非空,Spotify要求至少提供一个种子参数。
内容的提问来源于stack exchange,提问作者Sam




