Spaces:
Sleeping
Sleeping
Download web_app/database.py from Shivam4096/Financial2API: direct link, hf CLI and curl.
- Browser
- Download file 5.89 kB
-
https://huggingface.co/spaces/Shivam4096/Financial2API/resolve/main/web_app/database.py
- Command line
-
hf download hf://spaces/Shivam4096/Financial2API/web_app/database.py
-
curl -L -o database.py https://huggingface.co/spaces/Shivam4096/Financial2API/resolve/main/web_app/database.py
5.89 kB
| """ | |
| web_app/database.py — Database audit logging system. | |
| Supports dual-driver data persistence: | |
| - Direct Cloud Supabase PostgreSQL storage (if environment variables exist). | |
| - Automatic Local SQLite database fallback. | |
| """ | |
| import os | |
| import sqlite3 | |
| import datetime | |
| from pathlib import Path | |
| from typing import List, Dict | |
| DB_PATH = Path(__file__).parent / "financial_audit.db" | |
| def init_db(): | |
| """Initializes the local SQLite database if not present.""" | |
| conn = sqlite3.connect(str(DB_PATH)) | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS financial_analysis_audit ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| timestamp TEXT NOT NULL, | |
| user_email TEXT NOT NULL, | |
| company_ticker TEXT NOT NULL, | |
| company_name TEXT NOT NULL, | |
| selected_formats TEXT NOT NULL, | |
| ai_model_used TEXT NOT NULL, | |
| status TEXT NOT NULL | |
| ) | |
| """) | |
| conn.commit() | |
| conn.close() | |
| def save_audit_log(user_email: str, company_ticker: str, company_name: str, selected_formats: List[str], ai_models: List[str], status: str): | |
| """ | |
| Saves an audit log entry. | |
| Tries Supabase first, falls back to local SQLite on failure or if not configured. | |
| """ | |
| timestamp = datetime.datetime.utcnow().isoformat() | |
| selected_formats_str = ", ".join(selected_formats) | |
| ai_models_str = ", ".join(ai_models) if ai_models else "none" | |
| supabase_url = os.environ.get("SUPABASE_URL") | |
| supabase_key = os.environ.get("SUPABASE_KEY") | |
| if supabase_url and supabase_key: | |
| try: | |
| from supabase import create_client, Client | |
| supabase: Client = create_client(supabase_url, supabase_key) | |
| data = { | |
| "user_email": user_email, | |
| "company_ticker": company_ticker, | |
| "company_name": company_name, | |
| "selected_formats": selected_formats, # stored as text array in Postgres | |
| "ai_model_used": ai_models_str, | |
| "status": status | |
| } | |
| supabase.table("financial_analysis_audit").insert(data).execute() | |
| print("Audit log successfully written to Cloud Supabase DB.") | |
| return | |
| except Exception as e: | |
| print(f"Supabase logging failed: {e}. Falling back to SQLite.") | |
| # Local SQLite Fallback | |
| try: | |
| init_db() | |
| conn = sqlite3.connect(str(DB_PATH)) | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| INSERT INTO financial_analysis_audit (timestamp, user_email, company_ticker, company_name, selected_formats, ai_model_used, status) | |
| VALUES (?, ?, ?, ?, ?, ?, ?) | |
| """, (timestamp, user_email, company_ticker, company_name, selected_formats_str, ai_models_str, status)) | |
| conn.commit() | |
| conn.close() | |
| print("Audit log written to local SQLite database.") | |
| except Exception as sqle: | |
| print(f"Local SQLite database audit write error: {sqle}") | |
| def get_audit_logs() -> List[Dict]: | |
| """ | |
| Fetches the history of audit logs. | |
| Tries Supabase first, falls back to local SQLite. | |
| """ | |
| supabase_url = os.environ.get("SUPABASE_URL") | |
| supabase_key = os.environ.get("SUPABASE_KEY") | |
| if supabase_url and supabase_key: | |
| try: | |
| from supabase import create_client, Client | |
| supabase: Client = create_client(supabase_url, supabase_key) | |
| response = supabase.table("financial_analysis_audit").select("*").order("timestamp", desc=True).limit(50).execute() | |
| logs = [] | |
| for row in response.data: | |
| # Convert list array from supabase to comma-separated string for display alignment | |
| formats = row.get("selected_formats", []) | |
| formats_str = ", ".join(formats) if isinstance(formats, list) else str(formats) | |
| # Format timestamp | |
| ts = row.get("timestamp", "") | |
| if ts: | |
| try: | |
| ts = datetime.datetime.fromisoformat(ts.replace("Z", "+00:00")).strftime("%Y-%m-%d %H:%M:%S") | |
| except: | |
| pass | |
| logs.append({ | |
| "timestamp": ts, | |
| "user_email": row.get("user_email", "N/A"), | |
| "company_ticker": row.get("company_ticker", "N/A"), | |
| "company_name": row.get("company_name", "N/A"), | |
| "selected_formats": formats_str, | |
| "ai_model_used": row.get("ai_model_used", "N/A"), | |
| "status": row.get("status", "N/A") | |
| }) | |
| return logs | |
| except Exception as e: | |
| print(f"Supabase fetch logs failed: {e}. Falling back to SQLite.") | |
| # SQLite Fallback | |
| try: | |
| init_db() | |
| conn = sqlite3.connect(str(DB_PATH)) | |
| conn.row_factory = sqlite3.Row | |
| cursor = conn.cursor() | |
| cursor.execute("SELECT * FROM financial_analysis_audit ORDER BY timestamp DESC LIMIT 50") | |
| rows = cursor.fetchall() | |
| logs = [] | |
| for r in rows: | |
| ts = r["timestamp"] | |
| if ts and "T" in ts: | |
| try: | |
| ts = datetime.datetime.fromisoformat(ts).strftime("%Y-%m-%d %H:%M:%S") | |
| except: | |
| pass | |
| logs.append({ | |
| "timestamp": ts, | |
| "user_email": r["user_email"], | |
| "company_ticker": r["company_ticker"], | |
| "company_name": r["company_name"], | |
| "selected_formats": r["selected_formats"], | |
| "ai_model_used": r["ai_model_used"], | |
| "status": r["status"] | |
| }) | |
| conn.close() | |
| return logs | |
| except Exception as sqle: | |
| print(f"Local SQLite logs retrieve error: {sqle}") | |
| return [] | |