File size: 3,420 Bytes
f6b402d
 
 
 
3665fc5
f6b402d
3665fc5
f6b402d
 
 
 
 
 
3665fc5
f6b402d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3665fc5
f6b402d
3665fc5
 
 
 
 
 
 
 
f6b402d
 
 
 
3665fc5
 
f6b402d
 
 
 
 
 
 
 
 
 
 
3665fc5
f6b402d
 
3665fc5
f6b402d
 
 
 
 
 
3665fc5
f6b402d
 
 
3665fc5
 
 
 
 
 
 
 
 
f6b402d
 
 
 
3665fc5
f6b402d
3665fc5
 
f6b402d
3665fc5
f6b402d
3665fc5
f6b402d
 
 
3665fc5
f6b402d
 
 
 
 
3665fc5
f6b402d
 
 
3665fc5
f6b402d
 
3665fc5
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
import sys
import os
import uvicorn
import re
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from typing import List, Optional

# 🚨 FORCE PYTHON TO FIND THE 'src' FOLDER
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

# Import custom modules
from src.db_connector import Database
from src.rag_manager import RAGSystem 
from src.sql_generator import SQLGenerator

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

class ChatRequest(BaseModel):
    question: str
    history: Optional[List[dict]] = [] 

# --- HELPER: CLEAN AI OUTPUT ---
def clean_sql(sql_text: str) -> str:
    if not sql_text: return ""
    cleaned = re.sub(r"```sql|```", "", sql_text, flags=re.IGNORECASE).strip()
    return cleaned.rstrip(';')

# --- πŸš€ SAFE INITIALIZATION ---
# Initialize as None so the app doesn't crash if DB fails
db = None
rag = None
generator = None
startup_error = None

print("--- πŸš€ SYSTEM STARTUP SEQUENCE ---")
try:
    print("   ...Connecting to Database")
    # ⚠️ IF THIS FAILS, THE APP WILL NOW CATCH IT GRACEFULLY
    db = Database() 
    print("   βœ… Database Connection: SUCCESS")
    
    print("   ...Initializing RAG System")
    rag = RAGSystem(db)
    print("   βœ… RAG System: ONLINE")
    
    print("   ...Loading AI Model")
    generator = SQLGenerator()
    print("   βœ… AI Model: LOADED")
    
except Exception as e:
    startup_error = str(e)
    print(f"   ❌ CRITICAL STARTUP ERROR: {e}")

# --- ROUTES ---
@app.get("/", response_class=HTMLResponse)
async def serve_ui():
    try:
        with open("index.html", "r", encoding="utf-8") as f:
            return f.read()
    except FileNotFoundError:
        return "Error: index.html not found."

@app.post("/chat")
def chat_endpoint(request: ChatRequest):
    # 🚨 CHECK FOR STARTUP ERRORS FIRST
    if rag is None or db is None:
        return {
            "answer": [f"System Error: {startup_error}"],
            "sql": "-- Database Connection Failed",
            "message": f"I cannot connect to the database. Reason: {startup_error}. Please check the Logs tab.",
            "follow_ups": []
        }

    try:
        context = rag.get_relevant_schema(request.question)
        raw_sql, explanation, friendly_msg = generator.generate_sql(request.question, context, request.history)
        
        # Clean SQL
        cleaned_sql = clean_sql(raw_sql)
        
        # Security Check
        if not cleaned_sql.upper().startswith("SELECT"):
             return {"answer": [], "sql": cleaned_sql, "message": "Security Alert: Read-Only Mode.", "follow_ups": []}

        # Run Query
        try:
            results = db.run_query(cleaned_sql)
        except Exception as db_err:
            return {"answer": [f"SQL Error: {str(db_err)}"], "sql": cleaned_sql, "message": "Syntax Error in SQL.", "follow_ups": []}
        
        return {
            "answer": results,
            "sql": cleaned_sql,
            "message": friendly_msg, 
            "follow_ups": []
        }

    except Exception as e:
        return {"answer": [], "sql": "-- Error", "message": f"Processing Error: {str(e)}", "follow_ups": []}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=7860)