Spaces:
Sleeping
Sleeping
File size: 9,481 Bytes
d32f83a 1eea1b0 97e7d6b d32f83a 25f9ba9 d32f83a 1eea1b0 25f9ba9 d32f83a 1eea1b0 d32f83a 1eea1b0 d32f83a 1cbada8 25f9ba9 1cbada8 97e7d6b d32f83a 97e7d6b d32f83a 1eea1b0 25f9ba9 1eea1b0 d32f83a 97e7d6b 1eea1b0 25f9ba9 1eea1b0 25f9ba9 1eea1b0 25f9ba9 d32f83a 97e7d6b 1eea1b0 97e7d6b 1eea1b0 25f9ba9 1eea1b0 97e7d6b 1eea1b0 25f9ba9 1cbada8 1eea1b0 1cbada8 1eea1b0 97e7d6b 1eea1b0 25f9ba9 1cbada8 1eea1b0 1cbada8 1eea1b0 97e7d6b 1cbada8 25f9ba9 1cbada8 97e7d6b 1cbada8 25f9ba9 1cbada8 97e7d6b 1cbada8 25f9ba9 1cbada8 97e7d6b 1cbada8 25f9ba9 1cbada8 97e7d6b 1eea1b0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
import sqlite3
import pandas as pd
import json
import streamlit as st
DB_FILE = "leads.db"
def get_connection():
"""Create a SQLite connection with safe defaults (foreign keys on)."""
conn = sqlite3.connect(DB_FILE)
try:
conn.execute("PRAGMA foreign_keys = ON")
except Exception:
pass
return conn
def init_db():
"""Initializes all tables for the application."""
with get_connection() as conn:
cursor = conn.cursor()
# Main leads table
cursor.execute("""
CREATE TABLE IF NOT EXISTS leads (
id INTEGER PRIMARY KEY AUTOINCREMENT,
Date TEXT, Name TEXT, Company TEXT, Type TEXT, Context TEXT,
Pain_Point TEXT, Budget TEXT, Outcome TEXT, Summary TEXT,
Archetype TEXT, Transcript TEXT
)
""")
# --- Colosseum Tables ---
cursor.execute("""
CREATE TABLE IF NOT EXISTS scenarios (
id INTEGER PRIMARY KEY AUTOINCREMENT,
generation INTEGER DEFAULT 0,
fitness_score REAL DEFAULT 0.0,
graph_json TEXT
)
""")
cursor.execute("""
CREATE TABLE IF NOT EXISTS simulations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
scenario_id INTEGER,
customer_persona TEXT,
outcome TEXT,
score INTEGER,
transcript TEXT,
FOREIGN KEY (scenario_id) REFERENCES scenarios (id)
)
""")
cursor.execute("""
CREATE TABLE IF NOT EXISTS phrase_analytics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
scenario_id INTEGER,
node_name TEXT,
phrase TEXT,
impact TEXT,
count INTEGER DEFAULT 1,
UNIQUE(scenario_id, node_name, phrase, impact),
FOREIGN KEY (scenario_id) REFERENCES scenarios (id)
)
""")
conn.commit()
def add_lead(lead_data):
"""Adds a new lead to the database.
lead_data: dict with optional keys matching leads table columns.
Returns inserted row id.
"""
with get_connection() as conn:
cursor = conn.cursor()
# Ensure DB exists
init_db()
# Valid columns as per schema
columns = [
"Date", "Name", "Company", "Type", "Context",
"Pain_Point", "Budget", "Outcome", "Summary",
"Archetype", "Transcript"
]
cols_used = []
vals_used = []
for col in columns:
if col in lead_data:
cols_used.append(col)
vals_used.append(lead_data[col])
if not cols_used:
return None
placeholders = ", ".join(["?"] * len(cols_used))
cols_sql = ", ".join(cols_used)
cursor.execute(
f"INSERT INTO leads ({cols_sql}) VALUES ({placeholders})",
tuple(vals_used)
)
conn.commit()
# Invalidate cached readers
try:
st.cache_data.clear()
except Exception:
pass
return cursor.lastrowid
# --- Functions that write data don't get cached ---
@st.cache_data
def get_all_leads():
"""Retrieves all leads from the database."""
with get_connection() as conn:
return pd.read_sql_query("SELECT * FROM leads", conn)
@st.cache_data
def get_scenario(scenario_id):
"""Retrieves a specific scenario."""
with get_connection() as conn:
cursor = conn.cursor()
cursor.execute("SELECT graph_json FROM scenarios WHERE id = ?", (int(scenario_id),))
row = cursor.fetchone()
if not row:
return None
try:
return json.loads(row[0])
except Exception:
# Corrupt or invalid JSON stored
return None
# --- Evolution Hub Read Functions ---
@st.cache_data
def get_all_scenarios_with_stats():
"""Retrieves all scenarios with aggregated stats."""
with get_connection() as conn:
query = """
SELECT
s.id,
s.generation,
s.fitness_score,
COUNT(sim.id) as simulation_count
FROM scenarios s
LEFT JOIN simulations sim ON s.id = sim.scenario_id
GROUP BY s.id
ORDER BY s.fitness_score DESC
"""
return pd.read_sql_query(query, conn)
@st.cache_data
def get_simulations_for_scenario(scenario_id, limit=10):
"""Retrieves recent simulations for a specific scenario."""
# Sanitize inputs
try:
scenario_id = int(scenario_id)
except Exception:
scenario_id = -1
try:
limit = int(limit)
except Exception:
limit = 10
# Clamp limit to safe bounds
if limit < 1:
limit = 1
if limit > 100:
limit = 100
with get_connection() as conn:
query = (
"SELECT outcome, score, customer_persona FROM simulations "
"WHERE scenario_id = ? ORDER BY id DESC LIMIT ?"
)
return pd.read_sql_query(query, conn, params=(scenario_id, limit))
@st.cache_data
def get_phrase_analytics_for_scenario(scenario_id):
"""Retrieves phrase analytics for a specific scenario."""
try:
scenario_id = int(scenario_id)
except Exception:
scenario_id = -1
with get_connection() as conn:
query = (
"SELECT phrase, impact, count, node_name FROM phrase_analytics "
"WHERE scenario_id = ? ORDER BY count DESC"
)
return pd.read_sql_query(query, conn, params=(scenario_id,))
# --- Write functions (no caching) ---
def add_scenario(graph_json, generation=0):
"""Insert a new scenario and return its ID."""
init_db()
with get_connection() as conn:
cursor = conn.cursor()
cursor.execute(
"INSERT INTO scenarios (generation, fitness_score, graph_json) VALUES (?, ?, ?)",
(generation, 0.0, json.dumps(graph_json))
)
conn.commit()
try:
st.cache_data.clear()
except Exception:
pass
return cursor.lastrowid
def log_simulation(log_data):
"""Insert a simulation log. Expects keys: scenario_id, customer_persona, outcome, score, transcript"""
required = ["scenario_id", "customer_persona", "outcome", "score", "transcript"]
for k in required:
if k not in log_data:
raise ValueError(f"Missing field in log_data: {k}")
with get_connection() as conn:
cursor = conn.cursor()
cursor.execute(
"INSERT INTO simulations (scenario_id, customer_persona, outcome, score, transcript) "
"VALUES (?, ?, ?, ?, ?)",
(
log_data["scenario_id"],
json.dumps(log_data["customer_persona"]) if not isinstance(log_data["customer_persona"], str) else log_data["customer_persona"],
log_data["outcome"],
int(log_data["score"]),
log_data["transcript"],
)
)
conn.commit()
try:
st.cache_data.clear()
except Exception:
pass
return cursor.lastrowid
def update_phrase_analytics(analytics_data):
"""Update phrase analytics using upsert-like logic.
Expects list of dicts with keys: scenario_id, node_name, phrase, impact, count
"""
if not analytics_data:
return 0
updated = 0
with get_connection() as conn:
cursor = conn.cursor()
for item in analytics_data:
scenario_id = item.get("scenario_id")
node_name = item.get("node_name")
phrase = item.get("phrase")
impact = item.get("impact")
count = int(item.get("count", 1))
if not all([scenario_id, node_name, phrase, impact]):
continue
# Try insert; if conflict, update count
cursor.execute(
"INSERT OR IGNORE INTO phrase_analytics (scenario_id, node_name, phrase, impact, count) "
"VALUES (?, ?, ?, ?, ?)",
(scenario_id, node_name, phrase, impact, count)
)
cursor.execute(
"UPDATE phrase_analytics SET count = count + ? WHERE scenario_id = ? AND node_name = ? AND phrase = ? AND impact = ?",
(count, scenario_id, node_name, phrase, impact)
)
updated += 1
conn.commit()
try:
st.cache_data.clear()
except Exception:
pass
return updated
def update_scenario_fitness(scenario_id):
"""Recompute and update the fitness score of a scenario as the average of its simulations' scores."""
with get_connection() as conn:
cursor = conn.cursor()
cursor.execute(
"SELECT AVG(score) FROM simulations WHERE scenario_id = ?",
(scenario_id,)
)
row = cursor.fetchone()
avg_score = row[0] if row and row[0] is not None else 0.0
cursor.execute(
"UPDATE scenarios SET fitness_score = ? WHERE id = ?",
(avg_score, scenario_id)
)
conn.commit()
try:
st.cache_data.clear()
except Exception:
pass
return avg_score
if __name__ == '__main__':
print("Initializing database for Colosseum...")
init_db()
print("Database initialized.")
|