Corin1998 commited on
Commit
e691c59
·
verified ·
1 Parent(s): 79f40eb

Update app/storage.py

Browse files
Files changed (1) hide show
  1. app/storage.py +124 -73
app/storage.py CHANGED
@@ -1,89 +1,140 @@
1
  from __future__ import annotations
2
- value_per_conversion: float):
3
- with get_conn() as con:
4
- con.execute(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  """
6
- INSERT INTO campaigns (campaign_id, brand, product, target_audience, tone, language, constraints_json, value_per_conversion)
7
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
8
- ON CONFLICT(campaign_id) DO UPDATE SET
9
- brand=excluded.brand,
10
- product=excluded.product,
11
- target_audience=excluded.target_audience,
12
- tone=excluded.tone,
13
- language=excluded.language,
14
- constraints_json=excluded.constraints_json,
15
- value_per_conversion=excluded.value_per_conversion
16
- """,
17
- (campaign_id, brand, product, target_audience, tone, language, json.dumps(constraints or {}), value_per_conversion)
18
- )
19
-
20
-
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  def insert_variant(campaign_id: str, variant_id: str, text: str, status: str, rejection_reason: Optional[str]):
24
- with get_conn() as con:
25
- con.execute(
26
- """
27
- INSERT OR REPLACE INTO variants (campaign_id, variant_id, text, status, rejection_reason)
28
- VALUES (?, ?, ?, ?, ?)
29
- """,
30
- (campaign_id, variant_id, text, status, rejection_reason)
31
- )
32
- con.execute(
33
- """
34
- INSERT OR IGNORE INTO metrics (campaign_id, variant_id)
35
- VALUES (?, ?)
36
- """,
37
- (campaign_id, variant_id)
38
- )
39
-
40
-
41
-
42
 
43
  def get_variants(campaign_id: str) -> List[sqlite3.Row]:
44
- with get_conn() as con:
45
- cur = con.execute("SELECT * FROM variants WHERE campaign_id=?", (campaign_id,))
46
- return cur.fetchall()
47
-
48
-
49
-
50
 
51
  def get_variant(campaign_id: str, variant_id: str) -> Optional[sqlite3.Row]:
52
- with get_conn() as con:
53
- cur = con.execute("SELECT * FROM variants WHERE campaign_id=? AND variant_id=?", (campaign_id, variant_id))
54
- return cur.fetchone()
55
-
56
-
57
-
58
 
59
  def get_metrics(campaign_id: str) -> List[sqlite3.Row]:
60
- with get_conn() as con:
61
- cur = con.execute("SELECT * FROM metrics WHERE campaign_id=?", (campaign_id,))
62
- return cur.fetchall()
63
-
64
-
65
-
66
 
67
  def update_metric(campaign_id: str, variant_id: str, field: str, inc: float = 1.0):
68
- assert field in {"impressions", "clicks", "conversions", "alpha_click", "beta_click", "alpha_conv", "beta_conv"}
69
- with get_conn() as con:
70
- con.execute(f"UPDATE metrics SET {field} = {field} + ? WHERE campaign_id=? AND variant_id=?", (inc, campaign_id, variant_id))
71
-
72
-
73
-
74
-
75
- def log_event(campaign_id: str, variant_id: str, event_type: str, ts: Optional[str], value: Optional[float]):
76
- with get_conn() as con:
77
- con.execute(
78
- "INSERT INTO events (campaign_id, variant_id, event_type, ts, value) VALUES (?, ?, ?, ?, ?)",
79
- (campaign_id, variant_id, event_type, ts, value)
80
- )
81
-
82
-
83
 
 
 
 
 
 
 
84
 
85
  def get_campaign_value_per_conversion(campaign_id: str) -> float:
86
- with get_conn() as con:
87
- cur = con.execute("SELECT value_per_conversion FROM campaigns WHERE campaign_id=?", (campaign_id,))
88
- row = cur.fetchone()
89
- return float(row[0]) if row else 1.0
 
1
  from __future__ import annotations
2
+ import os
3
+ import sqlite3
4
+ import json
5
+ from pathlib import Path
6
+ from typing import Optional, Dict, Any, List
7
+
8
+ # 永続領域 /data が書き込み可なら /data/app_data を使う。なければ /tmp/app_data へフォールバック。
9
+ DEFAULT_DIR = "/data/app_data" if os.access("/data", os.W_OK) else "/tmp/app_data"
10
+ DB_DIR = Path(os.environ.get("APP_DATA_DIR", DEFAULT_DIR))
11
+ DB_DIR.mkdir(parents=True, exist_ok=True)
12
+ DB_PATH = DB_DIR / "data.db"
13
+
14
+ SCHEMA_SQL = """
15
+ PRAGMA journal_mode=WAL;
16
+ CREATE TABLE IF NOT EXISTS campaigns (
17
+ campaign_id TEXT PRIMARY KEY,
18
+ brand TEXT,
19
+ product TEXT,
20
+ target_audience TEXT,
21
+ tone TEXT,
22
+ language TEXT,
23
+ constraints_json TEXT,
24
+ value_per_conversion REAL DEFAULT 1.0
25
+ );
26
+ CREATE TABLE IF NOT EXISTS variants (
27
+ campaign_id TEXT,
28
+ variant_id TEXT,
29
+ text TEXT,
30
+ status TEXT,
31
+ rejection_reason TEXT,
32
+ PRIMARY KEY (campaign_id, variant_id)
33
+ );
34
+ CREATE TABLE IF NOT EXISTS metrics (
35
+ campaign_id TEXT,
36
+ variant_id TEXT,
37
+ impressions INTEGER DEFAULT 0,
38
+ clicks INTEGER DEFAULT 0,
39
+ conversions INTEGER DEFAULT 0,
40
+ alpha_click REAL DEFAULT 1.0,
41
+ beta_click REAL DEFAULT 1.0,
42
+ alpha_conv REAL DEFAULT 1.0,
43
+ beta_conv REAL DEFAULT 1.0,
44
+ PRIMARY KEY (campaign_id, variant_id)
45
+ );
46
+ CREATE TABLE IF NOT EXISTS events (
47
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
48
+ campaign_id TEXT,
49
+ variant_id TEXT,
50
+ event_type TEXT,
51
+ ts TEXT,
52
+ value REAL
53
+ );
54
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ def get_conn():
57
+ conn = sqlite3.connect(DB_PATH)
58
+ conn.row_factory = sqlite3.Row
59
+ return conn
60
+
61
+ def init_db():
62
+ with get_conn() as con:
63
+ con.executescript(SCHEMA_SQL)
64
+
65
+ def upsert_campaign(
66
+ campaign_id: str,
67
+ brand: str,
68
+ product: str,
69
+ target_audience: str,
70
+ tone: str,
71
+ language: str,
72
+ constraints: Optional[Dict[str, Any]],
73
+ value_per_conversion: float,
74
+ ):
75
+ with get_conn() as con:
76
+ con.execute(
77
+ """
78
+ INSERT INTO campaigns (campaign_id, brand, product, target_audience, tone, language, constraints_json, value_per_conversion)
79
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
80
+ ON CONFLICT(campaign_id) DO UPDATE SET
81
+ brand=excluded.brand,
82
+ product=excluded.product,
83
+ target_audience=excluded.target_audience,
84
+ tone=excluded.tone,
85
+ language=excluded.language,
86
+ constraints_json=excluded.constraints_json,
87
+ value_per_conversion=excluded.value_per_conversion
88
+ """,
89
+ (campaign_id, brand, product, target_audience, tone, language, json.dumps(constraints or {}), value_per_conversion),
90
+ )
91
 
92
  def insert_variant(campaign_id: str, variant_id: str, text: str, status: str, rejection_reason: Optional[str]):
93
+ with get_conn() as con:
94
+ con.execute(
95
+ """
96
+ INSERT OR REPLACE INTO variants (campaign_id, variant_id, text, status, rejection_reason)
97
+ VALUES (?, ?, ?, ?, ?)
98
+ """,
99
+ (campaign_id, variant_id, text, status, rejection_reason),
100
+ )
101
+ con.execute(
102
+ """
103
+ INSERT OR IGNORE INTO metrics (campaign_id, variant_id)
104
+ VALUES (?, ?)
105
+ """,
106
+ (campaign_id, variant_id),
107
+ )
 
 
 
108
 
109
  def get_variants(campaign_id: str) -> List[sqlite3.Row]:
110
+ with get_conn() as con:
111
+ cur = con.execute("SELECT * FROM variants WHERE campaign_id=?", (campaign_id,))
112
+ return cur.fetchall()
 
 
 
113
 
114
  def get_variant(campaign_id: str, variant_id: str) -> Optional[sqlite3.Row]:
115
+ with get_conn() as con:
116
+ cur = con.execute("SELECT * FROM variants WHERE campaign_id=? AND variant_id=?", (campaign_id, variant_id))
117
+ return cur.fetchone()
 
 
 
118
 
119
  def get_metrics(campaign_id: str) -> List[sqlite3.Row]:
120
+ with get_conn() as con:
121
+ cur = con.execute("SELECT * FROM metrics WHERE campaign_id=?", (campaign_id,))
122
+ return cur.fetchall()
 
 
 
123
 
124
  def update_metric(campaign_id: str, variant_id: str, field: str, inc: float = 1.0):
125
+ assert field in {"impressions", "clicks", "conversions", "alpha_click", "beta_click", "alpha_conv", "beta_conv"}
126
+ with get_conn() as con:
127
+ con.execute(f"UPDATE metrics SET {field} = {field} + ? WHERE campaign_id=? AND variant_id=?", (inc, campaign_id, variant_id))
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
+ def log_event(campaign_id: str, variant_id: str, event_type: str, ts: str, value):
130
+ with get_conn() as con:
131
+ con.execute(
132
+ "INSERT INTO events (campaign_id, variant_id, event_type, ts, value) VALUES (?, ?, ?, ?, ?)",
133
+ (campaign_id, variant_id, event_type, ts, value),
134
+ )
135
 
136
  def get_campaign_value_per_conversion(campaign_id: str) -> float:
137
+ with get_conn() as con:
138
+ cur = con.execute("SELECT value_per_conversion FROM campaigns WHERE campaign_id=?", (campaign_id,))
139
+ row = cur.fetchone()
140
+ return float(row[0]) if row else 1.0