Spaces:
Running
Running
File size: 4,768 Bytes
767deae 4ca0250 767deae 26078c9 767deae 26078c9 767deae 1829c17 767deae 1829c17 26078c9 767deae 26078c9 767deae 1829c17 767deae 1829c17 767deae 26078c9 767deae 1829c17 767deae 26078c9 767deae 26078c9 767deae 26078c9 767deae 26078c9 767deae 26078c9 767deae 26078c9 | 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 | """
Database layer — SQLite for user data and thread metadata.
LangGraph checkpointing also uses SQLite (configured in graph.py).
"""
import sqlite3
import time
from config import DB_PATH
conn = sqlite3.connect(database=DB_PATH, check_same_thread=False)
# --- Schema ---
conn.execute("""
CREATE TABLE IF NOT EXISTS users (
google_id TEXT PRIMARY KEY,
email TEXT NOT NULL,
name TEXT NOT NULL,
picture TEXT,
openrouter_key TEXT,
tavily_key TEXT,
student_profile TEXT,
created_at REAL NOT NULL,
last_login REAL NOT NULL
)
""")
# Upgrade path: add tavily_key column to pre-existing databases.
try:
conn.execute("ALTER TABLE users ADD COLUMN tavily_key TEXT")
except sqlite3.OperationalError:
pass # column already exists
conn.execute("""
CREATE TABLE IF NOT EXISTS thread_titles (
thread_id TEXT PRIMARY KEY,
title TEXT,
last_active REAL,
user_id TEXT
)
""")
conn.commit()
# --- User operations ---
def upsert_user(google_id: str, email: str, name: str, picture: str = "") -> dict:
"""Create or update a user from Google OAuth data."""
now = time.time()
existing = conn.execute(
"SELECT google_id FROM users WHERE google_id = ?", (google_id,)
).fetchone()
if existing:
conn.execute(
"UPDATE users SET last_login = ?, name = ?, picture = ? WHERE google_id = ?",
(now, name, picture, google_id),
)
else:
conn.execute(
"INSERT INTO users (google_id, email, name, picture, created_at, last_login) "
"VALUES (?, ?, ?, ?, ?, ?)",
(google_id, email, name, picture, now, now),
)
conn.commit()
return {"google_id": google_id, "email": email, "name": name, "picture": picture}
def get_user(google_id: str) -> dict | None:
row = conn.execute(
"SELECT google_id, email, name, picture, openrouter_key, student_profile, tavily_key "
"FROM users WHERE google_id = ?",
(google_id,),
).fetchone()
if not row:
return None
return {
"google_id": row[0], "email": row[1], "name": row[2],
"picture": row[3], "openrouter_key": row[4] or "",
"student_profile": row[5] or "",
"tavily_key": row[6] or "",
}
def save_user_api_key(google_id: str, key: str):
conn.execute(
"UPDATE users SET openrouter_key = ? WHERE google_id = ?", (key, google_id)
)
conn.commit()
def save_tavily_key(google_id: str, key: str):
conn.execute(
"UPDATE users SET tavily_key = ? WHERE google_id = ?", (key, google_id)
)
conn.commit()
def get_tavily_key(google_id: str) -> str:
row = conn.execute(
"SELECT tavily_key FROM users WHERE google_id = ?", (google_id,)
).fetchone()
return row[0] if row and row[0] else ""
def save_student_profile(google_id: str, profile: str):
conn.execute(
"UPDATE users SET student_profile = ? WHERE google_id = ?", (profile, google_id)
)
conn.commit()
def get_user_api_key(google_id: str) -> str:
row = conn.execute(
"SELECT openrouter_key FROM users WHERE google_id = ?", (google_id,)
).fetchone()
return row[0] if row and row[0] else ""
# --- Thread operations ---
def get_threads(user_id: str = ""):
if user_id:
cursor = conn.execute(
"SELECT thread_id, title FROM thread_titles "
"WHERE user_id = ? ORDER BY last_active DESC",
(user_id,),
)
else:
cursor = conn.execute(
"SELECT thread_id, title FROM thread_titles ORDER BY last_active DESC"
)
return [{"id": row[0], "title": row[1]} for row in cursor]
def upsert_thread(thread_id: str, message: str, now: float, user_id: str = ""):
row = conn.execute(
"SELECT thread_id FROM thread_titles WHERE thread_id = ?", (thread_id,)
).fetchone()
if row:
conn.execute(
"UPDATE thread_titles SET last_active = ? WHERE thread_id = ?",
(now, thread_id),
)
else:
title = message[:30] + ("..." if len(message) > 30 else "")
conn.execute(
"INSERT INTO thread_titles (thread_id, title, last_active, user_id) "
"VALUES (?, ?, ?, ?)",
(thread_id, title, now, user_id),
)
conn.commit()
def rename_thread(thread_id: str, title: str):
conn.execute(
"UPDATE thread_titles SET title = ? WHERE thread_id = ?", (title, thread_id)
)
conn.commit()
def delete_thread(thread_id: str):
conn.execute("DELETE FROM thread_titles WHERE thread_id = ?", (thread_id,))
conn.commit()
|