mirror of
https://github.com/ZhuLinsen/daily_stock_analysis
synced 2026-09-20 10:53:33 +08:00
fix: bundle AkShare calendar data in desktop builds (#1990)
This commit is contained in:
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
- [修复] 市场结构概念排行为空或超时时复用本轮负结果,避免批量个股分析重复请求同一概念排行数据源。
|
||||
- [修复] Windows/macOS 桌面后端打包显式收集并校验 AkShare `file_fold/calendar.json`,避免发行包因缺少交易日历 package data 导致热点题材和选股日线增强降级。
|
||||
- [改进] 为 multi-agent DecisionAgent 增加内部低敏分歧摘要输入管线,作为 #1904 P1 解释输出的前置 plumbing;不改变 public API、dashboard schema 或最终解释字段。
|
||||
- [修复] 推送报告、Jinja 报告与历史 Markdown 导出复用 Web/API 的评分-action 口径:高分但旧 `operation_advice` 仍为持有且无降级原因时,建议文案与三类统计展示为买入;有明确 guardrail reason 时继续保留持有/观望。
|
||||
- [改进] GitHub Actions 每日分析工作流补齐 TickFlow 数据源环境变量映射,并收敛 README 数据源稳定性说明到完整指南。
|
||||
|
||||
@@ -190,7 +190,7 @@ npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
2) 按现有脚本打包 Python 后端(脚本已内置 AlphaSift 依赖收集)
|
||||
2) 按现有脚本打包 Python 后端(脚本已内置 AlphaSift 与 AkShare 数据文件收集)
|
||||
|
||||
- Windows:
|
||||
|
||||
@@ -204,7 +204,7 @@ powershell -ExecutionPolicy Bypass -File scripts\build-backend.ps1
|
||||
bash scripts/build-backend-macos.sh
|
||||
```
|
||||
|
||||
该脚本会在安装依赖后执行 `--collect-all alphasift`,并校验打包产物中可导入 `alphasift.dsa_adapter`,避免分步命令遗漏内置 AlphaSift 模块。
|
||||
该脚本会在安装依赖后执行 `--collect-all alphasift` 和 `--collect-data akshare`。构建完成后会校验 `alphasift.dsa_adapter` 可导入,并确认 AkShare 的 `file_fold/calendar.json` 已进入冻结产物,避免发行包在热点题材或日线增强路径中因缺少 package data 降级。
|
||||
|
||||
3) 打包 Electron 桌面应用
|
||||
|
||||
@@ -297,6 +297,8 @@ win-unpacked/
|
||||
|
||||
PyInstaller 打包时缺少模块,需要在 `scripts/build-backend.ps1` 中增加 `--hidden-import`。
|
||||
|
||||
如果日志提示缺少 `akshare/file_fold/calendar.json`,说明后端冻结产物没有完整收集 AkShare package data。请使用仓库当前的 `scripts/build-backend.ps1` 或 `scripts/build-backend-macos.sh` 重新构建;脚本会在生成桌面包前检查该文件,缺失时直接终止构建。
|
||||
|
||||
### UI 加载空白
|
||||
|
||||
确认 `static/index.html` 存在,如不存在需重新构建 React UI。
|
||||
|
||||
@@ -110,7 +110,7 @@ for module in "${hidden_imports[@]}"; do
|
||||
done
|
||||
|
||||
pushd "${ROOT_DIR}" >/dev/null
|
||||
cmd=("${PYTHON_BIN}" -m PyInstaller --name stock_analysis --onedir --noconfirm --noconsole --add-data "static:static" --add-data "strategies:strategies" --collect-data litellm --collect-data tiktoken)
|
||||
cmd=("${PYTHON_BIN}" -m PyInstaller --name stock_analysis --onedir --noconfirm --noconsole --add-data "static:static" --add-data "strategies:strategies" --collect-data litellm --collect-data tiktoken --collect-data akshare)
|
||||
cmd+=("--collect-all" "alphasift")
|
||||
cmd+=("${hidden_import_args[@]}" "main.py")
|
||||
|
||||
@@ -144,6 +144,16 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Verifying packaged AkShare calendar data..."
|
||||
packaged_akshare_calendar="${packaged_root}/_internal/akshare/file_fold/calendar.json"
|
||||
if [[ ! -f "${packaged_akshare_calendar}" ]]; then
|
||||
packaged_akshare_calendar="${packaged_root}/akshare/file_fold/calendar.json"
|
||||
fi
|
||||
if [[ ! -f "${packaged_akshare_calendar}" ]]; then
|
||||
echo "ERROR: packaged AkShare calendar data not found under ${packaged_root}."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Verifying static asset references (packaged)..."
|
||||
packaged_static="${ROOT_DIR}/dist/backend/stock_analysis/_internal/static"
|
||||
if [[ ! -d "${packaged_static}" ]]; then
|
||||
|
||||
@@ -124,6 +124,7 @@ $pyInstallerArgs = @(
|
||||
'--add-data', 'strategies;strategies',
|
||||
'--collect-data', 'litellm',
|
||||
'--collect-data', 'tiktoken',
|
||||
'--collect-data', 'akshare',
|
||||
'--collect-all', 'alphasift'
|
||||
)
|
||||
$pyInstallerArgs += $hiddenImportArgs
|
||||
@@ -161,6 +162,15 @@ try {
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host 'Verifying packaged AkShare calendar data...'
|
||||
$packagedAkshareCalendar = Join-Path 'dist\backend\stock_analysis' '_internal\akshare\file_fold\calendar.json'
|
||||
if (-not (Test-Path $packagedAkshareCalendar)) {
|
||||
$packagedAkshareCalendar = Join-Path 'dist\backend\stock_analysis' 'akshare\file_fold\calendar.json'
|
||||
}
|
||||
if (-not (Test-Path $packagedAkshareCalendar)) {
|
||||
throw 'Packaged AkShare calendar data not found under dist\backend\stock_analysis.'
|
||||
}
|
||||
|
||||
Write-Host 'Verifying static asset references (packaged)...'
|
||||
$packagedStatic = Join-Path 'dist\backend\stock_analysis' '_internal\static'
|
||||
if (-not (Test-Path $packagedStatic)) {
|
||||
|
||||
30
tests/test_desktop_packaging_assets.py
Normal file
30
tests/test_desktop_packaging_assets.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Static contracts for third-party data bundled in desktop backends."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class DesktopPackagingAssetsTestCase(unittest.TestCase):
|
||||
"""Keep Windows and macOS PyInstaller package-data rules aligned."""
|
||||
|
||||
repo_root = Path(__file__).resolve().parent.parent
|
||||
|
||||
def test_scripts_collect_and_verify_akshare_calendar_data(self) -> None:
|
||||
macos_script = (self.repo_root / "scripts" / "build-backend-macos.sh").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
windows_script = (self.repo_root / "scripts" / "build-backend.ps1").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
|
||||
self.assertIn("--collect-data akshare", macos_script)
|
||||
self.assertIn("'--collect-data', 'akshare'", windows_script)
|
||||
self.assertIn("_internal/akshare/file_fold/calendar.json", macos_script)
|
||||
self.assertIn("_internal\\akshare\\file_fold\\calendar.json", windows_script)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user