Corin1998 commited on
Commit
eca36cb
·
verified ·
1 Parent(s): bed5e0d

Update dashboard.py

Browse files
Files changed (1) hide show
  1. dashboard.py +76 -5
dashboard.py CHANGED
@@ -1,21 +1,78 @@
1
  from __future__ import annotations
2
  import gradio as gr
3
  import plotly.express as px
4
- from data import read_events, aggregate
 
5
  from bandit import EmpiricalBayesHierarchicalThompson
6
  from causal import fit_uplift_binary
7
 
8
  BANDIT = EmpiricalBayesHierarchicalThompson(min_explore=0.05, margin=0.0, n_draws=10000)
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  def ui_refresh_tables():
11
  df = read_events()
12
  agg = aggregate()
13
- return df, agg
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
 
15
  def ui_recommend():
16
  agg = aggregate()
17
  if agg.empty:
18
- return {"message": "No data yet. POST /api/ingest first."}
19
  return BANDIT.recommend(agg)
20
 
21
  def ui_plot_posteriors(medium: str):
@@ -36,14 +93,26 @@ def ui_fit_uplift():
36
  return {"message": "No data"}
37
  return fit_uplift_binary(agg)
38
 
 
39
  def build_ui():
40
  with gr.Blocks(title="AdCopy MAB Optimizer Pro") as demo:
41
  gr.Markdown("# AdCopy MAB Optimizer Pro — Hierarchical TS + Uplift")
 
42
  with gr.Tab("Data"):
43
- btn = gr.Button("Refresh")
 
 
 
 
 
 
44
  grid = gr.Dataframe(headers=["ts","date","medium","creative","is_control","impressions","clicks","conversions","cost","features_json"], wrap=True)
45
  grid_agg = gr.Dataframe()
46
- btn.click(ui_refresh_tables, outputs=[grid, grid_agg])
 
 
 
 
47
  with gr.Tab("Bandit"):
48
  bbtn = gr.Button("Suggest Allocation (TS)")
49
  jout = gr.JSON()
@@ -53,8 +122,10 @@ def build_ui():
53
  plot = gr.Plot(visible=False)
54
  msg = gr.Markdown()
55
  gr.Button("Plot CTR by Creative").click(ui_plot_posteriors, inputs=[medium], outputs=[plot, msg])
 
56
  with gr.Tab("Uplift (Causal)"):
57
  cbtn = gr.Button("Fit Uplift Model")
58
  cout = gr.JSON()
59
  cbtn.click(ui_fit_uplift, outputs=cout)
 
60
  return demo
 
1
  from __future__ import annotations
2
  import gradio as gr
3
  import plotly.express as px
4
+ import pandas as pd
5
+ from data import read_events, aggregate, append_events
6
  from bandit import EmpiricalBayesHierarchicalThompson
7
  from causal import fit_uplift_binary
8
 
9
  BANDIT = EmpiricalBayesHierarchicalThompson(min_explore=0.05, margin=0.0, n_draws=10000)
10
 
11
+ REQUIRED_COLS = [
12
+ "date","medium","creative","is_control",
13
+ "impressions","clicks","conversions","cost","features_json"
14
+ ]
15
+
16
+ # ---- helpers ----
17
+ def _ok(msg: str):
18
+ return gr.Markdown.update(value=f"✅ {msg}")
19
+ def _warn(msg: str):
20
+ return gr.Markdown.update(value=f"⚠️ {msg}")
21
+ def _err(msg: str):
22
+ return gr.Markdown.update(value=f"❌ {msg}")
23
+
24
+ # ---- data ops ----
25
  def ui_refresh_tables():
26
  df = read_events()
27
  agg = aggregate()
28
+ return df, agg, _ok("Refreshed.")
29
+
30
+ def ui_load_sample():
31
+ rows = [
32
+ {"date":"2025-09-01","medium":"FB","creative":"A1","is_control":1,"impressions":1000,"clicks":25,"conversions":3,"cost":480,"features_json":"{}"},
33
+ {"date":"2025-09-01","medium":"FB","creative":"B1","is_control":0,"impressions":850,"clicks":24,"conversions":2,"cost":395,"features_json":"{}"},
34
+ {"date":"2025-09-01","medium":"FB","creative":"C1","is_control":0,"impressions":900,"clicks":21,"conversions":2,"cost":420,"features_json":"{}"},
35
+ {"date":"2025-09-01","medium":"FB","creative":"D1","is_control":0,"impressions":820,"clicks":20,"conversions":2,"cost":380,"features_json":"{}"},
36
+ {"date":"2025-09-01","medium":"FB","creative":"E1","is_control":0,"impressions":960,"clicks":31,"conversions":3,"cost":490,"features_json":"{}"},
37
+ {"date":"2025-09-01","medium":"GDN","creative":"A2","is_control":1,"impressions":1100,"clicks":25,"conversions":2,"cost":545,"features_json":"{}"},
38
+ {"date":"2025-09-01","medium":"GDN","creative":"B2","is_control":0,"impressions":990,"clicks":27,"conversions":3,"cost":514,"features_json":"{}"},
39
+ {"date":"2025-09-01","medium":"GDN","creative":"C2","is_control":0,"impressions":860,"clicks":19,"conversions":2,"cost":450,"features_json":"{}"},
40
+ {"date":"2025-09-01","medium":"GDN","creative":"D2","is_control":0,"impressions":1045,"clicks":33,"conversions":4,"cost":570,"features_json":"{}"},
41
+ {"date":"2025-09-01","medium":"GDN","creative":"E2","is_control":0,"impressions":905,"clicks":20,"conversions":2,"cost":462,"features_json":"{}"}
42
+ ]
43
+ append_events(pd.DataFrame(rows))
44
+ df, agg = read_events(), aggregate()
45
+ return df, agg, _ok("Sample data loaded.")
46
+
47
+ def ui_upload_csv(file: gr.File):
48
+ if file is None:
49
+ return gr.update(), gr.update(), _warn("CSVファイルを選択してください。")
50
+ try:
51
+ df = pd.read_csv(file.name)
52
+ except Exception as e:
53
+ return gr.update(), gr.update(), _err(f"CSV読み込みに失敗: {e}")
54
+
55
+ missing = [c for c in REQUIRED_COLS if c not in df.columns]
56
+ if missing:
57
+ return gr.update(), gr.update(), _err(f"必須列が不足: {missing}")
58
+
59
+ # 型のサニタイズ(軽く)
60
+ for c in ["is_control","impressions","clicks","conversions"]:
61
+ df[c] = df[c].fillna(0).astype(int)
62
+ if "cost" in df.columns:
63
+ df["cost"] = df["cost"].fillna(0.0).astype(float)
64
+ if "features_json" in df.columns:
65
+ df["features_json"] = df["features_json"].fillna("{}").astype(str)
66
+
67
+ append_events(df)
68
+ df2, agg2 = read_events(), aggregate()
69
+ return df2, agg2, _ok(f"取り込み完了({len(df)}行)。")
70
 
71
+ # ---- bandit / causal ----
72
  def ui_recommend():
73
  agg = aggregate()
74
  if agg.empty:
75
+ return {"message": "No data yet. Dataタブで 'Load Sample Data' を押すか、CSVを取り込んでください。"}
76
  return BANDIT.recommend(agg)
77
 
78
  def ui_plot_posteriors(medium: str):
 
93
  return {"message": "No data"}
94
  return fit_uplift_binary(agg)
95
 
96
+ # ---- UI ----
97
  def build_ui():
98
  with gr.Blocks(title="AdCopy MAB Optimizer Pro") as demo:
99
  gr.Markdown("# AdCopy MAB Optimizer Pro — Hierarchical TS + Uplift")
100
+
101
  with gr.Tab("Data"):
102
+ status = gr.Markdown() # メッセージ表示
103
+ with gr.Row():
104
+ btn_refresh = gr.Button("Refresh")
105
+ btn_seed = gr.Button("Load Sample Data")
106
+ with gr.Row():
107
+ file = gr.File(label="Upload CSV (columns: " + ", ".join(REQUIRED_COLS) + ")", file_types=[".csv"])
108
+ btn_upload = gr.Button("Import CSV")
109
  grid = gr.Dataframe(headers=["ts","date","medium","creative","is_control","impressions","clicks","conversions","cost","features_json"], wrap=True)
110
  grid_agg = gr.Dataframe()
111
+
112
+ btn_refresh.click(ui_refresh_tables, outputs=[grid, grid_agg, status])
113
+ btn_seed.click(ui_load_sample, outputs=[grid, grid_agg, status])
114
+ btn_upload.click(ui_upload_csv, inputs=[file], outputs=[grid, grid_agg, status])
115
+
116
  with gr.Tab("Bandit"):
117
  bbtn = gr.Button("Suggest Allocation (TS)")
118
  jout = gr.JSON()
 
122
  plot = gr.Plot(visible=False)
123
  msg = gr.Markdown()
124
  gr.Button("Plot CTR by Creative").click(ui_plot_posteriors, inputs=[medium], outputs=[plot, msg])
125
+
126
  with gr.Tab("Uplift (Causal)"):
127
  cbtn = gr.Button("Fit Uplift Model")
128
  cout = gr.JSON()
129
  cbtn.click(ui_fit_uplift, outputs=cout)
130
+
131
  return demo