Spaces:
Runtime error
Runtime error
Download src/formatter.py from BinbomJared/DM-Agent: direct link, hf CLI and curl.
- Browser
- Download file 17.7 kB
-
https://huggingface.co/spaces/BinbomJared/DM-Agent/resolve/main/src/formatter.py
- Command line
-
hf download hf://spaces/BinbomJared/DM-Agent/src/formatter.py
-
curl -L -o formatter.py https://huggingface.co/spaces/BinbomJared/DM-Agent/resolve/main/src/formatter.py
17.7 kB
| """ | |
| 固定消息模板:钉钉 Markdown 周报。 | |
| 结构不变,数据填充,专家预警分级展示。 | |
| """ | |
| from typing import Any | |
| ALERT_ICON = { | |
| "red": "🔴", | |
| "yellow": "🟡", | |
| "green": "🟢", | |
| # 兼容旧格式 | |
| "critical": "🔴", | |
| "warning": "🟡", | |
| "positive": "🟢", | |
| } | |
| # ─── 数值格式化 ─── | |
| def _n(val: float | None, prefix: str = "", suffix: str = "", d: int = 2) -> str: | |
| if val is None or val != val: | |
| return "—" | |
| if abs(val) >= 1_000_000: | |
| return f"{prefix}{val / 1_000_000:,.{d}f}M{suffix}" | |
| if abs(val) >= 1_000: | |
| return f"{prefix}{val / 1_000:,.{d}f}K{suffix}" | |
| return f"{prefix}{val:,.{d}f}{suffix}" | |
| def _pct(val: float | None) -> str: | |
| if val is None or val != val: | |
| return "—" | |
| return f"{val * 100:.2f}%" if abs(val) < 1 else f"{val:.2f}%" | |
| def _arrow(change: float | None) -> str: | |
| """根据变化幅度返回方向箭头。""" | |
| if change is None or change != change: | |
| return "" | |
| if change >= 10: | |
| return "↑↑" | |
| if change > 0: | |
| return "↑" | |
| if change <= -10: | |
| return "↓↓" | |
| if change < 0: | |
| return "↓" | |
| return "→" | |
| def _deltas_zh(wow_val: float | None, yoy_val: float | None) -> str: | |
| """环比/同比(中文标签),适合钉钉 Markdown;大幅波动加粗。""" | |
| parts: list[str] = [] | |
| if wow_val is not None and wow_val == wow_val: | |
| sign = "+" if wow_val >= 0 else "" | |
| ar = _arrow(wow_val) | |
| s = f"环比 {ar}{sign}{wow_val:.1f}%" | |
| if abs(wow_val) >= 10: | |
| s = f"**{s}**" | |
| parts.append(s) | |
| if yoy_val is not None and yoy_val == yoy_val: | |
| sign = "+" if yoy_val >= 0 else "" | |
| ar = _arrow(yoy_val) | |
| s = f"同比 {ar}{sign}{yoy_val:.1f}%" | |
| if abs(yoy_val) >= 10: | |
| s = f"**{s}**" | |
| parts.append(s) | |
| if not parts: | |
| return "" | |
| return " | " + " | ".join(parts) | |
| def _append_funnel_dim_lines(L: list[str], m: dict[str, Any], cw: dict, cy: dict) -> None: | |
| """漏斗维度:每指标一行,钉钉端更易扫读。""" | |
| L.append(f"- **花费** {_n(m.get('Cost'), prefix='$')}{_deltas_zh(cw.get('Cost'), cy.get('Cost'))}") | |
| L.append(f"- **销售额** {_n(m.get('Ads.Sales'), prefix='$')}{_deltas_zh(cw.get('Ads.Sales'), cy.get('Ads.Sales'))}") | |
| L.append(f"- **ROAS** {m.get('ROAS', 0):.2f}{_deltas_zh(cw.get('ROAS'), cy.get('ROAS'))}") | |
| L.append(f"- **展示量** {_n(m.get('Impressions'), d=0)}{_deltas_zh(cw.get('Impressions'), cy.get('Impressions'))}") | |
| L.append(f"- **CTR** {_pct(m.get('CTR'))}{_deltas_zh(cw.get('CTR'), cy.get('CTR'))}") | |
| L.append(f"- **CPC** {_n(m.get('CPC'), prefix='$')}{_deltas_zh(cw.get('CPC'), cy.get('CPC'))}") | |
| if m.get("ATC"): | |
| L.append(f"- **加购 ATC** {_n(m.get('ATC'), d=0)}{_deltas_zh(cw.get('ATC'), cy.get('ATC'))}") | |
| if m.get("GA4.Sessions"): | |
| L.append(f"- **会话** {_n(m.get('GA4.Sessions'), d=0)}{_deltas_zh(cw.get('GA4.Sessions'), cy.get('GA4.Sessions'))}") | |
| def _append_country_dim_lines(L: list[str], m: dict[str, Any], cw: dict, cy: dict, *, full: bool) -> None: | |
| """市场维度:full=True 与周报一致;False 仅花费+ROAS(日报/简版)。""" | |
| L.append(f"- **花费** {_n(m.get('Cost'), prefix='$')}{_deltas_zh(cw.get('Cost'), cy.get('Cost'))}") | |
| if full: | |
| L.append(f"- **销售额** {_n(m.get('Ads.Sales'), prefix='$')}{_deltas_zh(cw.get('Ads.Sales'), cy.get('Ads.Sales'))}") | |
| L.append(f"- **ROAS** {m.get('ROAS', 0):.2f}{_deltas_zh(cw.get('ROAS'), cy.get('ROAS'))}") | |
| if full: | |
| L.append(f"- **会话** {_n(m.get('GA4.Sessions'), d=0)}{_deltas_zh(cw.get('GA4.Sessions'), cy.get('GA4.Sessions'))}") | |
| L.append(f"- **加购** {_n(m.get('ATC'), d=0)}{_deltas_zh(cw.get('ATC'), cy.get('ATC'))}") | |
| L.append(f"- **转化率** {_pct(m.get('CVR'))}{_deltas_zh(cw.get('CVR'), cy.get('CVR'))}") | |
| # ─── 固定模板 ─── | |
| def format_report(data: dict[str, Any]) -> str: | |
| cp = data.get("current_period", {}) | |
| pp = data.get("previous_period") | |
| year, week = cp.get("year"), cp.get("week") | |
| L: list[str] = [] | |
| L.append(f"## DM 周报 · {year} W{week}") | |
| cmp_bits: list[str] = [] | |
| if pp: | |
| cmp_bits.append(f"环比:{pp['year']} 年第 {pp['week']} 周") | |
| if data.get("yoy_period"): | |
| yp = data["yoy_period"] | |
| cmp_bits.append(f"同比:{yp['year']} 年第 {yp['week']} 周") | |
| if cmp_bits: | |
| L.append("> " + " | ".join(cmp_bits)) | |
| L.append("") | |
| curr = data.get("current", {}) | |
| wow_t = data.get("wow_total") or {} | |
| yoy_t = data.get("yoy_total") or {} | |
| total = curr.get("total", {}) | |
| L.append("### 一、整体表现") | |
| L.append("") | |
| _block_metrics(L, total, wow_t, yoy_t if yoy_t else None) | |
| L.append("") | |
| by_plat = curr.get("by_platform", {}) | |
| wow_plat = data.get("wow_by_platform") or {} | |
| yoy_plat = data.get("yoy_by_platform") or {} | |
| L.append("### 二、平台对比") | |
| L.append("") | |
| for plat in ["Google", "Meta"]: | |
| m = by_plat.get(plat) | |
| if not m: | |
| continue | |
| pw = wow_plat.get(plat, {}) | |
| py = yoy_plat.get(plat, {}) | |
| L.append(f"**{plat}**") | |
| _block_metrics(L, m, pw, py if py else None) | |
| L.append("") | |
| by_ct = curr.get("by_campaign_type", {}) | |
| wow_ct = data.get("wow_by_campaign") or {} | |
| yoy_ct = data.get("yoy_by_campaign") or {} | |
| L.append("### 三、广告漏斗") | |
| L.append("") | |
| for ct in ["Awareness", "Consideration", "Conversion"]: | |
| m = by_ct.get(ct) | |
| if not m: | |
| continue | |
| cw = wow_ct.get(ct, {}) | |
| cy = yoy_ct.get(ct, {}) | |
| L.append(f"**{ct}**") | |
| _append_funnel_dim_lines(L, m, cw, cy) | |
| L.append("") | |
| by_country = curr.get("by_country", {}) | |
| wow_country = data.get("wow_by_country") or {} | |
| yoy_country = data.get("yoy_by_country") or {} | |
| L.append("### 四、市场表现") | |
| L.append("") | |
| for c in sorted(by_country.keys()): | |
| m = by_country[c] | |
| cw = wow_country.get(c, {}) | |
| cy = yoy_country.get(c, {}) | |
| L.append(f"**{c}**") | |
| _append_country_dim_lines(L, m, cw, cy, full=True) | |
| L.append("") | |
| _append_expert_section(L, data.get("expert", {})) | |
| return "\n".join(L).strip() | |
| def _append_expert_section(L: list[str], expert: dict[str, Any]) -> None: | |
| """将专家分析追加到报告末尾。兼容新格式(verdict)和旧格式(summary)。""" | |
| if not expert: | |
| return | |
| L.append("### 陈策点评") | |
| L.append("") | |
| verdict = expert.get("verdict") or expert.get("summary", "") | |
| if verdict: | |
| L.append(f"> 💡 {verdict}") | |
| L.append("") | |
| findings = expert.get("key_findings") or [] | |
| if not findings: | |
| for key in ["efficiency", "platform", "funnel", "market"]: | |
| findings.extend(expert.get(key, [])) | |
| if findings: | |
| for i, f in enumerate(findings, 1): | |
| L.append(f"**{i}.** {f}") | |
| L.append("") | |
| alerts = expert.get("alerts", []) | |
| if alerts: | |
| for a in alerts: | |
| level = a.get("level", "yellow") | |
| icon = ALERT_ICON.get(level, "🟡") | |
| msg = a.get("msg") or f"{a.get('title', '')}:{a.get('detail', '')}" | |
| L.append(f"{icon} **{msg}**" if level == "red" else f"{icon} {msg}") | |
| L.append("") | |
| action = expert.get("next_action", "") | |
| if not action: | |
| recs = expert.get("recommendations", []) | |
| if recs: | |
| action = recs[0] | |
| if action: | |
| L.append(f"> 👉 **下一步:{action}**") | |
| L.append("") | |
| def _flag(wow_val: float | None, yoy_val: float | None) -> str: | |
| """大幅异动时加前缀标记,让读者快速定位重点。""" | |
| for v in [wow_val, yoy_val]: | |
| if v is not None and v == v: | |
| if v <= -20: | |
| return "⚠️ " | |
| if v >= 20: | |
| return "🔥 " | |
| return "" | |
| def _block_metrics( | |
| L: list[str], | |
| m: dict[str, float], | |
| wow: dict[str, float | None], | |
| yoy: dict[str, float | None] | None = None, | |
| ) -> None: | |
| """每个核心指标独立一行,大幅异动自动标记。""" | |
| y = yoy or {} | |
| rows = [ | |
| ("花费", _n(m.get("Cost", 0), prefix="$"), wow.get("Cost"), y.get("Cost")), | |
| ("销售额", _n(m.get("Ads.Sales", 0), prefix="$"), wow.get("Ads.Sales"), y.get("Ads.Sales")), | |
| ("ROAS", f"{m.get('ROAS', 0):.2f}", wow.get("ROAS"), y.get("ROAS")), | |
| ("展示量", _n(m.get("Impressions", 0), d=0), wow.get("Impressions"), y.get("Impressions")), | |
| ("CTR", _pct(m.get("CTR", 0)), wow.get("CTR"), y.get("CTR")), | |
| ("转化率", _pct(m.get("CVR", 0)), wow.get("CVR"), y.get("CVR")), | |
| ("CPC", _n(m.get("CPC", 0), prefix="$"), wow.get("CPC"), y.get("CPC")), | |
| ("会话", _n(m.get("GA4.Sessions", 0), d=0), wow.get("GA4.Sessions"), y.get("GA4.Sessions")), | |
| ] | |
| if m.get("ATC", 0): | |
| rows.append(("加购 ATC", _n(m["ATC"], d=0), wow.get("ATC"), y.get("ATC"))) | |
| for name, val, w, yr in rows: | |
| prefix = _flag(w, yr) | |
| L.append(f"- {prefix}**{name}** {val}{_deltas_zh(w, yr)}") | |
| def format_title(data: dict[str, Any]) -> str: | |
| cp = data.get("current_period", {}) | |
| return f"DM Weekly Report {cp.get('year')} W{cp.get('week')}" | |
| # ───────────────────────────────────────────── | |
| # 月度报告模板(与周报结构一致) | |
| # ───────────────────────────────────────────── | |
| def format_monthly_report(data: dict[str, Any]) -> str: | |
| """月度汇总报告,与周报结构一致,含环比+同比。""" | |
| period = data.get("period_label", "") | |
| prev = data.get("prev_label") | |
| yoy_label = data.get("yoy_label") | |
| error = data.get("error") | |
| L: list[str] = [] | |
| L.append(f"## DM 月报 · {period}") | |
| cmp_parts = [] | |
| if prev: | |
| cmp_parts.append(f"环比:{prev}") | |
| if yoy_label: | |
| cmp_parts.append(f"同比:{yoy_label}") | |
| if cmp_parts: | |
| L.append("> " + " | ".join(cmp_parts)) | |
| L.append("") | |
| if error: | |
| L.append(f"> {error}") | |
| return "\n".join(L).strip() | |
| curr = data.get("current", {}) | |
| wow_t = data.get("wow_total") or {} | |
| yoy_t = data.get("yoy_total") or {} | |
| total = curr.get("total", {}) | |
| L.append("### 一、整体表现") | |
| L.append("") | |
| _block_metrics(L, total, wow_t, yoy_t if yoy_t else None) | |
| L.append("") | |
| by_plat = curr.get("by_platform", {}) | |
| wow_plat = data.get("wow_by_platform") or {} | |
| yoy_plat = data.get("yoy_by_platform") or {} | |
| L.append("### 二、平台对比") | |
| L.append("") | |
| for plat in ["Google", "Meta"]: | |
| m = by_plat.get(plat) | |
| if not m: | |
| continue | |
| pw = wow_plat.get(plat, {}) | |
| py = yoy_plat.get(plat, {}) | |
| L.append(f"**{plat}**") | |
| _block_metrics(L, m, pw, py if py else None) | |
| L.append("") | |
| by_ct = curr.get("by_campaign_type", {}) | |
| wow_ct = data.get("wow_by_campaign") or {} | |
| yoy_ct = data.get("yoy_by_campaign") or {} | |
| L.append("### 三、广告漏斗") | |
| L.append("") | |
| for ct in ["Awareness", "Consideration", "Conversion"]: | |
| m = by_ct.get(ct) | |
| if not m: | |
| continue | |
| cw = wow_ct.get(ct, {}) | |
| cy = yoy_ct.get(ct, {}) | |
| L.append(f"**{ct}**") | |
| _append_funnel_dim_lines(L, m, cw, cy) | |
| L.append("") | |
| by_country = curr.get("by_country", {}) | |
| wow_country = data.get("wow_by_country") or {} | |
| yoy_country = data.get("yoy_by_country") or {} | |
| L.append("### 四、市场表现") | |
| L.append("") | |
| for c in sorted(by_country.keys()): | |
| m = by_country[c] | |
| cw = wow_country.get(c, {}) | |
| cy = yoy_country.get(c, {}) | |
| L.append(f"**{c}**") | |
| _append_country_dim_lines(L, m, cw, cy, full=True) | |
| L.append("") | |
| _append_expert_section(L, data.get("expert", {})) | |
| return "\n".join(L).strip() | |
| def format_monthly_title(data: dict[str, Any]) -> str: | |
| return f"DM Monthly Report {data.get('period_label', '')}" | |
| # ───────────────────────────────────────────── | |
| # 日报模板(复用月报结构) | |
| # ───────────────────────────────────────────── | |
| def format_daily_report(data: dict[str, Any]) -> str: | |
| """日度报告,结构与月报一致,标签改为 DoD/YoY。""" | |
| period = data.get("period_label", "") | |
| prev = data.get("prev_label") | |
| yoy_label = data.get("yoy_label") | |
| error = data.get("error") | |
| L: list[str] = [] | |
| L.append(f"## DM 日报 · {period}") | |
| cmp_parts = [] | |
| if prev: | |
| cmp_parts.append(f"环比:{prev}") | |
| if yoy_label: | |
| cmp_parts.append(f"同比:{yoy_label}") | |
| if cmp_parts: | |
| L.append("> " + " | ".join(cmp_parts)) | |
| L.append("") | |
| if error: | |
| L.append(f"> {error}") | |
| return "\n".join(L).strip() | |
| curr = data.get("current", {}) | |
| wow_t = data.get("wow_total") or {} | |
| yoy_t = data.get("yoy_total") or {} | |
| total = curr.get("total", {}) | |
| L.append("### 整体表现") | |
| L.append("") | |
| _block_metrics(L, total, wow_t, yoy_t if yoy_t else None) | |
| L.append("") | |
| by_plat = curr.get("by_platform", {}) | |
| wow_plat = data.get("wow_by_platform") or {} | |
| yoy_plat = data.get("yoy_by_platform") or {} | |
| L.append("### 平台对比") | |
| L.append("") | |
| for plat in ["Google", "Meta"]: | |
| m = by_plat.get(plat) | |
| if not m: | |
| continue | |
| pw = wow_plat.get(plat, {}) | |
| py = yoy_plat.get(plat, {}) | |
| L.append(f"**{plat}**") | |
| _block_metrics(L, m, pw, py if py else None) | |
| L.append("") | |
| by_country = curr.get("by_country", {}) | |
| wow_country = data.get("wow_by_country") or {} | |
| yoy_country = data.get("yoy_by_country") or {} | |
| if by_country: | |
| L.append("### 市场表现") | |
| L.append("") | |
| for c in sorted(by_country.keys()): | |
| m = by_country[c] | |
| cw = wow_country.get(c, {}) | |
| cy = yoy_country.get(c, {}) | |
| L.append(f"**{c}**") | |
| _append_country_dim_lines(L, m, cw, cy, full=False) | |
| L.append("") | |
| _append_expert_section(L, data.get("expert", {})) | |
| return "\n".join(L).strip() | |
| def format_daily_title(data: dict[str, Any]) -> str: | |
| return f"DM Daily Report {data.get('period_label', '')}" | |
| # ───────────────────────────────────────────── | |
| # 自定义时间段报告 | |
| # ───────────────────────────────────────────── | |
| def format_range_report(data: dict[str, Any]) -> str: | |
| """自定义时间段报告,结构与月报一致。""" | |
| period = data.get("period_label", "") | |
| prev = data.get("prev_label") | |
| yoy_label = data.get("yoy_label") | |
| days = data.get("days_count", "") | |
| error = data.get("error") | |
| L: list[str] = [] | |
| L.append(f"## DM 自定义报告 · {period}") | |
| sub_parts = [] | |
| if days: | |
| sub_parts.append(f"统计 {days} 天") | |
| if prev: | |
| sub_parts.append(f"环比:{prev}") | |
| if yoy_label: | |
| sub_parts.append(f"同比:{yoy_label}") | |
| if sub_parts: | |
| L.append("> " + " | ".join(sub_parts)) | |
| L.append("") | |
| if error: | |
| L.append(f"> {error}") | |
| return "\n".join(L).strip() | |
| curr = data.get("current", {}) | |
| wow_t = data.get("wow_total") or {} | |
| yoy_t = data.get("yoy_total") or {} | |
| total = curr.get("total", {}) | |
| L.append("### 整体表现") | |
| L.append("") | |
| _block_metrics(L, total, wow_t, yoy_t if yoy_t else None) | |
| L.append("") | |
| by_plat = curr.get("by_platform", {}) | |
| wow_plat = data.get("wow_by_platform") or {} | |
| yoy_plat = data.get("yoy_by_platform") or {} | |
| L.append("### 平台对比") | |
| L.append("") | |
| for plat in ["Google", "Meta"]: | |
| m = by_plat.get(plat) | |
| if not m: | |
| continue | |
| pw = wow_plat.get(plat, {}) | |
| py = yoy_plat.get(plat, {}) | |
| L.append(f"**{plat}**") | |
| _block_metrics(L, m, pw, py if py else None) | |
| L.append("") | |
| by_ct = curr.get("by_campaign_type", {}) | |
| wow_ct = data.get("wow_by_campaign") or {} | |
| yoy_ct = data.get("yoy_by_campaign") or {} | |
| if by_ct: | |
| L.append("### 广告漏斗") | |
| L.append("") | |
| for ct in ["Awareness", "Consideration", "Conversion"]: | |
| m = by_ct.get(ct) | |
| if not m: | |
| continue | |
| cw = wow_ct.get(ct, {}) | |
| cy = yoy_ct.get(ct, {}) | |
| L.append(f"**{ct}**") | |
| _append_funnel_dim_lines(L, m, cw, cy) | |
| L.append("") | |
| by_country = curr.get("by_country", {}) | |
| wow_country = data.get("wow_by_country") or {} | |
| yoy_country = data.get("yoy_by_country") or {} | |
| if by_country: | |
| L.append("### 市场表现") | |
| L.append("") | |
| for c in sorted(by_country.keys()): | |
| m = by_country[c] | |
| cw = wow_country.get(c, {}) | |
| cy = yoy_country.get(c, {}) | |
| L.append(f"**{c}**") | |
| _append_country_dim_lines(L, m, cw, cy, full=False) | |
| L.append("") | |
| _append_expert_section(L, data.get("expert", {})) | |
| return "\n".join(L).strip() | |
| def format_range_title(data: dict[str, Any]) -> str: | |
| return f"DM Custom Report {data.get('period_label', '')}" | |