Compare commits
2 Commits
14d29724f1
...
eada1a829b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eada1a829b | ||
|
|
1c500328d1 |
@@ -27,6 +27,19 @@ def record_sql_audit(query, success, error_message=None):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
current_app.logger.error(f"Failed to record SQL audit: {e}")
|
current_app.logger.error(f"Failed to record SQL audit: {e}")
|
||||||
|
|
||||||
|
def record_llm_audit(prompt, response, model, success, error_message=None):
|
||||||
|
"""Records an LLM interaction in the audit table."""
|
||||||
|
try:
|
||||||
|
person_id = getattr(current_user, 'id', None)
|
||||||
|
ip_address = get_client_ip()
|
||||||
|
sql = """
|
||||||
|
INSERT INTO llm_audit (person_id, prompt, response, model, ip_address, success, error_message)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
||||||
|
"""
|
||||||
|
db.execute(sql, [person_id, prompt, response, model, ip_address, success, error_message], commit=True)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error(f"Failed to record LLM audit: {e}")
|
||||||
|
|
||||||
def _execute_sql(query):
|
def _execute_sql(query):
|
||||||
"""Executes arbitrary SQL query, returning results, columns, and error."""
|
"""Executes arbitrary SQL query, returning results, columns, and error."""
|
||||||
results, columns, error = None, [], None
|
results, columns, error = None, [], None
|
||||||
@@ -76,10 +89,11 @@ def _generate_sql_from_natural_language(natural_query):
|
|||||||
api_url = f"https://generativelanguage.googleapis.com/v1beta/models/{gemni_model}:generateContent?key={api_key}"
|
api_url = f"https://generativelanguage.googleapis.com/v1beta/models/{gemni_model}:generateContent?key={api_key}"
|
||||||
headers = {'Content-Type': 'application/json'}
|
headers = {'Content-Type': 'application/json'}
|
||||||
|
|
||||||
|
prompt = natural_query
|
||||||
try:
|
try:
|
||||||
# Get and format schema
|
# Get and format schema
|
||||||
schema_info = _get_schema_info()
|
schema_info = db.schema.get_schema_info()
|
||||||
schema_string = _generate_create_script(schema_info)
|
schema_string = db.schema.generate_create_script(schema_info)
|
||||||
|
|
||||||
prompt = f"""Given the following database schema:
|
prompt = f"""Given the following database schema:
|
||||||
```sql
|
```sql
|
||||||
@@ -128,14 +142,20 @@ Return ONLY the SQL query, without any explanation or surrounding text/markdown.
|
|||||||
filtered_lines = [line for line in sql_lines if not line.strip().startswith('--')]
|
filtered_lines = [line for line in sql_lines if not line.strip().startswith('--')]
|
||||||
final_sql = "\n".join(filtered_lines).strip()
|
final_sql = "\n".join(filtered_lines).strip()
|
||||||
|
|
||||||
return final_sql, None
|
generated_sql, error = final_sql, None
|
||||||
|
record_llm_audit(prompt, generated_sql, gemni_model, True)
|
||||||
|
return generated_sql, error
|
||||||
|
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
current_app.logger.error(f"Gemini API request error: {e}")
|
current_app.logger.error(f"Gemini API request error: {e}")
|
||||||
return None, f"Error communicating with API: {e}"
|
error_msg = f"Error communicating with API: {e}"
|
||||||
|
record_llm_audit(prompt, None, gemni_model, False, error_msg)
|
||||||
|
return None, error_msg
|
||||||
except (KeyError, IndexError, Exception) as e:
|
except (KeyError, IndexError, Exception) as e:
|
||||||
current_app.logger.error(f"Error processing Gemini API response: {e} - Response: {response_data if 'response_data' in locals() else 'N/A'}")
|
current_app.logger.error(f"Error processing Gemini API response: {e} - Response: {response_data if 'response_data' in locals() else 'N/A'}")
|
||||||
return None, f"Error processing API response: {e}"
|
error_msg = f"Error processing API response: {e}"
|
||||||
|
record_llm_audit(prompt, None, gemni_model, False, error_msg)
|
||||||
|
return None, error_msg
|
||||||
|
|
||||||
|
|
||||||
# --- Routes ---
|
# --- Routes ---
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 199 KiB |
@@ -32,8 +32,8 @@
|
|||||||
class="flex-grow p-2 border border-gray-300 rounded-l-md shadow-sm focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent"
|
class="flex-grow p-2 border border-gray-300 rounded-l-md shadow-sm focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent"
|
||||||
placeholder="e.g., 'Show me the number of workouts per person'">
|
placeholder="e.g., 'Show me the number of workouts per person'">
|
||||||
<button type="button" hx-post="{{ url_for('sql_explorer.generate_sql') }}"
|
<button type="button" hx-post="{{ url_for('sql_explorer.generate_sql') }}"
|
||||||
hx-include="[name='natural_query']" hx-target="#query" hx-swap="innerHTML"
|
hx-include="[name='natural_query']" hx-indicator="#sql-spinner" hx-swap="none"
|
||||||
hx-indicator="#sql-spinner"
|
_="on htmx:afterRequest set #query.value to detail.xhr.responseText then send input to #query"
|
||||||
class="bg-purple-600 text-white p-2.5 rounded-r-md hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-opacity-50 inline-flex items-center">
|
class="bg-purple-600 text-white p-2.5 rounded-r-md hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-opacity-50 inline-flex items-center">
|
||||||
Generate SQL
|
Generate SQL
|
||||||
<span id="sql-spinner" class="htmx-indicator ml-2">
|
<span id="sql-spinner" class="htmx-indicator ml-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user