ShopTRAINING/lyf开发日志记录文档.md

494 lines
45 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 开发日志记录
本文档记录了项目开发过程中的主要修改、问题修复和重要决策。
---
## 2025-07-13早期后端修复与重构
**开发者**: lyf
### 13:30 - 修复数据加载路径问题
- **任务目标**: 解决模型训练时因数据文件路径错误导致的数据加载失败问题。
- **核心问题**: `server/core/predictor.py` 中的 `PharmacyPredictor` 类初始化时,硬编码了错误的默认数据文件路径。
- **修复方案**: 将默认数据路径更正为 `'data/timeseries_training_data_sample_10s50p.parquet'`,并同步更新了所有训练器。
### 14:00 - 数据流重构
- **任务目标**: 解决因数据处理流程中断导致关键特征丢失,从而引发模型训练失败的根本问题。
- **核心问题**: `predictor.py` 未将预处理好的数据向下传递,导致各训练器重复加载并错误处理数据。
- **修复方案**: 重构了核心数据流,确保数据在 `predictor.py` 中被统一加载和预处理然后作为一个DataFrame显式传递给所有下游的训练器函数。
---
## 2025-07-14模型训练与并发问题集中攻坚
**开发者**: lyf
### 10:16 - 修复训练器层 `KeyError`
- **问题**: 所有模型训练均因 `KeyError: "['sales', 'price'] not in index"` 失败。
- **分析**: 训练器硬编码的特征列表中包含了数据源中不存在的 `'price'` 列。
- **修复**: 从所有四个训练器 (`mlstm`, `transformer`, `tcn`, `kan`) 的 `features` 列表中移除了对不存在的 `'price'` 列的依赖。
### 10:38 - 修复数据标准化层 `KeyError`
- **问题**: 修复后出现新错误 `KeyError: "['sales'] not in index"`
- **分析**: `server/utils/multi_store_data_utils.py` 中的 `standardize_column_names` 函数列名映射错误,且缺少最终列选择机制。
- **修复**: 修正了列名映射,并增加了列选择机制,确保函数返回的 `DataFrame` 结构统一且包含 `sales` 列。
### 11:04 - 修复JSON序列化失败问题
- **问题**: 训练完成后,因 `Object of type float32 is not JSON serializable` 导致前后端通信失败。
- **分析**: 训练产生的评估指标是NumPy的 `float32` 类型,无法被标准 `json` 库序列化。
- **修复**: 在 `server/utils/training_process_manager.py` 中增加了 `convert_numpy_types` 辅助函数在通过WebSocket或API返回数据前将所有NumPy数值类型转换为Python原生类型从根源上解决了所有序列化问题。
### 11:15 - 修复MAPE计算错误
- **问题**: 训练日志显示 `MAPE: nan%` 并伴有 `RuntimeWarning: Mean of empty slice.`
- **分析**: 当测试集中的所有真实值都为0时计算MAPE会导致对空数组求平均值。
- **修复**: 在 `server/analysis/metrics.py` 中增加条件判断若不存在非零真实值则直接将MAPE设为0。
### 11:41 - 修复“按店铺训练”页面列表加载失败
- **问题**: “选择店铺”的下拉列表为空。
- **分析**: `standardize_column_names` 函数错误地移除了包括店铺元数据在内的非训练必需列。
- **修复**: 将列筛选的逻辑从通用的 `standardize_column_names` 函数中移出,精确地应用到仅为模型训练准备数据的函数中。
### 13:00 - 修复“按店铺训练-所有药品”模式
- **问题**: 选择“所有药品”训练时,因 `product_id` 被错误地处理为字符串 `"unknown"` 而失败。
- **修复**: 在 `server/core/predictor.py` 中拦截 `"unknown"` ID并将其意图正确地转换为“聚合此店铺的所有产品数据”。同时扩展了 `aggregate_multi_store_data` 函数使其支持按店铺ID进行聚合。
### 14:19 - 修复并发训练中的稳定性问题
- **问题**: 并发训练时出现 `API列表排序错误``WebSocket连接错误`
- **修复**:
1. **排序**: 在 `api.py` 中为 `None` 类型的 `start_time` 提供了默认值,解决了 `TypeError`
2. **连接**: 在 `socketio.run()` 调用时增加了 `allow_unsafe_werkzeug=True` 参数解决了调试模式下Socket.IO与Werkzeug的冲突。
### 15:30 - 根治模型训练中的维度不匹配问题
- **问题**: 所有模型训练完成后,评估指标 `R²` 始终为0.0。
- **根本原因**: `server/utils/data_utils.py``create_dataset` 函数在创建目标数据集 `dataY` 时,错误地保留了一个多余的维度。同时,模型文件 (`mlstm_model.py`, `transformer_model.py`) 的输出也存在维度问题。
- **最终修复**:
1. **数据层**: 在 `create_dataset` 中使用 `.flatten()` 修正了 `y` 标签的维度。
2. **模型层**: 在所有模型的 `forward` 方法最后增加了 `.squeeze(-1)`,确保模型输出维度正确。
3. **训练器层**: 撤销了所有为解决此问题而做的临时性维度调整,恢复了最直接的损失计算。
### 16:10 - 修复“全局模型训练-所有药品”模式
- **问题**: 与“按店铺训练”类似,全局训练的“所有药品”模式也因 `product_id="unknown"` 而失败。
- **修复**: 采用了与店铺训练完全相同的修复模式。在 `predictor.py` 中拦截 `"unknown"` 并将其意图转换为真正的全局聚合(`product_id=None`),并扩展 `aggregate_multi_store_data` 函数以支持此功能。
---
## 2025-07-15端到端修复“按药品预测”图表功能
**开发者**: lyf
### 10:00 - 阶段一:修复数据库写入失败 (`sqlite3.IntegrityError`)
- **问题**: 后端日志显示 `datatype mismatch`
- **分析**: `save_prediction_result` 函数试图将复杂Python对象直接存入数据库。
- **修复**: 在 `server/api.py` 中,执行数据库插入前,使用 `json.dumps()` 将复杂对象序列化为JSON字符串。
### 10:30 - 阶段二修复API响应结构与前端不匹配
- **问题**: 图表依然无法渲染。
- **分析**: 前端期望 `history_data` 在顶层,而后端将其封装在 `data` 子对象中。
- **修复**: 修改 `server/api.py``predict` 函数,将关键数据提升到响应的根级别。
### 11:00 - 阶段三:修复历史数据与预测数据时间不连续
- **问题**: 图表数据在时间上完全脱节。
- **分析**: 获取历史数据的逻辑总是取整个数据集的最后30条而非预测起始日期之前的30条。
- **修复**: 在 `server/api.py` 中增加了正确的日期筛选逻辑。
### 14:00 - 阶段四:重构数据源,根治数据不一致问题
- **问题**: 历史数据(绿线)与预测数据(蓝线)的口径完全不同。
- **根本原因**: API层独立加载**原始数据**画图,而预测器使用**聚合后数据**预测。
- **修复 (重构)**:
1. 修改 `server/predictors/model_predictor.py`,使其返回预测结果的同时,也返回其所使用的、口径一致的历史数据。
2. 彻底删除了 `server/api.py` 中所有独立加载历史数据的冗余代码,确保了数据源的唯一性。
### 15:00 - 阶段五修复图表X轴日期格式问题
- **问题**: X轴显示为混乱的GMT格式时间戳。
- **分析**: `history_data` 中的 `Timestamp` 对象未被正确格式化。
- **修复**: 在 `server/api.py` 中,为 `history_data` 增加了 `.strftime('%Y-%m-%d')` 的格式化处理。
### 16:00 - 阶段六:修复模型“学不会”的根本原因 (超参数传递中断)
- **问题**: 即便流程正确,所有模型的预测结果依然是无法学习的直线。
- **根本原因**: `server/core/predictor.py` 在调用训练器时,**没有将 `sequence_length` 等关键超参数传递下去**,导致所有模型都使用了错误的默认值。
- **修复**:
1. 修改 `server/core/predictor.py`,在调用中加入超参数的传递。
2. 修改所有四个训练器文件,使其能接收并使用这些参数。
---
## 2025-07-16最终验证与项目总结
**开发者**: lyf
### 10:00 - 阶段七:最终验证与结论
- **问题**: 在修复所有代码问题后,对特定日期的预测结果依然是平线。
- **分析**: 通过编写临时数据分析脚本 (`temp_check_parquet.py`) 最终确认,这是**数据本身**的问题。我们选择的预测日期在样本数据集中恰好处于一个“零销量”的空白期。
- **最终结论**: 系统代码已完全修复。图表上显示的平线,是模型对“零销量”历史做出的**正确且符合逻辑**的反应。
### 11:45 - 项目总结与文档归档
- **任务**: 根据用户要求,回顾整个调试过程,将所有问题、解决方案、优化思路和最终结论,按照日期和时间顺序,整理并更新到本开发日志中,形成一份高质量的技术档案。
- **结果**: 本文档已更新完成。
### 13:15 - 最终修复:根治模型标识符不一致问题
- **问题**: 经过再次测试和日志分析,发现即便是修正后,店铺模型的 `model_identifier` 在训练时依然被错误地构建为 `01010023_store_01010023`
- **根本原因**: `server/core/predictor.py``train_model` 方法中,在 `training_mode == 'store'` 的分支下,构建 `model_identifier` 的逻辑存在冗余和错误。
- **最终解决方案**: 删除了错误的拼接逻辑 `model_identifier = f"{store_id}_{product_id}"`,直接使用在之前步骤中已经被正确赋值为 `f"store_{store_id}"``product_id` 变量作为 `model_identifier`。这确保了从训练、保存到最终API查询店铺模型的唯一标识符始终保持一致。
### 13:30 - 最终修复(第二轮):根治模型保存路径错误
- **问题**: 即便修复了标识符,模型版本依然无法加载。
- **根本原因**: 通过分析训练日志,发现所有训练器(`transformer_trainer.py`, `mlstm_trainer.py`, `tcn_trainer.py`)中的 `save_checkpoint` 函数,都会强制在 `saved_models` 目录下创建一个 `checkpoints` 子目录,并将所有模型文件保存在其中。而负责查找模型的 `get_model_versions` 函数只在根目录查找,导致模型永远无法被发现。
- **最终解决方案**: 逐一修改了所有相关训练器文件中的 `save_checkpoint` 函数,移除了创建和使用 `checkpoints` 子目录的逻辑,确保所有模型都直接保存在 `saved_models` 根目录下。
- **结论**: 至此,模型保存的路径与查找的路径完全统一,从根本上解决了模型版本无法加载的问题。
### 13:40 - 最终修复(第三轮):统一所有训练器的模型保存逻辑
- **问题**: 在修复了 `transformer_trainer.py` 后,发现 `mlstm_trainer.py``tcn_trainer.py` 存在完全相同的路径和命名错误,导致问题依旧。
- **根本原因**: `save_checkpoint` 函数在所有训练器中都被错误地实现,它们都强制创建了 `checkpoints` 子目录,并使用了错误的逻辑来拼接文件名。
- **最终解决方案**:
1. **逐一修复**: 逐一修改了 `transformer_trainer.py`, `mlstm_trainer.py`, 和 `tcn_trainer.py` 中的 `save_checkpoint` 函数。
2. **路径修复**: 移除了创建和使用 `checkpoints` 子目录的逻辑,确保模型直接保存在 `model_dir` (即 `saved_models`) 的根目录下。
3. **文件名修复**: 简化并修正了文件名的生成逻辑,直接使用 `product_id` 参数作为唯一标识符(该参数已由上游逻辑正确赋值为 `药品ID``store_{店铺ID}`),不再进行任何额外的、错误的拼接。
- **结论**: 至此所有训练器的模型保存逻辑完全统一模型保存的路径和文件名与API的查找逻辑完全匹配从根本上解决了模型版本无法加载的问题。
---
## 2025-07-16 (续):端到端修复“店铺预测”图表功能
**开发者**: lyf
### 15:30 - 最终修复(第四轮):打通店铺预测的数据流
- **问题**: 在解决了模型加载问题后,“店铺预测”功能虽然可以成功执行,但前端图表依然空白,不显示历史数据和预测数据。
- **根本原因**: 参数传递在调用链中出现断裂。
1. `server/api.py` 在调用 `run_prediction` 时,没有传递 `training_mode`
2. `server/core/predictor.py` 在调用 `load_model_and_predict` 时,没有传递 `store_id``training_mode`
3. `server/predictors/model_predictor.py` 内部的数据加载逻辑,在处理店铺预测时,错误地使用了模型标识符(`store_{id}`作为产品ID来过滤数据导致无法加载到任何历史数据。
- **最终解决方案 (三步修复)**:
1. **修复 `model_predictor.py`**: 修改 `load_model_and_predict` 函数,使其能够根据 `training_mode` 参数智能地加载数据。当模式为 `'store'` 时,它会正确地聚合该店铺的所有销售数据作为历史数据,这与训练时的数据准备方式完全一致。
2. **修复 `predictor.py`**: 修改 `predict` 方法,将 `store_id``training_mode` 参数正确地传递给底层的 `load_model_and_predict` 函数。
3. **修复 `api.py`**: 修改 `predict` 路由和 `run_prediction` 辅助函数,确保 `training_mode` 参数在整个调用链中被完整传递。
- **结论**: 通过以上修复我们确保了从API接口到最底层数据加载器的参数传递是完整和正确的。现在无论是药品预测还是店铺预测系统都能够加载正确的历史数据用于图表绘制彻底解决了图表显示空白的问题。
### 16:16 - 项目状态更新
- **状态**: **所有已知问题已修复**
- **确认**: 用户已确认“现在药品和店铺预测流程通了。
- **后续**: 将本次修复过程归档至本文档。
---
### 2025年7月16日 18:38 - 全模型预测功能通用性修复
**问题现象**:
在解决了 `Transformer` 模型的预测问题后,发现一个更深层次的系统性问题:在所有预测模式(按药品、按店铺、全局)中,只有 `Transformer` 算法可以成功预测并显示图表,而其他四种模型(`mLSTM`, `KAN`, `优化版KAN`, `TCN`)虽然能成功训练,但在预测时均会失败,并提示“没有可用于图表的数据”。
**根本原因深度分析**:
这个问题的核心在于**模型配置的持久化不完整且不统一**。
1. **Transformer 的“幸存”**: `Transformer` 模型的实现恰好不依赖于那些在保存时被遗漏的特定超参数,因此它能“幸存”下来。
2. **其他模型的“共性缺陷”**: 其他所有模型 (`mLSTM`, `TCN`, `KAN`) 在它们的构造函数中,都依赖于一些在训练时定义、但在保存到检查点文件 (`.pth`) 时**被遗漏的**关键结构性参数。
* **mLSTM**: 缺少 `mlstm_layers`, `embed_dim`, `dense_dim` 等参数。
* **TCN**: 缺少 `num_channels`, `kernel_size` 等参数。
* **KAN**: 缺少 `hidden_sizes` 列表。
3. **连锁失败**:
*`server/predictors/model_predictor.py` 尝试加载这些模型的检查点文件时,它从 `checkpoint['config']` 中找不到实例化模型所必需的全部参数。
* 模型实例化失败,抛出 `KeyError``TypeError`
* 这个异常导致 `load_model_and_predict` 函数提前返回 `None`,最终导致返回给前端的响应中缺少 `history_data`,前端因此无法渲染图表。
**系统性、可扩展的解决方案**:
为了彻底解决这个问题,并为未来平稳地加入新算法,我们对所有非 Transformer 的训练器进行了标准化的、彻底的修复。
1. **修复 `mlstm_trainer.py`**: 在 `config` 字典中补全了 `mlstm_layers`, `embed_dim`, `dense_dim` 等所有缺失的参数。
2. **修复 `tcn_trainer.py`**: 在 `config` 字典中补全了 `num_channels`, `kernel_size` 等所有缺失的参数。
3. **修复 `kan_trainer.py`**: 在 `config` 字典中补全了 `hidden_sizes` 列表。
**结果**:
通过这次系统性的修复,我们确保了所有训练器在保存模型时,都会将完整的、可用于重新实例化模型的配置信息写入检查点文件。这从根本上解决了所有模型算法的预测失败问题,使得整个系统在处理不同算法时具有了通用性和健壮性。
---
## 2025-07-17系统性链路疏通与规范化
**开发者**: lyf
### 15:00 - 创建技术文档与上手指南
- **任务**: 为了便于新成员理解和未来维护,创建了两份核心技术文档。
- **产出**:
1. **`系统调用逻辑与核心代码分析.md`**: 一份深入代码细节的端到端调用链路分析文档,详细描述了从前端交互到后端处理,再到模型训练和预测的完整流程。
2. **`项目快速上手指南.md`**: 一份面向新成员特别是Java背景的高层次指南通过技术栈类比、架构分层图和清晰的开发流程帮助新成员快速建立对项目的宏观理解。
### 16:00 - 修复 `mLSTM` 模型加载链路
- **问题**: `mLSTM` 模型在预测时因参数名不一致而加载失败。
- **分析**:
- 第一次失败: 加载器需要 `num_layers`,但训练器保存的是 `mlstm_layers`
- 第二次失败: 加载器需要 `dropout`,但训练器保存的是 `dropout_rate`
- **修复**: 遵循“保存方决定命名”的原则,修改了 `server/predictors/model_predictor.py`,将加载时使用的参数名统一为 `mlstm_layers``dropout_rate`,与训练器保持一致。
### 16:45 - 修复 `mLSTM` 模型算法缺陷
- **问题**: `mLSTM` 模型修复加载问题后,预测结果为一条无效的直线。
- **根本原因**: `server/models/mlstm_model.py` 中的模型架构存在设计缺陷。其解码器逻辑错误地将输入序列的最后一个时间步复制多份作为预测,导致模型无法学习时间序列的变化。
- **修复**: 重构了 `MLSTMTransformer` 类的 `forward` 方法,移除了有问题的解码器逻辑,改为直接使用编码器最终的隐藏状态通过一个线性层进行预测,从根本上修正了算法的实现。
### 17:00 - 修复 `TCN` 模型加载链路
- **问题**: `TCN` 模型在预测加载时存在硬编码参数,是一个潜在的崩溃点。
- **分析**: `server/predictors/model_predictor.py` 在创建 `TCNForecaster` 实例时,硬编码了 `kernel_size=3`,而没有从模型配置中读取。
- **修复**: 修改了 `model_predictor.py`,使其从 `config['kernel_size']` 中动态读取该参数,确保了配置的完整性和一致性。
### 17:15 - 修复 `KAN` 模型版本发现问题
- **问题**: `KAN``优化版KAN` 训练成功后,在预测页面无法找到任何模型版本。
- **根本原因**: **保存**和**搜索**逻辑不匹配。`kan_trainer.py` 使用 `model_manager.py``..._product_...` 格式保存模型,而 `server/core/config.py` 中的 `get_model_versions` 函数却只按 `..._epoch_...` 的格式进行搜索。
- **修复**: 扩展了 `config.py` 中的 `get_model_versions` 函数,使其能够兼容并搜索多种命名格式,包括 `KAN` 模型使用的 `..._product_...` 格式。
### 17:25 - 修复 `KAN` 模型文件路径生成问题
- **问题**: 修复版本发现问题后,点击预测依然失败,提示“未找到模型文件”。
- **根本原因**: 只修复了**版本发现**逻辑,但未同步修复**文件路径生成**逻辑。`config.py` 中的 `get_model_file_path` 函数在为 `KAN` 模型生成路径时,依然错误地使用了 `_epoch_` 格式。
- **修复**: 修改了 `get_model_file_path` 函数,为 `kan``optimized_kan` 模型增加了特殊处理,确保在生成其文件路径时使用正确的 `_product_` 命名格式。
### 17:40 - 升级 `KAN` 训练器的版本管理功能
- **问题**: `KAN` 模型只有一个静态的 `'v1'` 版本,与其他模型(有 `best`, `final_epoch_...` 等版本)不一致。
- **根本原因**: `kan_trainer.py` 的实现逻辑过于简单,缺少在训练过程中动态评估并保存多个版本的功能,仅在最后硬编码保存为 `'v1'`
- **修复 (功能升级)**: 重构了 `server/trainers/kan_trainer.py`,为其增加了与其他训练器完全一致的动态版本管理功能。现在它可以在训练时自动追踪并保存性能最佳的 `best` 版本,并在训练结束后保存 `final_epoch_...` 版本。
### 17:58 - 最终结论
- **状态**: **所有已知问题已修复**
- **成果**:
1. 所有模型的 **“数据 -> 训练 -> 保存 -> 加载 -> 预测 -> 可视化”** 执行链路已全面打通和验证。
2. 统一并修复了所有模型在配置持久化和加载过程中的参数不一致问题。
3. 将所有模型的版本管理逻辑和工程实现标准完全对齐。
4. 创建并完善了核心技术文档,固化了开发规范。
- **项目状态**: 系统现在处于一个健壮、一致且可扩展的稳定状态。
---
## 2025-07-18: 系统性重构模型版本管理机制
**开发者**: lyf
### 14:00 - 根治版本混乱与模型加载失败问题
- **问题现象**: `KAN` 及其他算法在训练后,预测时出现版本号混乱(如出现裸数字 `1``3``best` 等无效版本)、版本重复、以及因版本不匹配导致的“模型文件未找到”的 `404` 错误。
- **根本原因深度分析**:
1. **逻辑分散**: 版本生成的逻辑分散在各个训练器 (`trainer`) 中,而版本发现的逻辑在 `config.py` 中,两者标准不一,充满冲突的正则表达式和硬编码规则。
2. **命名不统一**: `KAN` 训练器使用 `model_manager` 保存,而其他训练器使用本地的 `save_checkpoint` 函数,导致了 `..._product_..._v1.pth``..._epoch_best.pth` 等多种不兼容的命名格式并存。
3. **提取错误**: `config.py` 中的 `get_model_versions` 函数因其过于宽泛和冲突的匹配规则,会从文件名中错误地提取出无效的版本号,是导致前端下拉框内容混乱的直接原因。
- **系统性重构解决方案**:
1. **确立单一权威**: 将 [`server/utils/model_manager.py`](server/utils/model_manager.py:1) 确立为系统中唯一负责版本管理、模型命名和文件IO的组件。
2. **实现自动版本控制**: 在 `ModelManager` 中增加了 `_get_next_version` 内部方法,使其能够自动扫描现有文件,并安全地生成下一个递增的、带 `v` 前缀的版本号(如 `v3`)。
3. **统一所有训练器**: 全面重构了 `kan_trainer.py`, `mlstm_trainer.py`, `tcn_trainer.py`, 和 `transformer_trainer.py`。现在,所有训练器在保存最终模型时,都调用 `model_manager.save_model` 并且**不再自行决定版本号**,完全由 `ModelManager` 自动生成。对于训练过程中的最佳模型,则统一显式保存为 `best` 版本。
4. **清理与加固**: 废弃并删除了 `config.py` 中所有旧的、有问题的版本管理函数,并重写了 `get_model_versions`,使其只使用严格的正则表达式来查找和解析符合新命名规范的模型版本。
5. **优化API**: 更新了 `api.py`,使其完全与新的 `ModelManager` 对接,并改进了预测失败时的错误信息反馈。
- **结论**: 通过这次重构系统的版本管理机制从一个分散、混乱、充满硬编码的状态升级为了一个集中的、统一的、自动化的健壮系统。所有已知相关的bug已被从根本上解决。
---
## 2025-07-18 (续): 实现“按店铺”AI闭环及连锁Bug修复
**开发者**: lyf
### 15:00 - 架构升级:实现“按店铺”训练与预测功能
- **任务目标**: 在现有“按药品”模式基础上增加并打通“按店铺”维度的完整AI闭环。
- **核心挑战**: 需要对数据处理、模型标识、训练流程和API调用进行系统性改造以支持新的训练模式。
- **解决方案 (四步重构)**:
1. **升级 `ModelManager`**: 重新设计了模型命名规则,为店铺和全局模型提供了清晰、无歧义的标识(如 `transformer_store_S001_v1.pth`),并同步更新了解析逻辑。
2. **修正核心预测器**: 修复了 `predictor.py` 中的关键逻辑缺陷,确保在店铺模式下,系统能生成并使用正确的 `model_identifier`(如 `store_S001`),并强制调用数据聚合函数。
3. **适配API层**: 调整了 `api.py` 中的训练和预测接口,使其能够兼容和正确处理新的店铺模式请求。
4. **统一所有训练器**: 对全部四个训练器文件进行了统一修改,确保它们在保存模型时,都正确地使用了新的 `model_identifier`
### 15:30 - 连锁Bug修复第一环解决店铺模型版本加载失败
- **问题现象**: “按店铺预测”页面的模型版本下拉框为空。
- **根本原因**: `api.py` 中负责获取店铺模型版本的接口 `get_store_model_versions_api` 仍在使用旧的、不兼容新命名规范的函数来查找模型。
- **修复**: 重写了该接口,使其放弃旧函数,转而使用 `ModelManager` 来进行统一、可靠的模型查找。
### 15:40 - 连锁Bug修复第二环解决店铺预测 `404` 失败
- **问题现象**: 版本列表加载正常后,点击“开始预测”返回 `404` 错误。
- **根本原因**: 后端预测接口 `predict()` 内部的执行函数 `load_model_and_predict` 存在一段过时的、手动的模型文件查找逻辑,它完全绕过了 `ModelManager`,并错误地构建了文件路径。
- **修复 (联合重构)**:
1. **改造 `model_predictor.py`**: 彻底移除了 `load_model_and_predict` 函数内部所有过时的文件查找代码,并修改其函数签名,使其直接接收一个明确的 `model_path` 参数。
2. **改造 `api.py`**: 修改了 `predict` 接口将在API层通过 `ModelManager` 找到的正确模型路径,一路传递到最底层的 `load_model_and_predict` 函数中,确保了调用链的逻辑一致性。
### 15:50 - 连锁Bug修复第三环解决服务启动 `NameError`
- **问题现象**: 在修复预测逻辑后API服务无法启动报错 `NameError: name 'Optional' is not defined`
- **根本原因**: 在修改 `model_predictor.py` 时,使用了 `Optional` 类型提示,但忘记从 `typing` 模块导入。
- **修复**: 在 `server/predictors/model_predictor.py` 文件顶部添加了 `from typing import Optional`
- **最终结论**: 至此所有与“按店铺”功能相关的架构升级和连锁bug均已修复。系统现在能够稳定、正确地处理两种维度的训练和预测任务并且代码逻辑更加统一和健壮。
---
## 2025-07-21前后端联合调试与UI修复
**开发者**: lyf
### 15:45 - 修复后端 `DataFrame` 序列化错误
- **问题现象**: 在清理了历史模型并重新进行预测后,前端出现 `Object of type DataFrame is not JSON serializable` 错误。
- **根本原因**: `server/predictors/model_predictor.py` 中的 `load_model_and_predict` 函数在返回结果时,为了兼容旧版接口而保留的 `'predictions'` 字段,其值依然是未经处理的 Pandas DataFrame (`predictions_df`)。
- **修复方案**: 修改了该函数的返回字典,将 `'predictions'` 字段的值也更新为已经过 `.to_dict('records')` 方法处理的 `prediction_data_json`确保了返回对象的所有部分都是JSON兼容的。
### 16:00 - 统一修复所有预测视图的图表渲染问题
- **问题现象**: 在解决了后端的序列化问题后所有三个预测视图按药品、按店铺、全局的图表均为空白并且图表下方的日期副标题显示为未经格式化的原始JavaScript日期字符串。
- **根本原因深度分析**:
1. **数据访问路径不精确**: 前端代码直接从API响应的根对象 (`response.data`) 中获取数据,而最可靠的数据源位于 `response.data.data` 中。
2. **日期对象处理不当**: 前端代码未能将从后端接收到的日期无论是字符串还是由axios自动转换的Date对象标准化为统一的字符串格式。这导致在使用 `Set` 对日期进行去重时,因对象引用不同而失败,最终图表上没有数据点。
- **统一修复方案**:
1. **逐一修改**: 逐一修改了 `ProductPredictionView.vue`, `StorePredictionView.vue`, 和 `GlobalPredictionView.vue` 三个文件。
2. **修正数据访问**: 在 `startPrediction` 方法中将API响应的核心数据 `response.data.data` 赋值给 `predictionResult`
3. **标准化日期**: 在 `renderChart` 方法的开头,增加了一个 `formatDate` 辅助函数,并在处理数据时立即调用它,将所有日期都统一转换为 `'YYYY-MM-DD'` 格式的字符串,从而一举解决了数据点丢失和标题格式错误的双重问题。
- **最终结论**: 至此所有预测视图的前后端数据链路和UI展示功能均已修复系统功能恢复正常。
---
## 2025-07-24UI/UX 优化与后端逻辑统一
**开发者**: Roo (AI Assistant) & lyf
### 14:30 - 统一预测图表颜色风格
- **任务**: 根据用户反馈将所有预测结果图表的文字颜色包括标题、副标题、图例、坐标轴统一修改为白色以适应深色UI背景。
- **实施**:
- 逐一修改了 `ProductPredictionView.vue`, `StorePredictionView.vue`, 和 `GlobalPredictionView.vue`
-`Chart.js``options` 配置中,将所有相关的 `color` 属性设置为 `'white'`,并将网格线颜色调整为半透明白色 `rgba(255, 255, 255, 0.2)`
### 14:50 - 修复“按店铺预测”图表标题显示错误
- **问题**: “按店铺预测”的图表标题显示为 `undefined`
- **根本原因**: 后端 `server/api.py` 在处理店铺预测时,没有查询并返回真实的店铺名称,导致前端无法获取该数据。
- **修复方案 (后端优先)**:
1.`server/api.py` 中新增了 `get_store_name` 辅助函数,用于根据 `store_id` 查询店铺名称。
2. 修改了 `/api/prediction` 接口,在 `training_mode``'store'` 时,调用新函数获取店铺名,并将其以 `store_name` 字段返回给前端。
- **结论**: 通过统一后端逻辑,确保了数据源的正确性,从根本上解决了问题。
### 15:05 - 统一模型列表时间显示格式
- **任务**: 根据用户要求将所有预测页面模型列表中的“创建时间”从ISO格式统一为 `YYYY-MM-DD HH:MM:SS` 的24小时制格式。
- **实施**:
- 逐一修改了 `ProductPredictionView.vue`, `StorePredictionView.vue`, 和 `GlobalPredictionView.vue`
-`<script setup>` 中添加了 `formatDateTime` 辅助函数。
-`<el-table-column>` 中使用 `:formatter="formatDateTime"` 属性来应用该格式化函数实现了UI显示的统一。
---
## 2025-07-24 (续): 深度调试与修复“历史预测”模块
**开发者**: Roo (AI Assistant) & lyf
### 16:00 - 阶段一:深度调试并修复“历史预测”图表渲染失败问题
- **问题现象**: “历史预测”详情页的预测趋势图始终为空白尽管后端API正常返回数据且页面下方的数据表格也能正确显示。
- **根本原因分析 (复合型问题)**:
1. **数据结构不匹配**: 前端 `HistoryView.vue` 对后端返回的数据结构处理逻辑过于复杂且存在错误,未能正确构建出图表渲染所需的数据对象。
2. **DOM渲染时序问题**: 图表容器在一个 `el-dialog` 弹窗内其渲染时机与Chart.js的初始化时机存在冲突。在弹窗动画完成前图表容器的尺寸为0导致Chart.js初始化失败。
- **最终解决方案 (彻底重构)**:
1. **后端API加固**: 统一并简化了 `/api/prediction/history/{id}` 接口的返回数据结构,确保其直接、清晰地提供前端所需的所有信息。
2. **前端实现统一**: 对 `UI/src/views/HistoryView.vue` 进行了彻底重构将其图表渲染的全部实现包括DOM结构、元素引用方式、渲染时机和函数逻辑与一个已知能正常工作的参照组件 (`ProductPredictionView.vue`) 完全同步,从根本上解决了数据处理和渲染时序的双重问题。
### 17:00 - 阶段二:修复历史数据天数被截断的问题
- **问题现象**: 在图表问题修复后发现无论预测时设置了多少天历史详情页的图表和数据总是显示被截断后的天数例如预测35天只显示7天
- **根本原因分析**: `server/api.py``predict` 函数在处理预测请求时如果前端没有传递天数参数会错误地回退到硬编码的默认值历史30天预测7天
- **解决方案 (代码与数据双重修复)**:
1. **后端代码修复**: 修改了 `server/api.py``predict` 函数,移除了默认值,强制要求前端在请求中必须提供 `future_days``history_lookback_days` 参数,确保用户的设置能被正确处理。
2. **历史数据修复**: 创建并执行了一个新的Python脚本 `fix_old_predictions.py`。该脚本遍历数据库中所有已存在的历史记录识别出被截断的数据并使用原始参数重新生成完整的预测结果覆盖掉旧的、不完整的数据文件。该脚本也经过了多次调试以处理文件编码、方法调用错误和JSON序列化等问题。
- **最终结论**: 至此,所有与“历史预测”模块相关的功能缺陷和数据一致性问题均已得到彻底解决。系统现在能够正确生成、保存、修复并完整展示所有历史预测的结果。
---
## 2025-07-25项目文档体系建立与路径Bug修复
**开发者**: Roo (AI Assistant) & lyf
### 18:30 - 修复预测结果保存路径错误
- **问题现象**: 预测成功后,生成的详细结果 `.json` 文件被错误地保存到了 `static/predictions/` 目录下,而非预期的 `saved_predictions/` 目录。
- **根本原因**: `server/api.py` 中的 `save_prediction_result` 辅助函数硬编码了旧的、不规范的保存路径。
- **修复方案**:
1. **标准化配置**: 在 `server/core/config.py` 中新增了 `DEFAULT_PREDICTIONS_DIR` 配置项,指向正确的 `saved_predictions/` 目录。
2. **修正代码**: 修改了 `server/api.py` 中的 `save_prediction_result` 函数,使其从配置文件中读取正确的路径,彻底解决了硬编码问题。
### 18:45 - 创建并完善项目核心技术文档
- **任务目标**: 解决项目因快速迭代而导致的文档缺失与过时问题,为新成员提供准确的上手材料,并固化当前稳定的系统架构。
- **实施过程**:
1. **全面分析**: 对项目的技术栈、核心工作流、数据存储结构、异步任务处理和模块化设计(如模型管理器、注册表)进行了全面的代码级分析。
2. **撰写新指南**: 基于分析结果,撰写并覆盖生成了一份全新的、内容详尽的 **`项目快速上手指南.md`**。
3. **文档迭代**: 根据开发者的提问,在新指南中补充了关于“数据库索引 -> JSON文件内容”的读取机制说明以及关于如何管理和清理历史产物的“系统维护与扩展”章节。
- **最终成果**: 产出了一份高质量、与当前代码完全同步的核心技术指南,显著提升了项目的可维护性和知识传承效率。
---
## 2025-07-25 (续): 历史数据一致性修复
**开发者**: Roo (AI Assistant) & lyf
### 19:45 - 修复历史预测详情加载失败 (404 Not Found)
- **问题现象**: 在修复了新预测的保存路径后,前端历史预测列表中的旧记录在点击“查看详情”时,会报错“预测结果文件不存在”。
- **根本原因分析**: 这是一个**数据一致性**问题。虽然我们修复了**新数据**的写入逻辑,但数据库中仍然存在大量**旧记录**,这些记录的 `file_path` 字段依然指向了旧的、错误的 `static/predictions/` 路径。
- **解决方案 (数据清理)**:
1. **创建清理脚本**: 创建了一个一次性维护脚本 `server/tools/delete_old_predictions.py`,用于安全地清理这些“脏数据”。
2. **调试与修复**: 脚本的初版存在时区比较逻辑错误未能正确识别本地时区的记录。在经过一轮调试将时间比较基准从UTC修正为本地时间后脚本得以正常工作。
3. **执行清理**: 最终成功执行脚本,从数据库中清除了所有在指定时间点之前创建的、带有错误文件路径的历史记录。
- **最终结论**: 通过对数据库中的存量数据进行清理,彻底解决了因新旧数据路径不一致而导致的 `404` 错误,确保了系统数据的一致性和功能的稳定性。
---
## 2025-07-26核心数据源替换与系统级重构
**开发者**: Roo (AI Assistant) & lyf
### 第一阶段:核心数据源替换与适配器重构
- **任务目标**: 将项目的数据源从旧的、简单的 `timeseries_training_data_sample_10s50p.parquet` 彻底更换为新的、特征更丰富、结构更复杂的核心数据集。
- **核心挑战**: 新旧数据集在表结构(如 `subbh` vs `store_id`)、数据类型、特征集(如新数据缺少 `is_promotion` 列)和数据粒度上存在巨大差异,直接替换会导致系统全面崩溃。
- **解决方案 (适配器模式)**:
1. **创建中央数据适配器**: 新建了 `server/utils/new_data_loader.py`,作为整个系统唯一的数据入口。
2. **实现动态转换**: 该适配器负责加载新数据集,并动态地将其转换为旧代码库能够理解的格式,包括重命名列、用 `0` 填充缺失的 `is_promotion` 特征、以及处理数据类型。
3. **全面重构**: 系统性地重构了所有数据消费端——包括 `server/api.py`, `server/core/predictor.py` 以及 `server/trainers/` 目录下的**所有**训练器脚本——使其不再直接加载数据,而是统一通过新的数据适配器获取,从而实现了新数据源与现有业务逻辑的完全解耦。
### 第二阶段:端到端迭代调试与连锁问题修复
在完成重构后,我们进行了一系列端到端的测试,并修复了因此次重大变更而引发的一系列连锁问题。
- **修复 `KeyError`**: 解决了因新旧列名 (`subbh` vs `store_id`) 不匹配导致的键查找错误。
- **修复 `NaN` 值问题**: 在实现“按店铺训练-所有商品”的聚合逻辑时,因部分商品在某些日期无销售记录,导致聚合操作引入了`NaN`值。通过在所有训练器的数据准备阶段增加 `.fillna(0)` 清理步骤,彻底解决了该问题。
- **修复 `TypeError` (JSON序列化)**: 解决了在API响应中因返回了未经处理的 `numpy.ndarray``datetime.date` 对象而导致的JSON序列化失败问题。
- **修复 XGBoost 预测逻辑的根本性错误**:
- **问题现象**: 使用新数据训练的 `XGBoost` 模型,后端预测返回 `200 OK`,但前端图表渲染失败。
- **根本原因**: `server/predictors/model_predictor.py` 中存在一个严重的逻辑缺陷。它错误地对 `XGBoost` 模型使用了为 `PyTorch` 模型设计的“自回归”循环预测逻辑(即预测一天,再用该预测值去预测下一天)。而 `XGBoost` 模型本身是“直接多步输出”模型,一次性就能返回所有未来日期的预测值。错误的循环逻辑导致系统只取用了 `XGBoost` 完整输出结果中的第一个值,并将其错误地复制了多天,生成了无用的预测结果。
- **最终修复**: 在 `model_predictor.py` 中为 `XGBoost` 模型创建了一个独立的、非循环的逻辑分支。该分支能够正确地接收并处理 `XGBoost` 的完整输出数组,从而生成了正确的、可供前端渲染的预测结果。
### 第三阶段:系统环境清理
- **任务目标**: 在最终测试前,确保一个完全纯净的、不受任何旧数据或旧模型干扰的系统环境。
- **实施过程**: 在开发者的精确指导下,我们完成了以下清理工作:
1. **文件系统清理**: 手动删除了 `saved_models``saved_predictions` 文件夹中的所有历史产物。
2. **数据库清理**: 成功执行了 `server/tools/delete_old_predictions.py` 脚本,清空了 `prediction_history.db` 数据库中所有过时的预测记录。
- **最终结论**: 至此,数据源替换、系统重构、连锁问题修复和环境清理工作已全部完成。项目现在处于一个代码逻辑更健壮、数据源更可靠的全新状态,并已准备好进行最终的完整性验证。
---
## 2025-07-26 (续): 端到端测试与系统级修复
**开发者**: Roo (AI Assistant) & lyf
### 第三阶段 (续): 迭代修复与架构澄清
在对重构后的系统进行全面的端到端测试时我们发现并修复了一系列深层次的、与特定模型架构和训练模式相关的Bug。
- **修复 `XGBoost` 自定义天数预测崩溃的Bug**:
- **问题现象**: 使用 `XGBoost` 模型进行预测时,如果自定义的预测天数与模型训练时固定的预测范围不符,程序会因数组长度不匹配而崩溃。
- **架构澄清**: 我们确认了 `XGBoost` 是“直接多步输出”模型,其预测长度在训练时已固定。
- **最终修复**: 修改了 `server/predictors/model_predictor.py`,使其不再依赖用户输入的预测天数,而是根据模型**实际**的输出长度来动态生成日期序列,从而保证了程序的健壮性。
- **修复 `CnnBiLstmAttention` 模型预测逻辑错误**:
- **问题现象**: 该模型预测成功,但前端图表渲染失败。
- **根本原因**: 与 `XGBoost` 类似,该模型也是“直接多步输出”架构,但被错误地注册给了为“自回归”模型设计的预测函数,导致生成了无意义的预测结果。
- **最终修复**: 在 `server/predictors/model_predictor.py` 中,为 `CnnBiLstmAttention` 模型创建了一个专属的、正确的、非回归式的预测逻辑分支,确保其能被正确处理。
- **修复“全局训练”模式数据筛选逻辑错误**:
- **问题现象**: 在“全局训练”模式下,选择“所有店铺所有药品”时,训练因找不到任何数据而失败。
- **根本原因**: `server/core/predictor.py` 在处理该模式时,错误地使用了一个特殊的信号值(如 `unknown`)去筛选 `product_id`,导致数据集为空。
- **最终修复**: 重构了该部分的逻辑,确保在选择“所有药品”时,程序能正确地跳过按 `product_id` 筛选的步骤,直接对整个数据集进行聚合。
- **修复“全局预测”模式数据加载逻辑错误**:
- **问题现象**: “全局预测”模式因找不到数据而失败。
- **根本原因**: `server/predictors/model_predictor.py` 中存在与训练逻辑不一致的镜像Bug。
- **最终修复**: 再次修改了 `model_predictor.py`,使其“全局预测”的数据加载逻辑与 `predictor.py` 中的训练逻辑完全同步。
- **澄清“负销量”是数据特性而非Bug**:
- **问题现象**: 在“全局预测”的图表中,历史销量出现了负数。
- **分析**: 经过讨论,我们确认这是由于原始数据中包含了“退货”等业务场景,导致按天聚合求和后出现负值。
- **最终决策**: 为了尊重元数据的真实性,我们决定**不**在代码中将负数强制修正为0并接受这可能会对模型的训练和预测结果产生影响。这是一个重要的、关于数据处理哲学的决策。
- **全链路增强以支持“自定义全局训练”功能**:
- **问题现象**: 在“全局训练”中选择“自定义范围”(指定店铺和药品列表)时,训练失败。
- **根本原因**: 这是一个**全链路的参数传递中断**问题。从API接口到进程管理器再到核心训练逻辑整个系统都没有为处理这个新增的、复杂的自定义范围参数做好准备。
- **最终修复 (三位一体的全链路改造)**:
1. **升级API层 (`api.py`)**: 修改了 `/api/training` 接口,使其能够正确接收前端传递的 `selected_stores``selected_products` 列表。
2. **升级进程管理层 (`training_process_manager.py`)**: 对 `TrainingTask` 数据类和核心函数进行了全面改造,使其能够完整地接收、存储和向下传递这些新的自定义范围参数。
3. **升级核心逻辑层 (`predictor.py`)**: 对 `train_model` 函数进行了重大功能增强,为其增加了处理 `selected_stores``selected_products` 列表的全新逻辑分支。
- **最终结论**: 通过这次彻底的全链路改造我们不仅修复了Bug还成功地为系统增加了一项强大的新功能。至此所有在端到端测试中发现的已知问题均已得到解决。
- **最终修复“加权平均”聚合引入NaN值的Bug**:
- **问题现象**: 在“全局训练”模式下,选择“加权平均”聚合方式时,训练因 `Input contains NaN` 错误而失败。
- **根本原因**: 在 `server/core/predictor.py` 中,为实现“加权平均”而设计的自定义聚合逻辑,在将计算出的加权销售额与其他特征(如`weekday`, `month`合并时如果某些日期的特征数据不完整会导致合并后的DataFrame中产生NaN值。
- **最终修复**: 在 `predictor.py` 的加权平均逻辑分支下,于数据合并操作(`pd.merge`)之后,增加了一个关键的 `.fillna(0, inplace=True)` 数据清洗步骤确保了在任何情况下传递给下游训练器的数据都是纯净、不含NaN值的。
- **最终结论**: 至此,所有在本次大规模、长周期、端到端测试中发现的已知问题,均已得到彻底解决。系统在功能、稳定性和健壮性上都达到了一个新的高度。