import sqlite3 import pandas as pd import gradio as gr from init_db import ensure_database from nl_to_sql import parse_question_to_sql, format_answer DB_PATH = "demo_store.db" ensure_database(DB_PATH) def execute_read_only_sql(sql: str): sql_clean = sql.strip().lower() banned = ["insert ", "update ", "delete ", "drop ", "alter ", "create ", "replace ", "truncate ", "attach ", "pragma ", "vacuum "] if not sql_clean.startswith("select"): raise ValueError("Only read-only SELECT queries are allowed in this demo.") if any(word in sql_clean for word in banned): raise ValueError("Unsafe SQL detected. This demo only allows SELECT queries.") conn = sqlite3.connect(DB_PATH) try: df = pd.read_sql_query(sql, conn) finally: conn.close() return df SYSTEM_TEXT = """ You can ask questions like: - Show all customers - Show orders from March 2026 - What is the total revenue by country? - Top 5 products by revenue - Average order value by customer - How many orders are delayed? """.strip() def answer_question(message, history): sql, notes = parse_question_to_sql(message) try: df = execute_read_only_sql(sql) answer = format_answer(message, sql, df, notes) except Exception as e: answer = f"""I could not run that query. Reason: {e} SQL candidate: ```sql {sql} ```""" return answer with gr.Blocks(title="NL → SQL Demo") as demo: gr.Markdown("# Natural language → SQL chatbot") gr.Markdown( "Ask a business question in plain English. The app converts it into a SQLite query and executes it against a demo store database." ) gr.Markdown("""## Demo schema - `customers(id, name, country, segment)` - `products(id, name, category, price)` - `orders(id, customer_id, order_date, status, shipping_days)` - `order_items(id, order_id, product_id, quantity, unit_price)`""") chatbot = gr.ChatInterface( fn=answer_question, examples=[ "Show all customers", "What is the total revenue by country?", "Top 5 products by revenue", "Show orders from March 2026", "Average order value by customer", "How many orders are delayed?", "Show revenue by month", "List products in the Electronics category", ], ) gr.Markdown("""### Notes - This starter uses simple rule-based parsing for reliability and zero external dependencies. - It is deliberately **read-only**: only `SELECT` statements are executed. - You can later swap `parse_question_to_sql()` for an LLM-based implementation while keeping the same UI.""") if __name__ == "__main__": demo.launch()