Spaces:
Runtime error
Runtime error
Commit History
-
feat: upgrade Meta API to ad-level (素材级别) data pull
wen Qiu- Change level from "campaign" to "ad" to get per-creative metrics - Add ad_name, ad_id, adset_name, adset_id fields - Update dedup key to include ad_name - Support --level flag for flexible granularity Made-with: Cursor381a123
-
fix: 全局统一 ROAS 只用 Conversion 数据计算
wen Qiu涉及所有模块: - 昨日数据:总体/平台/层级/campaign 异动的 ROAS 都只用 Conversion - 数据看板:汇总 KPI / 产品线看板 / 数据矩阵的 ROAS 都只用 Conversion - 新增 _conv_filter / _conv_roas 辅助函数统一过滤逻辑 Made-with: Cursor7be5d72 -
fix: 移除 /api/monitor 中的自动同步,避免 Google API rate limit 导致数据加载失败
wen Qiu_quick_sync_stale_platforms 在 monitor 请求前执行会占用 Google Sheets API 配额,导致紧接着的 load_raw 被 rate limit 拒绝后 fallback 到本地 Excel(不存在), 报出"未找到 .xlsx 文件"错误。数据同步改为仅通过手动按钮触发。 Made-with: Cursor3fdab06 -
fix: 提高 Campaign 异动检测阈值,减少噪声告警
wen Qiu- cost_spike: 花费门槛 $50→$200,倍数 2x→2.5x - roas_drop: 花费门槛 $30→$100 - stopped: 7日均值门槛 $30→$100 Made-with: Cursorb187dcc -
feat: 数据看板重构 — 四维筛选 + 产品线看板 + 昨日数据
wen Qiu- 重命名"日常监控"为"数据看板",拆分为上下两区 - 上区:自定义日期范围 + 6维筛选器(国家/平台/广告目标/产品线/产品型号/项目类型) - 新增产品线/型号小看板,展示各 funnel 的 Cost/Sales/ROAS 及占比 - 下区:昨日数据固定 overview,含告警 + campaign 异动 + 层级花费树 - 后端新增 /api/dashboard 和 /api/dashboard/filters 接口 - 集成 campaign_parser.enrich_dataframe 为 monitor 数据提供解析维度 Made-with: Cursor6633362
-
feat: add /api/rebuild_sheets endpoint for one-time data refresh
wen QiuClears all platform sheet data rows (keeps header), then re-syncs all platforms with raw numeric format to eliminate precision loss. Made-with: Cursor473acec -
refactor: simplify data pipeline to single source (Sheets platform tabs only)
wen Qiu- Remove Export sheet and local CSV as data sources, only read Meta/Google/Criteo/Bing platform tabs from Google Sheets - Remove _merge_api_data and _platforms_loaded_from_sheets - Write raw numbers to Sheets instead of formatted strings ($, %) to eliminate precision loss in round-trip - Add country to write dedup key (country, date, campaign_name) - Fix _quick_sync_stale_platforms to write back to Sheets instead of only saving local CSV - Only apply ffill when data source is Excel (not API Sheets) - Add daily throttle to quick sync to avoid redundant API calls Made-with: Cursora2b76e3 -
fix: apply ffill before filtering Export rows by platform
wen QiuRoot cause: Export sheet uses hierarchical layout where platform name only appears on the first row of each group, with subsequent rows left blank. When checking which rows to exclude (because API platform sheets exist), blank platform cells were not matched against platform names like "Meta"/"Google", so those rows survived the filter. After later ffill in load_daily_data, they became duplicates of the API data. Fix: Apply ffill to the platform column *before* the exclusion check, so all rows belonging to a platform are correctly identified and removed when that platform has its own API sheet. Made-with: Cursorf194379 -
fix: prevent duplicate data when Export table and platform sheets overlap
wen QiuRoot cause: _load_from_google_sheets was reading both the Export sheet (which contains all platforms) AND individual platform sheets (Meta, Google, Criteo, Bing written by API sync), then concatenating them. This caused campaigns present in both sources to be double-counted, inflating Cost/Revenue figures (e.g. US Conversion showing $407K instead of the correct $307K). Fix: When a platform has its own API-synced sheet, exclude that platform's rows from the Export sheet before merging. The API sheet data takes priority as it's more current and accurately formatted. Made-with: Cursor48fbfa9 -
feat: add Campaign-level drill-down, anomaly alerts, and pacing curve
wen QiuPhase 1 - Campaign drill-down in daily monitor: - _build_hierarchy now builds 4 layers: Country > Platform > Funnel > Campaign Name (Top 10) - Each campaign shows Cost/Revenue/ROAS with vs-7d-avg changes - Frontend renders collapsible campaign rows under each funnel type Phase 2 - Campaign anomaly alerts: - _build_campaign_alerts detects 3 types: cost spike (>2x), ROAS drop (>50%), spending stopped - New "Campaign 异动" alert card in monitor tab with red/yellow severity Phase 3 - Budget pacing curve: - budget.py returns daily cumulative spend vs ideal pace line - ECharts area chart in budget tab shows actual vs planned spending trajectory Made-with: Cursorec533d1 -
refactor: align column names with updated Sheets headers
wen Qiu- "流量大类" → "funnel", "广告目标/广告目的" → "优化目标" - p3_config.py: update header-skip logic to recognize new names - Update comments/docstrings across campaign_parser, p3_metrics, p3_analyzer, p3_report, config.yaml Made-with: Cursor8d0d365 -
fix: compute ROAS using only Conversion funnel data in budget tracking
wen QiuROAS target corresponds to Conversion campaigns only. Previously the calculation included Awareness and Consideration spend/revenue which diluted the actual ROAS figure. Now filters to campaign_type=Conversion before computing ROAS and DM revenue achievement. Made-with: Cursor90719f1 -
fix: remove scopes from OAuth credentials to avoid invalid_scope error
wen QiuMade-with: Cursor1c3f337 -
feat: add GitHub Actions workflow for Meta data sync
wen QiuHF Spaces blocks graph.facebook.com, so Meta data is synced via GitHub Actions instead. Runs daily at 09:00 Beijing time. Also refactored Google auth in loader.py to support OAuth refresh token (via GOOGLE_OAUTH_* env vars) in addition to service account, enabling GitHub Actions to write to Sheets without a service account key file. Made-with: Cursor164fe15 -
fix: include detailed error message in Google Ads API failures
wen QiuMade-with: Cursora9f3229 -
fix: improve Meta API error message for DNS-restricted environments
wen QiuRemove ineffective IP fallback (SSL cert mismatch). Instead, give a clear error message when graph.facebook.com is unreachable, guiding users to update Meta data via Google Sheets in such environments. Made-with: Cursorefd1ec0 -
fix: add DNS fallback for Meta API in restricted network environments
wen QiuHF Spaces containers sometimes fail to resolve graph.facebook.com. Add automatic fallback to known Facebook IP addresses with proper Host header rewriting when DNS resolution fails. Made-with: Cursore745c2e -
fix: use independent gspread client in p3_config to avoid HTTPClient.open_by_key error
wen Qiugspread 6.x spreadsheet.client returns HTTPClient not gspread.Client, so open_by_key is not available. Create a standalone gspread client with the same credentials instead. Made-with: Cursorf3833f0 -
feat: add P3 投放分析引擎 (campaign analysis engine)
wen Qiu- Campaign Name 12-field parser with audience classification - Dynamic config loader from Google Sheets (budgets, KPI, benchmarks) - Per-objective metrics engine (Purchase/Lead/ATC/Linkclick/Pageview/PE) - L1-L4 hierarchical aggregation (market → funnel → platform → campaign) - Benchmark annotation (red/yellow/green) driven entirely by Sheets data - Diagnostic rules engine with actionable recommendations - Markdown weekly report formatter - API routes: GET /api/p3/analysis, GET /api/p3/config, POST /api/p3/push - 16 unit tests for campaign name parser - Fix Python 3.9 compatibility (from __future__ import annotations) - Fix percentage parsing bug (0.14% was incorrectly kept as 0.14) Made-with: Cursorebb46dc
-
refactor: consolidate repo structure, remove upload_to_github duplication
unknownMade-with: Cursor3291500