From 82d57af6669fcb7c745a3d81796386e629ddc8a9 Mon Sep 17 00:00:00 2001 From: aszerW Date: Sat, 23 May 2026 23:57:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(flask=5Fserver):=20=E4=BF=AE=E5=A4=8D=20pic?= =?UTF-8?q?kle=20=E5=8F=8D=E5=BA=8F=E5=88=97=E5=8C=96=E5=90=8E=20JSON=20?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题修复: - pickle 反序列化后 attrs 包含真实 DataFrame/Series 对象 - build_premium_result_from_attrs 需要兼容 Series 对象和字典格式 - API 层需要将 DataFrame/Series 转换为 JSON 可序列化格式 修复方案: - build_premium_result_from_attrs 支持 pd.Series 和 dict 两种输入 - API 层将 DataFrame 转换为 records 格式(orient='records') - API 层将 Series 索引转换为字符串日期 - 过滤内部缓存元数据(_cache_*) --- datasource/flask_server.py | 65 ++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/datasource/flask_server.py b/datasource/flask_server.py index bac4226..ff739ea 100644 --- a/datasource/flask_server.py +++ b/datasource/flask_server.py @@ -460,12 +460,12 @@ def build_premium_result(premium_series: pd.Series) -> Dict: } -def build_premium_result_from_attrs(premium_data: Dict) -> Dict: +def build_premium_result_from_attrs(premium_data) -> Dict: """ - 从 attrs 格式构建溢价率返回结果 + 从 attrs 格式构建溢价率返回结果(兼容 Series 对象和字典格式) Args: - premium_data: attrs 中的溢价率数据,格式为: + premium_data: pd.Series 对象或字典格式: { 'type': 'series', 'data': {date_str: premium_value, ...}, @@ -475,16 +475,25 @@ def build_premium_result_from_attrs(premium_data: Dict) -> Dict: Returns: 包含 premium_series, latest_premium, premium_date, premium_stats 的字典 """ - if not premium_data or premium_data.get('type') != 'series': + # 处理 None + if premium_data is None: return {} - # 从 dict 恢复为 Series - premium_dict = premium_data.get('data', {}) - if not premium_dict: + # 如果是 pd.Series 对象(pickle 反序列化后) + if isinstance(premium_data, pd.Series): + premium_series = premium_data + # 如果是字典格式(旧 JSON 序列化格式) + elif isinstance(premium_data, dict): + if premium_data.get('type') != 'series': + return {} + premium_dict = premium_data.get('data', {}) + if not premium_dict: + return {} + premium_series = pd.Series(premium_dict) + premium_series.index = pd.to_datetime(premium_series.index) + else: return {} - premium_series = pd.Series(premium_dict) - premium_series.index = pd.to_datetime(premium_series.index) premium_series.index.name = 'date' # 转换为日期-溢价率列表 @@ -735,13 +744,49 @@ def get_ohlcv(): # 提取净值到顶层(方便调用方使用) if 'nav' in attrs: - result['nav'] = attrs['nav'] + nav_df = attrs['nav'] + if isinstance(nav_df, pd.DataFrame): + # 将 DataFrame 转换为列表格式(JSON 可序列化) + nav_df_copy = nav_df.reset_index().copy() + nav_df_copy['date'] = nav_df_copy['date'].dt.strftime('%Y-%m-%d') + nav_dict = { + 'data': nav_df_copy.to_dict(orient='records'), + 'count': len(nav_df_copy) + } + result['nav'] = nav_dict + else: + result['nav'] = nav_df # 提取溢价率到顶层(调用业务函数处理格式) if 'premium' in attrs: premium_result = build_premium_result_from_attrs(attrs['premium']) if premium_result: result.update(premium_result) + + # 将 attrs 中的 DataFrame/Series 转换为字典格式(用于 JSON 序列化) + attrs_serializable = {} + for key, value in attrs.items(): + if isinstance(value, pd.DataFrame): + df_copy = value.reset_index().copy() + if 'date' in df_copy.columns: + df_copy['date'] = df_copy['date'].dt.strftime('%Y-%m-%d') + attrs_serializable[key] = { + 'data': df_copy.to_dict(orient='records'), + 'count': len(df_copy) + } + elif isinstance(value, pd.Series): + # 将 Series 索引转换为字符串 + series_copy = value.copy() + series_copy.index = series_copy.index.strftime('%Y-%m-%d') + attrs_serializable[key] = { + 'type': 'series', + 'data': series_copy.to_dict(), + 'name': value.name + } + else: + attrs_serializable[key] = value + + result['attrs'] = attrs_serializable # 如果用户指定了类型但与自动检测不同,显示提示 if asset_type_param and detected_type != final_type: