""" One-time script: creates the meta_optimizer database in Baserow with all tables and fields. Run once, then paste the printed IDs into your .env file. Usage: python setup_baserow.py """ import os import sys import requests from dotenv import load_dotenv load_dotenv() BASE_URL = os.environ.get("BASEROW_URL", "").rstrip("/") EMAIL = os.environ.get("BASEROW_EMAIL", "") PASSWORD = os.environ.get("BASEROW_PASSWORD", "") if not BASE_URL or not EMAIL or not PASSWORD: print("Error: BASEROW_URL, BASEROW_EMAIL and BASEROW_PASSWORD must be set in your .env file.") sys.exit(1) # Authenticate to get a JWT token _auth = requests.post(f"{BASE_URL}/api/user/token-auth/", json={"email": EMAIL, "password": PASSWORD}, timeout=10) if not _auth.ok: print(f"Auth error: {_auth.text}") sys.exit(1) JWT = _auth.json()["access_token"] HEADERS = { "Authorization": f"JWT {JWT}", "Content-Type": "application/json", } def api(method: str, path: str, **kwargs) -> dict: url = f"{BASE_URL}/api{path}" resp = requests.request(method, url, headers=HEADERS, **kwargs) if not resp.ok: print(f" API error {resp.status_code} {method} {path}: {resp.text[:300]}") resp.raise_for_status() return resp.json() def setup_table(db_id: int, table_name: str, fields: list) -> int: """Create table, rename the auto-created primary field, then add remaining fields.""" t = api("POST", f"/database/tables/database/{db_id}/", json={"name": table_name}) table_id = t["id"] print(f"\n Table: {table_name} (id={table_id})") existing = api("GET", f"/database/fields/table/{table_id}/") primary_id = existing[0]["id"] first = fields[0] api("PATCH", f"/database/fields/{primary_id}/", json={"name": first["name"], "type": first["type"]}) print(f" ~ primary field renamed to: {first['name']}") for field in fields[1:]: api("POST", f"/database/fields/table/{table_id}/", json=field) print(f" + {field['name']}") return table_id # ── 1. Workspace ────────────────────────────────────────────────────────────── workspaces = api("GET", "/workspaces/") if not workspaces: print("No workspaces found. Create one in Baserow first.") sys.exit(1) workspace_id = workspaces[0]["id"] print(f"Workspace: {workspaces[0]['name']} (id={workspace_id})") # ── 2. Database ─────────────────────────────────────────────────────────────── db = api("POST", f"/applications/workspace/{workspace_id}/", json={ "type": "database", "name": "meta_optimizer", }) db_id = db["id"] print(f"Database: meta_optimizer (id={db_id})") # ── 3. Tables ───────────────────────────────────────────────────────────────── tid_campaigns = setup_table(db_id, "campaigns", [ {"name": "campaign_id", "type": "text"}, {"name": "name", "type": "text"}, {"name": "max_cpl", "type": "number", "number_decimal_places": 2}, {"name": "daily_budget", "type": "number", "number_decimal_places": 2}, {"name": "is_active", "type": "boolean"}, {"name": "notes", "type": "long_text"}, ]) tid_actions = setup_table(db_id, "proposed_actions", [ {"name": "campaign_id", "type": "text"}, {"name": "campaign_name", "type": "text"}, { "name": "action_type", "type": "single_select", "select_options": [ {"value": "PAUSE", "color": "red"}, {"value": "REDUCE_BUDGET", "color": "orange"}, {"value": "INCREASE_BUDGET", "color": "green"}, {"value": "MAINTAIN", "color": "blue"}, {"value": "REVIEW_CREATIVES", "color": "purple"}, ], }, {"name": "parameter", "type": "number", "number_decimal_places": 2}, {"name": "justification", "type": "long_text"}, {"name": "advice", "type": "long_text"}, {"name": "alert", "type": "long_text"}, {"name": "confidence", "type": "number", "number_decimal_places": 2}, { "name": "status", "type": "single_select", "select_options": [ {"value": "pending", "color": "yellow"}, {"value": "approved", "color": "green"}, {"value": "rejected", "color": "red"}, {"value": "executed", "color": "blue"}, ], }, {"name": "proposed_at", "type": "date", "date_format": "ISO", "date_include_time": True}, {"name": "executed_at", "type": "date", "date_format": "ISO", "date_include_time": True}, {"name": "slack_message_ts", "type": "text"}, ]) tid_creatives = setup_table(db_id, "creative_analyses", [ {"name": "ad_id", "type": "text"}, {"name": "ad_name", "type": "text"}, {"name": "campaign_id", "type": "text"}, {"name": "image_url", "type": "url"}, {"name": "analysis", "type": "long_text"}, {"name": "score", "type": "number", "number_decimal_places": 1}, {"name": "recommendations", "type": "long_text"}, {"name": "created_at", "type": "date", "date_format": "ISO", "date_include_time": True}, ]) tid_logs = setup_table(db_id, "execution_logs", [ {"name": "executed_at", "type": "date", "date_format": "ISO", "date_include_time": True}, {"name": "mode", "type": "text"}, {"name": "campaigns_analyzed", "type": "number"}, {"name": "actions_proposed", "type": "number"}, {"name": "actions_executed", "type": "number"}, {"name": "errors", "type": "long_text"}, {"name": "summary", "type": "long_text"}, {"name": "duration_seconds", "type": "number", "number_decimal_places": 1}, ]) # ── 4. Output env vars ──────────────────────────────────────────────────────── print(f""" {'='*55} Add these to your .env file: {'='*55} BASEROW_DB_ID={db_id} BASEROW_TABLE_CAMPAIGNS={tid_campaigns} BASEROW_TABLE_ACTIONS={tid_actions} BASEROW_TABLE_CREATIVES={tid_creatives} BASEROW_TABLE_LOGS={tid_logs} {'='*55} """)