From fa563140ca416fc1d0cd93a7c263f653f5a21098 Mon Sep 17 00:00:00 2001 From: LYFxiaoan Date: Fri, 25 Jul 2025 15:06:39 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=A2=84=E6=B5=8Bjson?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=B7=AF=E5=BE=84=E8=87=B3=EF=BC=9Asaved=5Fp?= =?UTF-8?q?redictions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prediction_history.db | Bin 167936 -> 167936 bytes ..._19549899-43bc-4a16-8a9e-c897d25693fb.json | 1 + server/api.py | 9 +- server/core/config.py | 4 +- 项目快速上手指南.md | 228 ++++++++++-------- 5 files changed, 140 insertions(+), 102 deletions(-) create mode 100644 saved_predictions/prediction_19549899-43bc-4a16-8a9e-c897d25693fb.json diff --git a/prediction_history.db b/prediction_history.db index 725300c485318fc03a9cee74126714d40f1419fc..b2a9488f706a43a4497d3fc16658f2c20baf3c5f 100644 GIT binary patch delta 10305 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 MPyXfCMc str: diff --git a/项目快速上手指南.md b/项目快速上手指南.md index b263f4d..114c5fd 100644 --- a/项目快速上手指南.md +++ b/项目快速上手指南.md @@ -1,127 +1,161 @@ -# 项目快速上手指南 (面向新开发者) +# 项目快速上手指南 (v2.0 - 2025年7月版) -欢迎加入项目!本指南旨在帮助你快速理解项目的核心功能、技术架构和开发流程,特别是为你(一位Java背景的开发者)提供清晰的切入点。 +欢迎加入项目!本指南旨在帮助你快速理解项目的核心功能、最新的技术架构和开发流程。 -## 1. 项目是做什么的?(实现了什么功能) +## 1. 项目核心功能 -这是一个基于历史销售数据的 **智能销售预测系统**。 +这是一个基于历史销售数据的 **智能销售预测系统**,其核心是实现一个 **"数据 -> 训练 -> 模型 -> 预测 -> 可视化"** 的完整闭环。 -核心功能有三个,全部通过Web界面操作: -1. **模型训练**: 用户可以选择某个**药品**、某个**店铺**或**全局**数据,然后选择一种机器学习算法(如Transformer、mLSTM等)进行训练,最终生成一个预测模型。 +所有功能均通过Web界面操作: +1. **模型训练**: 用户可以选择某个**药品**、某个**店铺**或**全局**数据,然后选择一种机器学习算法(如Transformer、KAN等)进行训练。训练过程是**异步**的,并能通过WebSocket实时反馈进度。 2. **销售预测**: 使用已经训练好的模型,对未来的销量进行预测。 3. **结果可视化**: 将历史销量和预测销量在同一个图表中展示出来,方便用户直观地看到趋势。 +4. **模型与历史管理**: 提供对已训练模型和历史预测记录的查询、详情查看和删除功能。 -简单来说,它就是一个 **"数据 -> 训练 -> 模型 -> 预测 -> 可视化"** 的完整闭环应用。 +## 2. 技术栈 -## 2. 用了什么技术?(技术栈) +| 层面 | 本项目技术 | 说明 | +| :--- | :--- | :--- | +| **后端框架** | **Flask** | 轻量级的Python Web框架,用于提供API接口。 | +| **前端框架** | **Vue.js** | 用于构建用户交互界面的现代化JavaScript框架。 | +| **核心算法库** | **PyTorch** | 实现深度学习算法的核心库。 | +| **数据处理** | **Pandas** | Python中用于数据分析和处理的核心库。 | +| **数据库** | **SQLite** | 一个轻量级的本地文件数据库,用于记录模型元数据和预测历史。 | +| **实时通信** | **Flask-SocketIO** | 用于后端在训练时向前端实时推送日志和进度。 | +| **异步任务** | **multiprocessing** | Python标准库,用于将耗时的训练任务放到独立的子进程中执行,避免阻塞API服务。 | -你可以将这个项目的技术栈与Java世界进行类比: +## 3. 系统架构与数据流 -| 层面 | 本项目技术 | Java世界类比 | 说明 | -| :--- | :--- | :--- | :--- | -| **后端框架** | **Flask** | Spring Boot | 一个轻量级的Web框架,用于提供API接口。 | -| **前端框架** | **Vue.js** | React / Angular | 用于构建用户交互界面的现代化JavaScript框架。 | -| **核心算法库** | **PyTorch** | (无直接对应) | 类似于Java的Deeplearning4j,是实现深度学习算法的核心。 | -| **数据处理** | **Pandas** | (无直接对应) | Python中用于数据分析和处理的“瑞士军刀”,可以看作是内存中的强大数据表格。 | -| **构建/打包** | **Vite** (前端) | Maven / Gradle | 前端项目的构建和依赖管理工具。 | -| **数据库** | **SQLite** | H2 / MySQL | 一个轻量级的本地文件数据库,用于记录预测历史等。 | -| **实时通信** | **Socket.IO** | WebSocket / STOMP | 用于后端在训练时向前端实时推送进度。 | - -## 3. 系统架构是怎样的?(架构层级和设计) - -本项目是经典的前后端分离架构,可以分为四个主要层次: +本项目是经典的前后端分离架构,其数据流和核心组件如下: ``` -+------------------------------------------------------+ -| 用户 (Browser) | -+------------------------------------------------------+ - | -+------------------------------------------------------+ -| 1. 前端层 (Frontend - Vue.js) | -| - Views (页面组件, e.g., ProductPredictionView.vue) | -| - API Calls (使用axios与后端通信) | -| - Charting (使用Chart.js进行图表渲染) | -+------------------------------------------------------+ - | (HTTP/S, WebSocket) -+------------------------------------------------------+ -| 2. 后端API层 (Backend API - Flask) | -| - api.py (类似Controller, 定义RESTful接口) | -| - 接收请求, 验证参数, 调用业务逻辑层 | -+------------------------------------------------------+ - | -+------------------------------------------------------+ -| 3. 业务逻辑层 (Business Logic - Python) | -| - core/predictor.py (类似Service层) | -| - 封装核心业务, 如“根据参数选择合适的训练器” | -+------------------------------------------------------+ - | -+------------------------------------------------------+ -| 4. 数据与模型层 (Data & Model - PyTorch/Pandas) | -| - trainers/*.py (具体的算法实现和训练逻辑) | -| - predictors/model_predictor.py (模型加载与预测逻辑) | -| - saved_models/ (存放训练好的.pth模型文件) | -| - data/ (存放原始数据.parquet文件) | -+------------------------------------------------------+ ++-----------------------------------------------------------------+ +| 用户 (Browser - Vue.js) | ++-----------------------------------------------------------------+ + | (1. HTTP/WebSocket请求) ++-----------------------------------------------------------------+ +| 后端API层 (Backend API - Flask) | +| - api.py: 定义所有RESTful接口 (e.g., /api/training) | +| - 接收请求, 验证参数, 调用核心服务层 | ++-----------------------------------------------------------------+ + | (2. 调用核心服务) ++-----------------------------------------------------------------+ +| 核心服务与管理层 (Core Services) | +| - training_process_manager.py: 异步训练任务管理器 (关键) | +| - model_manager.py: 模型保存、加载、版本控制 (关键) | +| - model_registry.py: 算法与训练器的注册表 (关键) | ++-----------------------------------------------------------------+ + | (3. 执行具体任务) ++-----------------------------------------------------------------+ +| 算法实现与数据处理层 (Algorithm & Data) | +| - trainers/*.py: 具体的算法训练逻辑 (e.g., kan_trainer.py) | +| - predictors/model_predictor.py: 模型加载与预测逻辑 | +| - models/*.py: PyTorch模型定义 (e.g., kan_model.py) | +| - utils/data_utils.py: 数据预处理和转换工具 | ++-----------------------------------------------------------------+ + | (4. 读写物理文件) ++-----------------------------------------------------------------+ +| 物理存储层 (Storage) | +| - data/*.parquet: 原始时序数据 | +| - saved_models/*.pth: 训练好的模型文件 (权重、配置、缩放器) | +| - saved_predictions/*.json: 详细的预测结果文件 | +| - prediction_history.db: SQLite数据库 (存储元数据) | ++-----------------------------------------------------------------+ ``` -## 4. 关键执行流程 +## 4. 核心工作流详解:“数据 -> 训练 -> 预测” -以最常见的“按药品预测”为例: +#### **步骤一:数据准备** +- **原始数据**: 存储在 [`data/timeseries_training_data_sample_10s50p.parquet`](data/timeseries_training_data_sample_10s50p.parquet)。 +- **元数据**: 存储在根目录的 `prediction_history.db` SQLite数据库中。 -1. **前端**: 用户在页面上选择药品和模型,点击“预测”按钮。Vue组件通过`axios`向后端发送一个POST请求到 `/api/prediction`。 -2. **API层**: `api.py` 接收到请求,像一个Controller一样,解析出药品ID、模型类型等参数。 -3. **业务逻辑层**: `api.py` 调用 `core/predictor.py` 中的 `predict` 方法,将参数传递下去。这一层是业务的“调度中心”。 -4. **模型层**: `core/predictor.py` 最终调用 `predictors/model_predictor.py` 中的 `load_model_and_predict` 函数。 -5. **模型加载与执行**: - * 根据参数在 `saved_models/` 目录下找到对应的模型文件(例如 `transformer_store_01010023_best.pth` 或 `mlstm_product_17002608_v3.pth`)。 - * 加载文件,从中恢复出 **模型结构**、**模型权重** 和 **数据缩放器**。 - * 准备最新的历史数据作为输入,执行预测。 - * 将预测结果返回。 -6. **返回与渲染**: 结果逐层返回到`api.py`,在这里被格式化为JSON,然后发送给前端。前端接收到JSON后,使用`Chart.js`将历史和预测数据画在图表上。 +#### **步骤二:模型训练 (异步)** +1. **API触发**: 前端调用 `POST /api/training` ([`server/api.py`](server/api.py:815))。 +2. **任务提交**: `api.py` 将训练请求提交给**训练进程管理器** (`training_process_manager`),并立即返回一个任务ID,不阻塞主服务。 +3. **动态执行**: + * 管理器在**新的子进程**中运行任务。 + * 它通过**模型注册表** (`model_registry`) 找到 `model_type` 对应的训练器函数(例如,`kan` -> `kan_trainer.py` 中的函数)。 + * 训练器加载数据,进行归一化,然后执行PyTorch训练循环。 +4. **模型保存**: + * 训练完成后,调用**模型管理器** (`model_manager`) 的 `save_model` 方法。 + * 模型(权重、配置、缩放器)被打包保存在 [`saved_models/`](saved_models/) 目录下,命名如 `kan_product_P001_v1.pth`。 + * 模型的元数据(路径、版本、指标)被写入数据库的 `model_versions` 表。 + +#### **步骤三:模型预测 (同步)** +1. **API触发**: 前端调用 `POST /api/prediction` ([`server/api.py`](server/api.py:1273))。 +2. **模型定位**: `api.py` 调用**模型管理器** (`model_manager`),根据参数从数据库中找到对应的模型文件路径。 +3. **加载与预测**: + * 核心逻辑在 [`server/predictors/model_predictor.py`](server/predictors/model_predictor.py) 的 `load_model_and_predict` 函数中。 + * 该函数加载 `.pth` 文件,并利用其中的 `config` 和 `state_dict` **精确重建模型实例**。 + * 执行**自回归预测**:预测一天,将结果作为下一天输入的一部分,循环往复。 +4. **结果保存**: + * 完整的预测结果(历史、预测、分析等)被保存为一个JSON文件到 [`saved_predictions/`](saved_predictions/) 目录。 + * 该次预测的元数据(包括JSON文件路径)被写入数据库的 `prediction_history` 表。 +5. **返回与渲染**: 完整的JSON结果被返回给前端,前端使用图表库进行可视化。 ## 5. 如何添加一个新的算法?(开发者指南) -这是你最可能接触到的新功能开发。假设你要添加一个名为 `NewNet` 的新算法,你需要按以下步骤操作: +假设你要添加一个名为 `NewNet` 的新算法。 **目标**: 让 `NewNet` 出现在前端的“模型类型”下拉框中,并能成功训练和预测。 -1. **创建训练器文件**: - * 在 `server/trainers/` 目录下,复制一份现有的训练器文件(例如 `tcn_trainer.py`)并重命名为 `newnet_trainer.py`。 - * 在 `newnet_trainer.py` 中: - * 定义你的 `NewNet` 模型类(继承自 `torch.nn.Module`)。 - * 修改 `train_..._with_tcn` 函数,将其重命名为 `train_..._with_newnet`。 - * 在这个新函数里,确保实例化的是你的 `NewNet` 模型。 - * **最关键的一步**: 在保存checkpoint时,确保 `config` 字典里包含了重建 `NewNet` 所需的所有超参数(比如层数、节点数等)。 +1. **创建模型定义文件**: + * 在 `server/models/` 目录下,创建 `newnet_model.py`。 + * 在其中定义你的 `NewNet` 模型类,继承自 `torch.nn.Module`。 - * **重要开发规范:参数命名规则** - 为了防止在模型加载时出现参数不匹配的错误(例如 `KeyError: 'num_layers'`),我们制定了以下命名规范: - > **规则:** 对于特定于某个算法的超参数,其在 `config` 字典中的键名(key)必须以该算法的名称作为前缀或唯一标识。 +2. **创建训练器文件**: + * 在 `server/trainers/` 目录下,创建 `newnet_trainer.py`。 + * 复制一份现有训练器(如 `kan_trainer.py`)的内容作为模板。 + * **关键修改**: + * 导入你的 `NewNet` 模型。 + * 在训练函数中,实例化你的 `NewNet` 模型。 + * 在保存checkpoint时,确保 `config` 字典里包含了重建 `NewNet` 所需的所有超参数。 + * 在文件末尾,**注册你的训练器**: `register_trainer('newnet', your_training_function)`。 - **示例:** - * 对于 `mLSTM` 模型的层数,键名应为 `mlstm_layers`。 - * 对于 `TCN` 模型的通道数,键名可以是 `tcn_channels`。 - * 对于 `Transformer` 模型的编码器层数,键名可以是 `num_encoder_layers` (因为这在Transformer语境下是明确的)。 +3. **创建预测器逻辑 (如果需要)**: + * 大多数情况,你可以复用默认的预测器。打开 [`server/predictors/model_predictor.py`](server/predictors/model_predictor.py)。 + * 在 `load_model_and_predict` 函数中,添加一个 `elif loaded_model_type == 'newnet':` 分支,确保它能根据 `config` 正确地创建 `NewNet` 模型实例。 + * 在文件末尾,**注册你的预测器**: `register_predictor('newnet', default_pytorch_predictor)`。如果你的模型有特殊的预测逻辑,可以自定义一个预测函数并注册它。 - 在 **加载模型时** ([`server/predictors/model_predictor.py`](server/predictors/model_predictor.py:1)),必须使用与保存时完全一致的键名来读取这些参数。遵循此规则可以从根本上杜绝因参数名不一致导致的模型加载失败问题。 +4. **更新前端界面**: + * 打开 `server/api.py` 中的 `get_model_types` 函数。 + * 在 `model_meta` 字典中添加 `'newnet'` 的元数据,包括名称、描述和标签类型。 + * **无需修改前端代码**,前端的下拉框会自动从这个API获取最新的模型列表。 -2. **注册新模型**: - * 打开 `server/core/config.py` 文件。 - * 找到 `SUPPORTED_MODELS` 列表。 - * 在列表中添加你的新模型标识符 `'newnet'`。 +完成以上步骤后,重启服务,你就可以在界面上选择并使用你的新算法了。这个插件式的设计大大简化了新算法的集成过程。 -3. **接入业务逻辑层 (训练)**: - * 打开 `server/core/predictor.py` 文件。 - * 在 `train_model` 方法中,找到 `if/elif` 模型选择逻辑。 - * 添加一个新的 `elif model_type == 'newnet':` 分支,让它调用你在第一步中创建的 `train_..._with_newnet` 函数。 +## 6. 系统维护与扩展 -4. **接入模型层 (预测)**: - * 打开 `server/predictors/model_predictor.py` 文件。 - * 在 `load_model_and_predict` 函数中,找到 `if/elif` 模型实例化逻辑。 - * 添加一个新的 `elif model_type == 'newnet':` 分支,确保它能根据 `config` 正确地创建 `NewNet` 模型实例。 +随着系统的持续运行,会不断产生模型文件、预测结果等历史产物。理解如何管理这些产物对于保持系统的健康至关重要。 -5. **更新前端界面**: - * 打开 `UI/src/views/training/` 和 `UI/src/views/prediction/` 目录下的相关Vue文件(如 `ProductTrainingView.vue`)。 - * 找到定义模型选项的地方(通常是一个数组或对象)。 - * 添加 `{ label: '新网络模型 (NewNet)', value: 'newnet' }` 这样的新选项。 +### 6.1. 历史产物管理 (Artifacts Management) -完成以上步骤后,重启服务,你就可以在界面上选择并使用你的新算法了。 \ No newline at end of file +**问题**: +随着时间推移,`saved_models/` 和 `saved_predictions/` 目录下的文件会越来越多,导致项目体积变得臃肿。 + +**当前状态**: +系统目前依赖**手动清理**。您可以通过Web界面删除单个模型或单条预测历史,程序会自动删除对应的文件。 + +**推荐的解决方案**: +为了实现自动化管理,推荐创建一个独立的维护脚本,并实施**数据保留策略 (Data Retention Policy)**。 + +#### **自动化清理策略** + +1. **创建清理脚本**: + * 可以在 `server/tools/` 目录下创建一个新脚本,例如 `cleanup_artifacts.py`。 + +2. **定义保留规则**: + * **对于预测结果 (`.json` in `saved_predictions/`)**: + * **基于时间**: 只保留最近30天的记录。 + * **基于数量**: 只保留最新的1000条记录。 + * **对于模型 (`.pth` in `saved_models/`)**: + * **基于版本**: 只保留每个模型(同一种药品、同一种算法)最新的3个版本。 + * **保留最佳模型**: 始终保留性能最佳的 `best` 版本,不参与自动清理。 + +3. **执行脚本**: + * 脚本的逻辑是:连接数据库,查询出所有符合清理条件的记录,然后安全地删除硬盘上对应的文件,最后再删除数据库中的条目。 + * 这个脚本可以通过服务器的定时任务(如Linux的Cron Job或Windows的Task Scheduler)设置为每日自动执行。 + +#### **企业级方案:归档到冷存储** + +对于需要长期保留数据以备审计的场景,更专业的做法是将旧文件归档至廉价的云对象存储(如阿里云OSS, AWS S3等),而不是直接删除。数据库中仅更新文件路径指向云端地址即可。 \ No newline at end of file From 0c321e218b53bd23f489f1be26dfdcde9374a4d0 Mon Sep 17 00:00:00 2001 From: LYFxiaoan Date: Fri, 25 Jul 2025 15:15:26 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=94=B9=E5=8A=A8?= =?UTF-8?q?=E5=88=B0=E6=96=87=E6=A1=A3=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lyf开发日志记录文档.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lyf开发日志记录文档.md b/lyf开发日志记录文档.md index 70d96fd..f79f15b 100644 --- a/lyf开发日志记录文档.md +++ b/lyf开发日志记录文档.md @@ -374,3 +374,24 @@ 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文件内容”的读取机制说明,以及关于如何管理和清理历史产物的“系统维护与扩展”章节。 +- **最终成果**: 产出了一份高质量、与当前代码完全同步的核心技术指南,显著提升了项目的可维护性和知识传承效率。