AISqlQueryFastApi / backend /app /services /sql_generator.py
Vivek0912's picture
test
70cfb8f verified
Raw
History Blame Contribute Delete
5.52 kB
from langchain_community.utilities import SQLDatabase
from langchain.chains import create_sql_query_chain
from langchain_openai import ChatOpenAI # or your LLaMA adapter
from config.settings import settings
from langchain.prompts import PromptTemplate, ChatPromptTemplate
from app.db.schema_reader import get_schema
from app.db.db_connector import get_db_engine
from app.db.db_connector import get_connection
import re
# llm = ChatOpenAI(model="gpt-4o-mini", temperature=0, api_key=settings.OPENAI_API_KEY)
print(f"OPENAI_API_KEY: {settings.OPENAI_API_KEY}")
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0, api_key=settings.OPENAI_API_KEY)
def detect_foreign_key_relationships_only(schema):
"""Only detect foreign key relationships without any assumptions about data types"""
relationships = []
for table_name, columns in schema.items():
for column in columns:
# Look for foreign key patterns: *_id columns
if column.endswith('_id') and column != 'id':
# Extract potential referenced table name
ref_name = column[:-3] # Remove '_id'
# Check for exact match or plural/singular variations
possible_refs = [ref_name, ref_name + 's', ref_name[:-1] if ref_name.endswith('s') else ref_name + 's']
for possible_ref in possible_refs:
if possible_ref in schema:
relationships.append({
'from_table': table_name,
'from_column': column,
'to_table': possible_ref,
'to_column': 'id'
})
break
return relationships
def generate_pure_schema_context(schema):
"""Generate schema context without any assumptions - let AI figure out everything"""
# Just provide the raw schema structure
context = "DATABASE SCHEMA:\n\n"
# List all tables and their columns
context += "TABLES AND COLUMNS:\n"
for table_name, columns in schema.items():
context += f"- {table_name}: {', '.join(columns)}\n"
# Detect only foreign key relationships (no assumptions about data types)
relationships = detect_foreign_key_relationships_only(schema)
# Show detected relationships
if relationships:
context += "\nDETECTED FOREIGN KEY RELATIONSHIPS:\n"
for rel in relationships:
context += f"- {rel['from_table']}.{rel['from_column']} β†’ {rel['to_table']}.{rel['to_column']}\n"
return context
def generate_sql_query(user_question: str):
schema = get_schema()
# Generate pure schema context - no assumptions, let AI figure it out
schema_context = generate_pure_schema_context(schema)
prompt = ChatPromptTemplate.from_template("""
You are an expert SQLite query generator with advanced analytical capabilities.
{schema_context}
INTELLIGENT ANALYSIS INSTRUCTIONS:
1. EXAMINE the schema above - look at table names and column names to understand what data each table contains
2. ANALYZE the column names to infer what type of information is stored (names, addresses, amounts, dates, etc.)
3. USE the detected foreign key relationships to understand how tables connect
4. For queries needing data from multiple tables, follow the relationship paths and use JOINs
5. INFER from context - if user asks about location and you see city/address columns, use those tables
6. THINK logically about which tables would contain the requested information
QUERY GENERATION STRATEGY:
- Read the user's question carefully
- Identify what data they want (customers, transactions, locations, etc.)
- Look at the schema to find which tables likely contain that data
- Check if multiple tables are needed and use the foreign key relationships
- Generate appropriate SQL with JOINs if data spans multiple tables
RESPONSE FORMAT:
- Return ONLY valid SQLite syntax
- No explanations, comments, or extra text
- Use proper JOIN syntax when needed
- If you cannot determine how to query the available schema, respond: "I cannot generate this query."
Example thinking process:
- User asks "customers in New York" β†’ Look for tables with customer info AND location info β†’ Use relationships to JOIN them
- User asks "transactions over $1000" β†’ Look for tables with transaction/amount data
- User asks "branch managers" β†’ Look for tables with employee/staff info and management roles
User question: {question}
""")
messages = prompt.format_messages(schema_context=schema_context, question=user_question)
sql_query = llm.invoke(messages).content.strip()
# If the LLM says it cannot generate a query, treat as normal chat
if sql_query.lower().startswith("i cannot generate this query"):
# Use the LLM as a chatbot for normal conversation
chat_prompt = (
"You are an AI assistant whose primary role is to generate SQL queries from natural language questions. "
"If the user's question is not related to SQL or databases, respond conversationally as a helpful assistant."
f"\n\nUser question: {user_question}"
)
chat_response = llm.invoke([{"role": "user", "content": chat_prompt}]).content.strip()
return {"chat_message": chat_response}
return sql_query