You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask音乐推荐API响应缓慢及500内部服务器错误排查求助

问题分析与解决方案

针对你的Flask音乐推荐系统中/recommendation端点的响应慢和偶发500错误问题,以下是针对性的优化和修复方案:


一、解决响应时间过长问题

1. 缓存预处理后的数据集

每次请求都重新读取CSV并执行字符串处理、合并等操作是最大性能瓶颈。建议提前预处理数据集并缓存到内存或本地文件:

import pickle
from flask import Flask

app = Flask(__name__)

# 全局变量存储缓存数据
spotify_df = None
complete_feature_set_cache = None

# 首次请求前加载预处理好的数据
@app.before_first_request
def load_preprocessed_data():
    global spotify_df, complete_feature_set_cache
    # 提前运行一次预处理,将结果保存为pickle(仅需执行一次)
    # spotify_df = ... # 执行所有数据清洗、合并逻辑
    # with open('spotify_preprocessed.pkl', 'wb') as f:
    #     pickle.dump(spotify_df, f)
    
    # 启动时加载缓存
    with open('spotify_preprocessed.pkl', 'rb') as f:
        spotify_df = pickle.load(f)
    # 预计算特征集
    float_cols = spotify_df.dtypes[spotify_df.dtypes == 'float64'].index.values
    complete_feature_set_cache = create_feature_set(spotify_df, float_cols=float_cols)

2. 批量调用Spotify API

原代码中循环调用sp.track(x)会产生大量网络请求,改为批量获取:

async def generate_playlist_recos(df, features, nonplaylist_features):
    non_playlist_df = df[df['id'].isin(nonplaylist_features['id'].values)]
    non_playlist_df['sim'] = cosine_similarity(nonplaylist_features.drop('id', axis=1).values,
                                               features.values.reshape(1, -1))[:, 0]
    non_playlist_df_top_40 = non_playlist_df.sort_values('sim', ascending=False).head(40)
    
    # 批量获取专辑封面URL,替代循环调用
    track_ids = non_playlist_df_top_40['id'].tolist()
    tracks_info = sp.tracks(track_ids)
    url_map = {track['id']: track['album']['images'][1]['url'] for track in tracks_info['tracks']}
    non_playlist_df_top_40['url'] = non_playlist_df_top_40['id'].map(url_map)
    
    return non_playlist_df_top_40

3. 替换低效的pandas循环

将generate_playlist_feature中的iterrows循环改为向量化操作:

def generate_playlist_feature(complete_feature_set, playlist_df, weight_factor):
    complete_feature_set_playlist = complete_feature_set[
        complete_feature_set['id'].isin(playlist_df['id'].values)
    ].merge(playlist_df[['id', 'date_added']], on='id', how='inner')
    complete_feature_set_nonplaylist = complete_feature_set[
        ~complete_feature_set['id'].isin(playlist_df['id'].values)
    ]

    playlist_feature_set = complete_feature_set_playlist.sort_values('date_added', ascending=False)
    most_recent_date = playlist_feature_set['date_added'].max()
    
    # 向量化计算月份差,替代iterrows
    playlist_feature_set['months_from_recent'] = ((most_recent_date - playlist_feature_set['date_added']).dt.days // 30).astype(int)
    playlist_feature_set['weight'] = weight_factor ** (-playlist_feature_set['months_from_recent'])
    
    # 批量加权计算,避免逐行操作
    feature_cols = playlist_feature_set.columns.difference(['id', 'date_added', 'months_from_recent', 'weight'])
    playlist_feature_set[feature_cols] = playlist_feature_set[feature_cols].multiply(playlist_feature_set['weight'], axis=0)
    
    return playlist_feature_set[feature_cols].sum(axis=0), complete_feature_set_nonplaylist

4. 移除不必要的异步操作

普通Flask不原生支持async路由,异步函数可能导致执行异常或性能损耗,将所有async修饰符移除,改为同步函数。


二、解决偶发500内部服务器错误

1. 完善错误日志与捕获

当前异常捕获仅返回简单错误信息,无法定位具体问题,添加详细日志:

import logging
import traceback

logging.basicConfig(filename='app_error.log', level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')

@app.route('/recommendation', methods=['GET'])
def recommendation():
    try:
        # ... 业务逻辑
    except Exception as e:
        # 记录完整错误回溯
        logging.error("Recommendation endpoint failed", exc_info=True)
        # 返回详细错误信息用于调试
        return traceback.format_exc(), 500

2. 处理Spotify API异常

Spotify API调用可能因网络、权限或资源不存在抛出异常,单独捕获并处理:

from spotipy.exceptions import SpotifyException

def create_necessary_outputs(playlist_name, id_dic, df):
    try:
        playlist_tracks = pd.DataFrame(sp.playlist(id_dic[playlist_name])['tracks']['items'])
    except SpotifyException as e:
        raise ValueError(f"Spotify API request failed: {e.msg}")
    
    playlist_df = playlist_tracks[
        ['track.artists[0].name', 'track.name', 'track.id', 'track.album.images[1].url', 'added_at']
    ]
    playlist_df.columns = ['artist', 'name', 'id', 'url', 'date_added']
    playlist_df['date_added'] = pd.to_datetime(playlist_df['date_added'])
    playlist_df = playlist_df[playlist_df['id'].isin(df['id'].values)].sort_values('date_added', ascending=False)
    
    # 处理空播放列表情况
    if playlist_df.empty:
        raise ValueError("No valid tracks found in the selected playlist")
    
    return playlist_df

3. 检查空DataFrame操作

在关键步骤添加空值检查,避免后续操作抛出异常:

def recommendation():
    try:
        # ... 其他逻辑
        playlist_random = create_necessary_outputs(next(iter(tracks.keys())), tracks, spotify_df)
        if playlist_random.empty:
            return jsonify({"error": "No valid tracks in playlist"}), 400
        # ... 后续逻辑
    except ValueError as e:
        return jsonify({"error": str(e)}), 400

内容的提问来源于stack exchange,提问作者Kenvin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 20:00:12