-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathai_engine.py
More file actions
137 lines (125 loc) · 4.55 KB
/
Copy pathai_engine.py
File metadata and controls
137 lines (125 loc) · 4.55 KB
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
try:
from openai import OpenAI
except Exception:
OpenAI = None
try:
import google.generativeai as genai
except Exception:
genai = None
import sqlite3
import os
import pandas as pd
import typing
openai_client = None
gemini_model = None
def _init_openai():
global openai_client
if openai_client is not None:
return
key = os.environ.get("OPENAI_API_KEY")
if OpenAI and key:
try:
openai_client = OpenAI(api_key=key)
except Exception:
openai_client = None
def _init_gemini():
global gemini_model
if gemini_model is not None:
return
key = os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY")
if not key:
try:
con = get_db()
try:
row = con.execute("SELECT gemini_key FROM ai_settings WHERE id=1").fetchone()
finally:
con.close()
if row and row[0]:
key = row[0]
except Exception:
key = None
if genai and key:
try:
genai.configure(api_key=key)
gemini_model = genai.GenerativeModel("gemini-2.0-flash")
except Exception:
gemini_model = None
DB_PATH = "database/trading.db"
def get_db():
return sqlite3.connect(DB_PATH)
def question_to_sql(question, provider: str = "auto"):
con = get_db()
tables = [r[0] for r in con.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()]
schema_parts = []
for t in tables:
cols = con.execute(f"PRAGMA table_info('{t}')").fetchall()
col_list = ", ".join([c[1] for c in cols])
schema_parts.append(f"{t}({col_list})")
con.close()
schema = "\n".join(schema_parts)
prompt = f"You are an expert SQLite developer.\n\nDatabase schema:\n{schema}\n\nConvert this question into valid, read-only SQLite SQL. Use SELECT only. Return only SQL.\n\nQuestion: {question}"
prov = (provider or "auto").lower()
if prov == "openai":
_init_openai()
if not openai_client:
return "SELECT 'OpenAI API key not configured' AS error"
response = openai_client.chat.completions.create(model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}])
return response.choices[0].message.content.strip()
if prov == "gemini":
_init_gemini()
if not gemini_model:
return "SELECT 'Gemini API key not configured' AS error"
try:
resp = gemini_model.generate_content(prompt)
except Exception as e:
msg = str(e)
if "quota" in msg.lower() or "429" in msg:
_init_openai()
if openai_client:
response = openai_client.chat.completions.create(model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}])
return response.choices[0].message.content.strip()
return "SELECT 'Gemini quota exceeded, please check plan and billing' AS error"
safe_msg = msg.replace("'", " ")
return "SELECT 'Gemini error: " + safe_msg + "' AS error"
text = ""
try:
text = resp.text or ""
except Exception:
text = ""
return text.strip() or "SELECT 'Gemini did not return SQL' AS error"
_init_openai()
if openai_client:
response = openai_client.chat.completions.create(model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}])
return response.choices[0].message.content.strip()
_init_gemini()
if gemini_model:
resp = gemini_model.generate_content(prompt)
text = ""
try:
text = resp.text or ""
except Exception:
text = ""
return text.strip() or "SELECT 'Gemini did not return SQL' AS error"
return "SELECT 'No AI provider configured' AS error"
def run_sql(sql: str) -> pd.DataFrame:
s = (sql or "").strip().lower()
if not s.startswith("select"):
return pd.DataFrame({"error": ["Only SELECT queries are allowed"]})
con = get_db()
try:
df = pd.read_sql_query(sql, con)
return df
except Exception as e:
return pd.DataFrame({"error": [str(e)]})
finally:
con.close()
def explain_result(df: pd.DataFrame) -> str:
if "error" in df.columns and len(df) == 1:
return str(df.iloc[0]["error"])
rows = len(df)
cols = list(df.columns)
if rows == 0:
return "No rows found."
head = df.head(5)
preview = head.to_string(index=False)
return f"Rows: {rows}\nColumns: {', '.join(cols)}\nPreview:\n{preview}"