sql-agent-demo / app.py
delcenjo's picture
Upload app.py with huggingface_hub
84868a0 verified
Raw
History Blame Contribute Delete
3.76 kB
import json
import os
import re
import time
import gradio as gr
from huggingface_hub import InferenceClient
from sqlagent import database
from sqlagent.seed import seed_database
DB_PATH = "/tmp/shop.db"
MODEL = "Qwen/Qwen2.5-7B-Instruct"
MAX_QUESTION_CHARS = 400
client = InferenceClient()
def ensure_db():
if not os.path.exists(DB_PATH):
connection = database.connect(DB_PATH)
seed_database(connection)
connection.close()
ensure_db()
def schema_text():
with database.connect(DB_PATH, read_only=True) as connection:
lines = []
for table in database.list_tables(connection):
cols = database.table_schema(connection, table)
joined = ", ".join(f"{c['column']} {c['type']}" for c in cols)
lines.append(f"{table}({joined})")
return "\n".join(lines)
def ask(messages, max_tokens=350):
last_error = None
for attempt in range(3):
try:
response = client.chat_completion(messages=messages, model=MODEL, max_tokens=max_tokens)
return response.choices[0].message.content.strip()
except Exception as error:
last_error = error
time.sleep(1.5 * (attempt + 1))
raise last_error
def extract_sql(text):
fence = re.search(r"```(?:sql)?\s*(.+?)```", text, re.S)
body = fence.group(1) if fence else text
match = re.search(r"(?is)\b(select|with)\b.*", body)
sql = match.group(0) if match else body
sql = sql.split(";")[0]
sql = sql.split("\n\n")[0]
return sql.strip()
def answer(question):
question = (question or "").strip()
if not question:
return "Ask a question about the shop database."
if len(question) > MAX_QUESTION_CHARS:
return f"Please keep the question under {MAX_QUESTION_CHARS} characters."
try:
schema = schema_text()
raw_sql = ask([
{"role": "system", "content": "You write SQLite SQL. Given the schema, write ONE read-only SELECT query that answers the question. Return only the SQL query: no explanation, no markdown, no comments."},
{"role": "user", "content": f"Schema:\n{schema}\n\nQuestion: {question}"},
], max_tokens=200)
sql = extract_sql(raw_sql)
with database.connect(DB_PATH, read_only=True) as connection:
rows = database.run_select(connection, sql)
results = json.dumps(rows, default=str)[:2000]
final = ask([
{"role": "system", "content": "Answer the question concisely using the query results. State the figures clearly."},
{"role": "user", "content": f"Question: {question}\nResults: {results}"},
], max_tokens=300)
return f"{final}\n\n---\nSQL used:\n{sql}"
except Exception:
return "The service is busy or unavailable right now. Please try again in a moment."
demo = gr.Interface(
fn=answer,
inputs=gr.Textbox(lines=2, label="Ask a question about the shop database",
placeholder="Which product category brings the most revenue?"),
outputs=gr.Textbox(lines=10, label="Answer"),
title="SQL Question Answering Agent",
description=(
"Ask a question in plain English about a small sample shop database "
"(customers, products, orders). The system writes a read-only SQL query, "
"runs it and answers from the results, showing the SQL it used."
),
article="Code: https://github.com/delcenjo/llm-sql-agent",
cache_examples=False,
examples=[
["Which product category brings the most revenue?"],
["How many customers are from Spain?"],
["List the top 3 products by total quantity sold."],
],
)
if __name__ == "__main__":
demo.launch(ssr_mode=False)