feat: complete production workflow migration

This commit is contained in:
2026-08-06 14:29:57 +08:00
parent 7f215e79c4
commit 8df5266abb
448 changed files with 56937 additions and 14619 deletions
@@ -0,0 +1,8 @@
# Launcher provenance only
These launchers preserve the arguments and sequencing discovered during the
read-only audit. Their project-root literals were replaced by the inert
`GYXX_RUNTIME_ROOT` placeholder during migration.
Do not register or invoke these files as production entry points. Final tasks
must call the native `gyxx-flow` CLI and its workflow registry.
@@ -0,0 +1,35 @@
@echo off
REM Daily 23:00 sales-decline alert -- independent of 08:40 daily collect.
REM
REM Detection window: previous 9 days from today, split into 3 segments
REM (strict decline: seg1 > seg2 > seg3 > 0).
REM Data source: data/<plat>/<safe_name>_<date>/data.json (PG first, JSON fallback).
REM Notify: POST Hermes analyzer chat completions, analyzer @ recipient by openid.
REM Recipient: ou_7ad5fc8012e2f741afc5346e05ffd447.
REM
REM Independence rationale:
REM - daily collect at 08:40 uses "yesterday" as window end (9d back: 5.31-6.8)
REM - this job at 23:00 uses "today" (9d back: 6.1-6.9) to see the latest trend
REM - even if daily collect fails, the alert still triggers
REM
REM Exit codes:
REM 0 = 0 events, or successful POST
REM 1 = detection logic failed
REM 3 = Hermes POST failed (events still persisted)
setlocal
cd /d %GYXX_RUNTIME_ROOT%
set "PY=%GYXX_RUNTIME_ROOT%\.venv\Scripts\python.exe"
if not exist data\logs mkdir data\logs
for /f %%i in ('powershell -NoProfile -Command "Get-Date -Format yyyy-MM-dd"') do set TODAY=%%i
echo [%TODAY% 23:00] === sales alert job start === >> data\logs\alerts.log
"%PY%" run_alerts_with_retry.py --end-date %TODAY% --openid ou_7ad5fc8012e2f741afc5346e05ffd447 >> data\logs\alerts.log 2>&1
set RC=%ERRORLEVEL%
echo [%TODAY% 23:00] === sales alert job end (rc=%RC%) === >> data\logs\alerts.log
exit /b %RC%
@@ -0,0 +1,17 @@
@echo off
REM Daily 08:40 trigger -- collect (ERP + 3 platforms) + analyze (date-first summary)
REM + export (data/ready_for_bitable/<date>/bitable_records.json)
REM + insert (推飞书多维表格)
REM Skips notify/decline (告警由 run_alerts.bat 23:00 跑; decline 暂未自动触发)
REM Uses project venv Python to ensure scrapling/playwright are available
REM 08:40 选在 JD/TM 当日数据已刷新、且赶在工作日开始前完成批跑
setlocal
cd /d %GYXX_RUNTIME_ROOT%
set "PY=%GYXX_RUNTIME_ROOT%\.venv\Scripts\python.exe"
if not exist data\logs mkdir data\logs
"%PY%" orchestrate_daily_collection.py --stages collect,analyze,export,insert >> data\logs\daily_collect.log 2>&1
exit /b %ERRORLEVEL%
@@ -0,0 +1,38 @@
@echo off
REM run_daily_import.bat
REM Triggered by Windows Task Scheduler daily at 19:00.
REM Imports previous day's data via import_product_daily.py.
REM Log goes to logs/daily_import_<timestamp>.log.
REM Note: file is ASCII-only on purpose - cmd's default codepage 936 (GBK)
REM misparses UTF-8 Chinese in REM/echo lines as commands.
setlocal EnableDelayedExpansion
set "PROJECT_DIR=%GYXX_RUNTIME_ROOT%"
set "PY=%PROJECT_DIR%\.venv\Scripts\python.exe"
set "SCRIPT=%PROJECT_DIR%\import_product_daily.py"
set "LOG_DIR=%PROJECT_DIR%\logs"
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
REM yesterday's date (cmd has no date math, use PowerShell with usebackq to avoid quote conflict)
for /f "usebackq" %%D in (`powershell -NoProfile -Command "(Get-Date).AddDays(-1).ToString('yyyy-MM-dd')"`) do set "YESTERDAY=%%D"
REM timestamp YYYYMMDD_HHMMSS
set "STAMP=%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%"
set "STAMP=%STAMP: =0%"
set "LOG_FILE=%LOG_DIR%\daily_import_%STAMP%.log"
REM banner (ASCII only)
echo [%date% %time:~0,8%] START daily import target_date=%YESTERDAY% log=%LOG_FILE%> "%LOG_FILE%"
cd /d "%PROJECT_DIR%"
"%PY%" "%SCRIPT%" --date %YESTERDAY% >> "%LOG_FILE%" 2>&1
set "EXIT_CODE=%ERRORLEVEL%"
echo [%date% %time:~0,8%] exit_code=%EXIT_CODE% >> "%LOG_FILE%"
REM keep 30 days of logs, delete older
forfiles /p "%LOG_DIR%" /m "daily_import_*.log" /d -30 /c "cmd /c del @file" 2>nul
endlocal & exit /b %EXIT_CODE%
@@ -0,0 +1,49 @@
# run_daily_import.ps1
# 每日 19:00 由 Windows Task Scheduler 触发。
# 计算昨天的日期, 调 import_product_daily.py 入库, 日志落到 logs/。
$ErrorActionPreference = "Continue"
$OutputEncoding = [System.Text.Encoding]::UTF8
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
$ProjectDir = $env:GYXX_RUNTIME_ROOT
$LogDir = Join-Path $ProjectDir "logs"
if (-not (Test-Path $LogDir)) {
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
}
$Stamp = Get-Date -Format "yyyyMMdd_HHmmss"
$Yesterday = (Get-Date).AddDays(-1).ToString("yyyy-MM-dd")
$LogFile = Join-Path $LogDir ("daily_import_" + $Stamp + ".log")
# 把 stdout/stderr 全部 >> 到日志 (用 cmd 重定向, 避免 PowerShell pipe 跟 Python 的编码冲突)
@"
[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] | =$Yesterday | =$LogFile
"@ | Out-File -FilePath $LogFile -Encoding utf8 -Append
Set-Location $ProjectDir
$Python = Join-Path $ProjectDir ".venv\Scripts\python.exe"
$Script = Join-Path $ProjectDir "import_product_daily.py"
if (-not (Test-Path $Python)) {
Add-Content -Path $LogFile -Value "[FATAL] 找不到 python: $Python" -Encoding utf8
exit 2
}
if (-not (Test-Path $Script)) {
Add-Content -Path $LogFile -Value "[FATAL] 找不到脚本: $Script" -Encoding utf8
exit 2
}
# 用 cmd 重定向 (2>&1 把 stderr 合并) - 兼容 Python 输出
cmd /c "`"$Python`" `"$Script`" --date $Yesterday >> `"$LogFile`" 2>&1"
$Exit = $LASTEXITCODE
Add-Content -Path $LogFile -Value "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] 退出码: $Exit" -Encoding utf8
# 保留 30 天日志, 删旧的
Get-ChildItem -Path $LogDir -Filter "daily_import_*.log" |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
ForEach-Object { Remove-Item $_.FullName -Force }
exit $Exit
@@ -0,0 +1,16 @@
@echo off
REM Daily 10:00 trigger -- 三平台人群画像并行采集 + 回填飞书表
REM 天猫: collect_persona_to_bitable.py (达摩盘)
REM 抖音: collect_dy_persona_to_bitable.py (罗盘成交人群)
REM 京东: collect_jd_persona_to_bitable.py (商智人群画像)
REM 三个脚本并行启动,各自独立写日志
setlocal
cd /d %GYXX_RUNTIME_ROOT%
set "PY=%GYXX_RUNTIME_ROOT%\.venv\Scripts\python.exe"
if not exist data\logs mkdir data\logs
"%PY%" run_daily_persona.py >> data\logs\daily_persona_launcher.log 2>&1
exit /b %ERRORLEVEL%
@@ -0,0 +1,13 @@
@echo off
REM Runs independently every 3 days at 11:00. The analyzer defaults to yesterday
REM as the window end, so each run covers the latest three complete calendar days.
setlocal
cd /d %GYXX_RUNTIME_ROOT%
set "PY=%GYXX_RUNTIME_ROOT%\.venv\Scripts\python.exe"
if not exist data\logs mkdir data\logs
"%PY%" -u analyze_style_with_hermes.py --all-styles --days 3 --min-interval-days 3 --skip-existing >> data\logs\style_analysis_3d.log 2>&1
exit /b %ERRORLEVEL%
@@ -0,0 +1,12 @@
@echo off
REM Weekly JD main image pipeline. Keep this file ASCII-only for Task Scheduler.
setlocal
cd /d %GYXX_RUNTIME_ROOT%
set "PY=%GYXX_RUNTIME_ROOT%\.venv\Scripts\python.exe"
set "PYTHONUNBUFFERED=1"
if not exist data\logs mkdir data\logs
"%PY%" -u run_weekly_jd_main_image.py --headless >> data\logs\weekly_jd_main_image.log 2>&1
exit /b %ERRORLEVEL%
@@ -0,0 +1,12 @@
@echo off
REM Weekly main image pipeline. Keep this file ASCII-only for Task Scheduler.
setlocal
cd /d %GYXX_RUNTIME_ROOT%
set "PY=%GYXX_RUNTIME_ROOT%\.venv\Scripts\python.exe"
set "PYTHONUNBUFFERED=1"
if not exist data\logs mkdir data\logs
"%PY%" -u run_weekly_main_image.py --headless >> data\logs\weekly_main_image.log 2>&1
exit /b %ERRORLEVEL%
@@ -0,0 +1,14 @@
@echo off
REM Weekly Monday 10:00 -- collect TM/JD/DY market ranks, create Feishu docs,
REM and archive each platform's latest document URL in PostgreSQL.
setlocal
cd /d %GYXX_RUNTIME_ROOT%
set "PY=%GYXX_RUNTIME_ROOT%\.venv\Scripts\python.exe"
set "PYTHONUNBUFFERED=1"
if not exist data\logs mkdir data\logs
"%PY%" orchestrate_market_rank_collection.py >> data\logs\market_rank_weekly.log 2>&1
exit /b %ERRORLEVEL%