Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -214,110 +214,77 @@ SQL:"""
|
|
214 |
# --- نقطة النهاية الرئيسية ---
|
215 |
@app.route('/api/query', methods=['POST'])
|
216 |
def handle_query():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
try:
|
218 |
-
|
219 |
-
|
220 |
-
return jsonify({
|
221 |
-
"status": "error",
|
222 |
-
"message": "Please provide both 'text' and 'cam_mac' in the request body",
|
223 |
-
"data": None
|
224 |
-
}), 400
|
225 |
-
|
226 |
-
natural_query = data['text']
|
227 |
-
cam_mac = data['cam_mac']
|
228 |
-
print(f"Natural query from {cam_mac}: {natural_query}")
|
229 |
|
230 |
-
#
|
231 |
-
if
|
232 |
-
return jsonify({
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
|
238 |
-
# توليد استعلام SQL
|
239 |
-
sql_query = generate_sql_gemini(natural_query, cam_mac)
|
240 |
-
if not sql_query:
|
241 |
-
return jsonify({
|
242 |
-
"status": "error",
|
243 |
-
"message": "Failed to generate SQL query",
|
244 |
-
"data": None
|
245 |
-
}), 500
|
246 |
-
|
247 |
-
print(f"Generated SQL: {sql_query}")
|
248 |
-
|
249 |
-
# التأكد من أن الاستعلام SELECT فقط
|
250 |
-
if not re.match(r'^\s*SELECT', sql_query, re.IGNORECASE):
|
251 |
-
return jsonify({
|
252 |
-
"status": "error",
|
253 |
-
"message": "Only SELECT queries are allowed",
|
254 |
-
"data": None
|
255 |
-
}), 403
|
256 |
-
|
257 |
-
# تنفيذ الاستعلام
|
258 |
-
conn = get_db_connection()
|
259 |
-
if not conn:
|
260 |
-
return jsonify({
|
261 |
-
"status": "error",
|
262 |
-
"message": "Database connection failed",
|
263 |
-
"data": None
|
264 |
-
}), 500
|
265 |
-
|
266 |
-
try:
|
267 |
-
with conn.cursor() as cursor:
|
268 |
-
cursor.execute(sql_query)
|
269 |
-
|
270 |
-
# إذا كان الاستعلام لا يعيد بيانات (مثل SELECT COUNT)
|
271 |
-
if cursor.description is None:
|
272 |
-
return jsonify({
|
273 |
-
"status": "success",
|
274 |
-
"message": "Query executed successfully",
|
275 |
-
"data": []
|
276 |
-
}), 200
|
277 |
-
|
278 |
-
columns = [desc[0] for desc in cursor.description]
|
279 |
-
rows = cursor.fetchall()
|
280 |
-
|
281 |
-
# تحويل النتائج إلى قاموس
|
282 |
-
result_data = []
|
283 |
-
for row in rows:
|
284 |
-
row_dict = {}
|
285 |
-
for i, col in enumerate(columns):
|
286 |
-
# تحويل أنواع البيانات غير القابلة للتسلسل
|
287 |
-
if isinstance(row[i], (datetime.date, datetime.time, datetime.datetime)):
|
288 |
-
row_dict[col] = row[i].isoformat()
|
289 |
-
elif isinstance(row[i], decimal.Decimal):
|
290 |
-
row_dict[col] = float(row[i])
|
291 |
-
else:
|
292 |
-
row_dict[col] = row[i]
|
293 |
-
result_data.append(row_dict)
|
294 |
-
|
295 |
-
return jsonify({
|
296 |
-
"status": "success",
|
297 |
-
"message": "Query executed successfully",
|
298 |
-
"data": result_data
|
299 |
-
}), 200
|
300 |
-
|
301 |
-
except Exception as e:
|
302 |
-
print(f"SQL execution error: {e}")
|
303 |
-
return jsonify({
|
304 |
-
"status": "error",
|
305 |
-
"message": f"Database error: {str(e)}",
|
306 |
-
"data": None,
|
307 |
-
"generated_sql": sql_query
|
308 |
-
}), 500
|
309 |
-
|
310 |
-
finally:
|
311 |
-
if conn:
|
312 |
-
conn.close()
|
313 |
-
|
314 |
except Exception as e:
|
315 |
-
print(f"
|
316 |
return jsonify({
|
317 |
-
"
|
318 |
-
"
|
319 |
-
"data": None
|
320 |
}), 500
|
|
|
|
|
|
|
|
|
|
|
321 |
|
322 |
@app.route('/')
|
323 |
def home():
|
|
|
214 |
# --- نقطة النهاية الرئيسية ---
|
215 |
@app.route('/api/query', methods=['POST'])
|
216 |
def handle_query():
|
217 |
+
data = request.get_json()
|
218 |
+
if not data or 'text' not in data or 'cam_mac' not in data:
|
219 |
+
return jsonify({"error": "Please send 'text' and 'cam_mac' in the request body"}), 400
|
220 |
+
|
221 |
+
natural_query = data['text']
|
222 |
+
cam_mac = data['cam_mac']
|
223 |
+
print(f"Natural query from {cam_mac}: {natural_query}")
|
224 |
+
|
225 |
+
# التحقق من صحة cam_mac
|
226 |
+
if not validate_cam_mac(cam_mac):
|
227 |
+
return jsonify({"error": "Invalid cam_mac address"}), 403
|
228 |
+
|
229 |
+
sql_query = generate_sql_gemini(natural_query, cam_mac)
|
230 |
+
|
231 |
+
if not sql_query:
|
232 |
+
return jsonify({"error": "Failed to generate SQL query"}), 500
|
233 |
+
|
234 |
+
print(f"Generated SQL: {sql_query}")
|
235 |
+
|
236 |
+
if not sql_query.upper().strip().startswith("SELECT"):
|
237 |
+
return jsonify({"error": "Only SELECT queries are allowed"}), 403
|
238 |
+
|
239 |
+
conn = get_db_connection()
|
240 |
+
if not conn:
|
241 |
+
return jsonify({"error": "Database connection failed"}), 500
|
242 |
+
|
243 |
+
cursor = None
|
244 |
try:
|
245 |
+
cursor = conn.cursor()
|
246 |
+
cursor.execute(sql_query)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
247 |
|
248 |
+
# إذا كان الاستعلام لا يعيد أي أعمدة (مثل SELECT COUNT(*))
|
249 |
+
if cursor.description is None:
|
250 |
+
return jsonify({"data": []}), 200
|
251 |
+
|
252 |
+
columns = [desc[0] for desc in cursor.description]
|
253 |
+
rows = cursor.fetchall()
|
254 |
+
|
255 |
+
# تحويل النتائج إلى JSON قابل للتسلسل
|
256 |
+
result = []
|
257 |
+
for row in rows:
|
258 |
+
row_dict = {}
|
259 |
+
for i, col in enumerate(columns):
|
260 |
+
# معالجة أنواع البيانات غير القابلة للتسلسل مباشرةً
|
261 |
+
value = row[i]
|
262 |
+
if isinstance(value, (datetime.date, datetime.datetime)):
|
263 |
+
value = value.isoformat()
|
264 |
+
elif isinstance(value, decimal.Decimal):
|
265 |
+
value = float(value)
|
266 |
+
row_dict[col] = value
|
267 |
+
result.append(row_dict)
|
268 |
+
|
269 |
+
# إرجاع الرد مع ضمان تنسيق JSON صحيح
|
270 |
+
response_data = {"data": result}
|
271 |
+
return Response(
|
272 |
+
json.dumps(response_data, ensure_ascii=False),
|
273 |
+
status=200,
|
274 |
+
mimetype='application/json; charset=utf-8'
|
275 |
+
)
|
276 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
except Exception as e:
|
278 |
+
print(f"SQL execution error: {e}")
|
279 |
return jsonify({
|
280 |
+
"error": str(e),
|
281 |
+
"generated_sql": sql_query
|
|
|
282 |
}), 500
|
283 |
+
finally:
|
284 |
+
if cursor:
|
285 |
+
cursor.close()
|
286 |
+
if conn:
|
287 |
+
conn.close()
|
288 |
|
289 |
@app.route('/')
|
290 |
def home():
|