Update report UI and month-to-date metrics
This commit is contained in:
@@ -5,135 +5,7 @@ SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
TMP_FILE="$SCRIPT_DIR/data.json.tmp"
|
||||
OUTPUT_FILE="$SCRIPT_DIR/data.json"
|
||||
|
||||
python3 - "$TMP_FILE" <<'PY'
|
||||
import csv
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import urllib.request
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, timedelta
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
CSV_URL = (
|
||||
"https://docs.google.com/spreadsheets/d/"
|
||||
"1KaNOwaZ3DqjTXRK8XhF1OGF9qUmOh0NLXOgxVrh14h0/"
|
||||
"export?format=csv&gid=1445753035"
|
||||
)
|
||||
TIMEZONE = ZoneInfo("Asia/Shanghai")
|
||||
DAYS = 14
|
||||
BLOCKS = [
|
||||
{"country": "KZ", "date": 2, "geo": 3, "installs": 5, "spend": 8, "cac": 10},
|
||||
{"country": "UZ", "date": 14, "geo": 15, "installs": 17, "spend": 18, "cac": 20},
|
||||
{"country": "KG", "date": 25, "geo": 26, "installs": 28, "spend": 29, "cac": 31},
|
||||
{"country": "AM", "date": 35, "geo": 36, "installs": 38, "spend": 39, "cac": 41},
|
||||
]
|
||||
|
||||
|
||||
def parse_date(value):
|
||||
text = str(value or "").strip()
|
||||
for fmt in ("%Y/%m/%d", "%Y-%m-%d", "%Y%m%d", "%m/%d/%Y"):
|
||||
try:
|
||||
return datetime.strptime(text, fmt).date()
|
||||
except ValueError:
|
||||
pass
|
||||
match = re.fullmatch(r"(\d{4})[/.-](\d{1,2})[/.-](\d{1,2})", text)
|
||||
if not match:
|
||||
return None
|
||||
try:
|
||||
return datetime(*map(int, match.groups())).date()
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def parse_number(value):
|
||||
text = str(value or "").strip().replace("\xa0", "").replace(",", "")
|
||||
if not text or text in {"-", "—"}:
|
||||
return None
|
||||
negative = text.startswith("(") and text.endswith(")")
|
||||
cleaned = re.sub(r"[^0-9.\-]", "", text)
|
||||
try:
|
||||
number = float(cleaned)
|
||||
return -number if negative else number
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def cell(row, index):
|
||||
return row[index] if index < len(row) else ""
|
||||
|
||||
|
||||
request = urllib.request.Request(CSV_URL, headers={"User-Agent": "AgentStage-Ozon-Report/1.0"})
|
||||
with urllib.request.urlopen(request, timeout=90) as response:
|
||||
text = response.read().decode("utf-8-sig")
|
||||
rows = list(csv.reader(text.splitlines()))
|
||||
|
||||
now = datetime.now(TIMEZONE)
|
||||
end_date = now.date() - timedelta(days=1)
|
||||
start_date = end_date - timedelta(days=DAYS - 1)
|
||||
aggregated = defaultdict(lambda: {"installs": 0.0, "spend": 0.0, "cac_values": []})
|
||||
|
||||
for row in rows:
|
||||
for block in BLOCKS:
|
||||
day = parse_date(cell(row, block["date"]))
|
||||
if day is None or not (start_date <= day <= end_date):
|
||||
continue
|
||||
country = str(cell(row, block["geo"])).strip().upper() or block["country"]
|
||||
if country != block["country"]:
|
||||
continue
|
||||
key = (country, day.isoformat())
|
||||
installs = parse_number(cell(row, block["installs"]))
|
||||
spend = parse_number(cell(row, block["spend"]))
|
||||
cac = parse_number(cell(row, block["cac"]))
|
||||
aggregated[key]["installs"] += installs or 0
|
||||
aggregated[key]["spend"] += spend or 0
|
||||
if cac is not None:
|
||||
aggregated[key]["cac_values"].append(cac)
|
||||
|
||||
records = []
|
||||
for country in [item["country"] for item in BLOCKS]:
|
||||
for offset in range(DAYS):
|
||||
day = (start_date + timedelta(days=offset)).isoformat()
|
||||
values = aggregated.get((country, day), {"installs": 0, "spend": 0, "cac_values": []})
|
||||
cac_values = values["cac_values"]
|
||||
records.append({
|
||||
"date": day,
|
||||
"country": country,
|
||||
"installs": round(values["installs"], 2),
|
||||
"spend": round(values["spend"], 4),
|
||||
"cac": round(sum(cac_values) / len(cac_values), 4) if cac_values else None,
|
||||
})
|
||||
|
||||
summary = []
|
||||
for country in [item["country"] for item in BLOCKS]:
|
||||
country_rows = [row for row in records if row["country"] == country]
|
||||
cac_values = [row["cac"] for row in country_rows if row["cac"] is not None]
|
||||
summary.append({
|
||||
"country": country,
|
||||
"installs": round(sum(row["installs"] for row in country_rows), 2),
|
||||
"spend": round(sum(row["spend"] for row in country_rows), 4),
|
||||
"avg_cac": round(sum(cac_values) / len(cac_values), 4) if cac_values else None,
|
||||
"cac_days": len(cac_values),
|
||||
})
|
||||
|
||||
payload = {
|
||||
"title": "Ozon · 过去14天国家投放表现",
|
||||
"generated_at": now.isoformat(timespec="seconds"),
|
||||
"timezone": "Asia/Shanghai",
|
||||
"period": {"start": start_date.isoformat(), "end": end_date.isoformat(), "days": DAYS},
|
||||
"countries": [item["country"] for item in BLOCKS],
|
||||
"summary": summary,
|
||||
"records": records,
|
||||
"definitions": {
|
||||
"installs": "Google Sheet 各国家区块的 Install",
|
||||
"spend": "Google Sheet 各国家区块的 Daily Spend(USD)",
|
||||
"cac": "Google Sheet 各国家区块的 CAC from client report;汇总值为有数据日期的日均 CAC",
|
||||
},
|
||||
}
|
||||
|
||||
with open(sys.argv[1], "w", encoding="utf-8") as handle:
|
||||
json.dump(payload, handle, ensure_ascii=False, indent=2)
|
||||
PY
|
||||
python3 "$SCRIPT_DIR/update_report_data.py" "$TMP_FILE"
|
||||
|
||||
mv "$TMP_FILE" "$OUTPUT_FILE"
|
||||
echo "Updated $OUTPUT_FILE"
|
||||
|
||||
Reference in New Issue
Block a user