bilalnaveed commited on
Commit
09258b6
Β·
verified Β·
1 Parent(s): caffb70

Upload database.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. database.py +329 -0
database.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Supabase Database Integration for Naveed AI
3
+ Handles all database operations β€” chat history, analytics, feedback.
4
+ """
5
+
6
+ import os
7
+ import uuid
8
+ import time
9
+ from datetime import datetime
10
+ from typing import Optional, List, Dict
11
+
12
+ # Supabase config
13
+ SUPABASE_URL = os.environ.get(
14
+ "SUPABASE_URL",
15
+ "https://kfvpwpjqdvfsmyldaqau.supabase.co"
16
+ )
17
+ SUPABASE_KEY = os.environ.get(
18
+ "SUPABASE_KEY",
19
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImtmdnB3cGpxZHZmc215bGRhcWF1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzEzNDgzMTEsImV4cCI6MjA4NjkyNDMxMX0.P9YujsB_WS2d3zVBYD3pY3J8I2RCvWkd4FRqDqrHCaM"
20
+ )
21
+
22
+ # Global client (lazy init)
23
+ _supabase = None
24
+ _db_available = False
25
+
26
+
27
+ def _get_client():
28
+ """Get or create Supabase client (lazy initialization)."""
29
+ global _supabase, _db_available
30
+ if _supabase is not None:
31
+ return _supabase
32
+
33
+ try:
34
+ from supabase import create_client
35
+ _supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
36
+ _db_available = True
37
+ print("βœ… Supabase connected!")
38
+ return _supabase
39
+ except ImportError:
40
+ print("⚠️ supabase package not installed β€” database disabled")
41
+ _db_available = False
42
+ return None
43
+ except Exception as e:
44
+ print(f"⚠️ Supabase connection failed: {e} β€” database disabled")
45
+ _db_available = False
46
+ return None
47
+
48
+
49
+ def is_available() -> bool:
50
+ """Check if database is available."""
51
+ _get_client()
52
+ return _db_available
53
+
54
+
55
+ def generate_session_id() -> str:
56
+ """Generate a unique session ID for anonymous users."""
57
+ return str(uuid.uuid4())[:16]
58
+
59
+
60
+ # ─────────────────────────────────────────────────────────────
61
+ # CONVERSATIONS & MESSAGES
62
+ # ─────────────────────────────────────────────────────────────
63
+
64
+ def create_conversation(session_id: str, title: str = "New Chat") -> Optional[str]:
65
+ """Create a new conversation. Returns conversation ID."""
66
+ client = _get_client()
67
+ if not client:
68
+ return None
69
+ try:
70
+ result = client.table("conversations").insert({
71
+ "session_id": session_id,
72
+ "title": title[:100],
73
+ }).execute()
74
+ if result.data:
75
+ _increment_analytics("chat")
76
+ return result.data[0]["id"]
77
+ except Exception as e:
78
+ print(f"DB error (create_conversation): {e}")
79
+ return None
80
+
81
+
82
+ def save_message(
83
+ conversation_id: str,
84
+ role: str,
85
+ content: str,
86
+ thinking_mode: bool = False,
87
+ tokens_used: int = 0,
88
+ response_time_ms: int = 0,
89
+ ) -> Optional[str]:
90
+ """Save a message to the database. Returns message ID."""
91
+ client = _get_client()
92
+ if not client or not conversation_id:
93
+ return None
94
+ try:
95
+ result = client.table("messages").insert({
96
+ "conversation_id": conversation_id,
97
+ "role": role,
98
+ "content": content[:10000], # limit content size
99
+ "thinking_mode": thinking_mode,
100
+ "tokens_used": tokens_used,
101
+ "response_time_ms": response_time_ms,
102
+ }).execute()
103
+
104
+ # Update conversation message count
105
+ client.table("conversations").update({
106
+ "message_count": client.table("messages")
107
+ .select("id", count="exact")
108
+ .eq("conversation_id", conversation_id)
109
+ .execute().count or 0
110
+ }).eq("id", conversation_id).execute()
111
+
112
+ _increment_analytics("message")
113
+
114
+ if result.data:
115
+ return result.data[0]["id"]
116
+ except Exception as e:
117
+ print(f"DB error (save_message): {e}")
118
+ return None
119
+
120
+
121
+ def get_conversation_history(conversation_id: str, limit: int = 50) -> List[Dict]:
122
+ """Get messages for a conversation."""
123
+ client = _get_client()
124
+ if not client or not conversation_id:
125
+ return []
126
+ try:
127
+ result = (
128
+ client.table("messages")
129
+ .select("role, content, thinking_mode, created_at")
130
+ .eq("conversation_id", conversation_id)
131
+ .order("created_at", desc=False)
132
+ .limit(limit)
133
+ .execute()
134
+ )
135
+ return result.data or []
136
+ except Exception as e:
137
+ print(f"DB error (get_history): {e}")
138
+ return []
139
+
140
+
141
+ def get_recent_conversations(session_id: str, limit: int = 20) -> List[Dict]:
142
+ """Get recent conversations for a session."""
143
+ client = _get_client()
144
+ if not client:
145
+ return []
146
+ try:
147
+ result = (
148
+ client.table("conversations")
149
+ .select("id, title, message_count, created_at")
150
+ .eq("session_id", session_id)
151
+ .order("created_at", desc=True)
152
+ .limit(limit)
153
+ .execute()
154
+ )
155
+ return result.data or []
156
+ except Exception as e:
157
+ print(f"DB error (get_conversations): {e}")
158
+ return []
159
+
160
+
161
+ # ─────────────────────────────────────────────────────────────
162
+ # IMAGE GENERATION TRACKING
163
+ # ─────────────────────────────────────────────────────────────
164
+
165
+ def log_image_generation(
166
+ session_id: str,
167
+ prompt: str,
168
+ style: str = "Default",
169
+ negative_prompt: str = "",
170
+ success: bool = True,
171
+ error_message: str = "",
172
+ ):
173
+ """Log an image generation event."""
174
+ client = _get_client()
175
+ if not client:
176
+ return
177
+ try:
178
+ client.table("image_generations").insert({
179
+ "session_id": session_id,
180
+ "prompt": prompt[:500],
181
+ "style": style,
182
+ "negative_prompt": negative_prompt[:500] if negative_prompt else None,
183
+ "success": success,
184
+ "error_message": error_message[:500] if error_message else None,
185
+ }).execute()
186
+ _increment_analytics("image_gen")
187
+ except Exception as e:
188
+ print(f"DB error (log_image_gen): {e}")
189
+
190
+
191
+ # ─────────────────────────────────────────────────────────────
192
+ # SPEECH-TO-TEXT TRACKING
193
+ # ─────────────────────────────────────────────────────────────
194
+
195
+ def log_stt(
196
+ session_id: str,
197
+ transcribed_text: str = "",
198
+ success: bool = True,
199
+ error_message: str = "",
200
+ ):
201
+ """Log a speech-to-text event."""
202
+ client = _get_client()
203
+ if not client:
204
+ return
205
+ try:
206
+ client.table("speech_transcriptions").insert({
207
+ "session_id": session_id,
208
+ "transcribed_text": transcribed_text[:5000] if transcribed_text else None,
209
+ "success": success,
210
+ "error_message": error_message[:500] if error_message else None,
211
+ }).execute()
212
+ _increment_analytics("stt")
213
+ except Exception as e:
214
+ print(f"DB error (log_stt): {e}")
215
+
216
+
217
+ # ─────────────────────────────────────────────────────────────
218
+ # IMAGE READING / VISION TRACKING
219
+ # ─────────────────────────────────────────────────────────────
220
+
221
+ def log_vision(
222
+ session_id: str,
223
+ question: str = "",
224
+ analysis_result: str = "",
225
+ success: bool = True,
226
+ error_message: str = "",
227
+ ):
228
+ """Log an image reading/vision event."""
229
+ client = _get_client()
230
+ if not client:
231
+ return
232
+ try:
233
+ client.table("image_readings").insert({
234
+ "session_id": session_id,
235
+ "question": question[:500] if question else None,
236
+ "analysis_result": analysis_result[:5000] if analysis_result else None,
237
+ "success": success,
238
+ "error_message": error_message[:500] if error_message else None,
239
+ }).execute()
240
+ _increment_analytics("vision")
241
+ except Exception as e:
242
+ print(f"DB error (log_vision): {e}")
243
+
244
+
245
+ # ─────────────────────────────────────────────────────────────
246
+ # FEEDBACK
247
+ # ─────────────────────────────────────────────────────────────
248
+
249
+ def save_feedback(
250
+ session_id: str,
251
+ rating: int,
252
+ comment: str = "",
253
+ feature: str = "general",
254
+ ):
255
+ """Save user feedback/rating."""
256
+ client = _get_client()
257
+ if not client:
258
+ return
259
+ try:
260
+ client.table("feedback").insert({
261
+ "session_id": session_id,
262
+ "rating": max(1, min(5, rating)),
263
+ "comment": comment[:1000] if comment else None,
264
+ "feature": feature,
265
+ }).execute()
266
+ except Exception as e:
267
+ print(f"DB error (save_feedback): {e}")
268
+
269
+
270
+ # ─────────────────────────────────────────────────────────────
271
+ # ANALYTICS
272
+ # ─────────────────────────────────────────────────────���───────
273
+
274
+ def _increment_analytics(feature: str):
275
+ """Increment daily analytics counter (internal)."""
276
+ client = _get_client()
277
+ if not client:
278
+ return
279
+ try:
280
+ # Use the database function
281
+ client.rpc("increment_analytics", {"p_feature": feature}).execute()
282
+ except Exception as e:
283
+ # Silently fail β€” analytics are not critical
284
+ pass
285
+
286
+
287
+ def get_analytics(days: int = 7) -> List[Dict]:
288
+ """Get analytics for the last N days."""
289
+ client = _get_client()
290
+ if not client:
291
+ return []
292
+ try:
293
+ result = (
294
+ client.table("analytics")
295
+ .select("*")
296
+ .order("date", desc=True)
297
+ .limit(days)
298
+ .execute()
299
+ )
300
+ return result.data or []
301
+ except Exception as e:
302
+ print(f"DB error (get_analytics): {e}")
303
+ return []
304
+
305
+
306
+ def get_total_stats() -> Dict:
307
+ """Get all-time total stats."""
308
+ client = _get_client()
309
+ if not client:
310
+ return {"total_chats": 0, "total_messages": 0, "total_image_gens": 0,
311
+ "total_stt": 0, "total_vision": 0}
312
+ try:
313
+ result = client.table("analytics").select(
314
+ "total_chats, total_messages, total_image_gens, total_stt_uses, total_vision_uses"
315
+ ).execute()
316
+
317
+ stats = {"total_chats": 0, "total_messages": 0, "total_image_gens": 0,
318
+ "total_stt": 0, "total_vision": 0}
319
+ for row in (result.data or []):
320
+ stats["total_chats"] += row.get("total_chats", 0)
321
+ stats["total_messages"] += row.get("total_messages", 0)
322
+ stats["total_image_gens"] += row.get("total_image_gens", 0)
323
+ stats["total_stt"] += row.get("total_stt_uses", 0)
324
+ stats["total_vision"] += row.get("total_vision_uses", 0)
325
+ return stats
326
+ except Exception as e:
327
+ print(f"DB error (get_total_stats): {e}")
328
+ return {"total_chats": 0, "total_messages": 0, "total_image_gens": 0,
329
+ "total_stt": 0, "total_vision": 0}