Spaces:
Sleeping
Sleeping
| 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) | |