import re import os import gradio as gr from transformers import AutoModelForSeq2SeqLM, AutoTokenizer import torch import time MODEL_ID = "RealMati/text2sql-wikisql-v5" print(f"Loading model: {MODEL_ID}") tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) model = AutoModelForSeq2SeqLM.from_pretrained(MODEL_ID) model.eval() print("Model loaded.") css_path = os.path.join(os.path.dirname(__file__), "style.css") with open(css_path, "r") as f: CSS = f.read() SQL_KEYWORDS = [ "SELECT", "FROM", "WHERE", "AND", "OR", "NOT", "IN", "LIKE", "JOIN", "LEFT", "RIGHT", "INNER", "OUTER", "ON", "AS", "GROUP", "BY", "ORDER", "HAVING", "LIMIT", "OFFSET", "DISTINCT", "COUNT", "SUM", "AVG", "MIN", "MAX", "BETWEEN", "EXISTS", "UNION", "ALL", "ANY", "CASE", "WHEN", "THEN", "ELSE", "END", "IS", "NULL", "ASC", "DESC", ] def postprocess_sql(sql): sql = sql.strip() sql = re.sub(r"|||", "", sql) sql = re.sub(r"\s+", " ", sql) for kw in SQL_KEYWORDS: sql = re.sub(rf"\b{re.escape(kw.lower())}\b", kw, sql, flags=re.IGNORECASE) return sql.strip() def predict(question, schema, num_beams, max_length): if not question or not question.strip(): return ( "-- Enter a question and schema, then click Generate SQL", "", ) input_text = f"translate to SQL: {question}" if schema and schema.strip(): input_text += f" | schema: {schema.strip()}" inputs = tokenizer(input_text, return_tensors="pt", max_length=512, truncation=True) t0 = time.time() with torch.no_grad(): outputs = model.generate( **inputs, max_length=int(max_length), num_beams=int(num_beams), early_stopping=True, do_sample=False, ) latency = time.time() - t0 raw = tokenizer.decode(outputs[0], skip_special_tokens=True) sql = postprocess_sql(raw) perf = f"Inference: {latency:.2f}s | Beams: {int(num_beams)} | Tokens: {inputs['input_ids'].shape[1]}" return sql, perf theme = gr.themes.Base( primary_hue="blue", secondary_hue="purple", neutral_hue="gray", font=gr.themes.GoogleFont("Inter"), font_mono=gr.themes.GoogleFont("Fira Code"), ).set( body_background_fill="#0d1117", body_text_color="#e2e8f0", block_background_fill="#161b22", block_border_color="#1f2937", block_border_width="1px", block_label_text_color="#d1d5db", block_title_text_color="#f3f4f6", block_radius="12px", block_shadow="none", input_background_fill="#111827", input_border_color="#1f2937", input_border_width="1px", input_placeholder_color="#4b5563", input_radius="8px", slider_color="#3b82f6", button_primary_background_fill="linear-gradient(135deg, #3b82f6, #8b5cf6)", button_primary_text_color="#ffffff", button_secondary_background_fill="#111827", button_secondary_text_color="#d1d5db", button_secondary_border_color="#1f2937", border_color_primary="#1f2937", color_accent_soft="#111827", ) with gr.Blocks(title="Text-to-SQL V5 | Direct SQL Output") as demo: gr.HTML("""

Text-to-SQL V5

T5-base (220M) Seq2Seq WikiSQL 80K+ Direct SQL Output
Question T5 Encoder-Decoder SQL Query
""") with gr.Tabs(): with gr.Tab("Demo"): with gr.Row(equal_height=False): with gr.Column(scale=1): question = gr.Textbox( label="Natural Language Question", placeholder="e.g. What is terrence ross' nationality?", lines=2, ) schema = gr.Textbox( label="Database Schema (optional)", placeholder="table_name: col1, col2, col3, ...", lines=2, ) gr.HTML('

Format: table: col1, col2, col3

') with gr.Row(): beams = gr.Slider(minimum=1, maximum=10, value=5, step=1, label="Beam Size") max_len = gr.Slider(minimum=64, maximum=512, value=256, step=64, label="Max Length") btn = gr.Button("Generate SQL", variant="primary", elem_classes=["generate-btn"], size="lg") with gr.Column(scale=1): sql_out = gr.Textbox( label="Generated SQL", value="-- Enter a question, then click Generate SQL", lines=4, elem_classes=["sql-output"], ) latency_out = gr.Textbox(label="Performance", value="", lines=1, elem_classes=["decode-box"]) btn.click(fn=predict, inputs=[question, schema, beams, max_len], outputs=[sql_out, latency_out]) question.submit(fn=predict, inputs=[question, schema, beams, max_len], outputs=[sql_out, latency_out]) gr.Markdown("#### Examples") gr.Examples( examples=[ ["What is terrence ross' nationality", "players: Player, No., Nationality, Position, Years in Toronto, School/Club Team", 5, 256], ["how many schools or teams had jalen rose", "players: Player, No., Nationality, Position, Years in Toronto, School/Club Team", 5, 256], ["What was the date of the race in Misano?", "races: No, Date, Round, Circuit, Pole Position, Fastest Lap, Race winner, Report", 5, 256], ["What was the number of race that Kevin Curtain won?", "races: No, Date, Round, Circuit, Pole Position, Fastest Lap, Race winner, Report", 5, 256], ["Where was Assen held?", "races: No, Date, Round, Circuit, Pole Position, Fastest Lap, Race winner, Report", 5, 256], ["How many different positions did Sherbrooke Faucons (qmjhl) provide in the draft?", "draft: Pick, Player, Position, Nationality, NHL team, College/junior/club team", 5, 256], ["What are the nationalities of the player picked from Thunder Bay Flyers (ushl)", "draft: Pick, Player, Position, Nationality, NHL team, College/junior/club team", 5, 256], ["How many different nationalities do the players of New Jersey Devils come from?", "draft: Pick, Player, Position, Nationality, NHL team, College/junior/club team", 5, 256], ["What's Dorain Anneck's pick number?", "draft: Pick, Player, Position, Nationality, NHL team, College/junior/club team", 5, 256], ], inputs=[question, schema, beams, max_len], outputs=[sql_out, latency_out], fn=predict, cache_examples=False, ) with gr.Tab("How It Works"): gr.HTML("""

Architecture

A T5-base encoder-decoder fine-tuned on WikiSQL. This version generates SQL directly as free-form text, unlike V6 which outputs structured tokens. The model learns to produce syntactically correct SQL from natural language questions.

Input Format

Question and optional schema concatenated:

translate to SQL: {question} | schema: {table}: {col1}, {col2}

Output Format

The model directly outputs SQL text:

SELECT Nationality FROM players WHERE Player = 'Terrence Ross'

Post-processing normalizes whitespace and uppercases SQL keywords.

V5 vs V6 Comparison

AspectV5 (Direct SQL)V6 (Structured)
OutputRaw SQL stringSEL/AGG/CONDS tokens
Schema dependencyOptionalRequired (for index mapping)
FlexibilityCan produce any SQLLimited to WikiSQL operations
ReliabilityMay produce invalid SQLGuaranteed valid structure
GeneralizationMemorizes column namesSchema-agnostic indices
""") with gr.Tab("Model & Training"): gr.HTML("""
220M
Parameters
80K+
Training Examples
T5-base
Architecture
WikiSQL
Dataset

Model

  • Base: T5-base (encoder-decoder)
  • Tokenizer: SentencePiece (32K vocab)
  • Max input: 512 tokens
  • Max output: 256 tokens
  • Decoding: Beam search (5 beams)
  • Framework: Transformers + PyTorch

Training

  • Dataset: WikiSQL (Zhong et al., 2017)
  • Train: ~56,355 examples
  • Dev: ~8,421 examples
  • Test: ~15,878 examples
  • Output: Direct SQL strings
  • Prefix: translate to SQL:

WikiSQL Dataset

80,654 hand-annotated SQL queries across 24,241 Wikipedia tables. Single-table queries with SELECT, aggregation, and WHERE conditions.

github.com/salesforce/WikiSQL

Limitations

  • Single-table only — no JOINs or subqueries
  • May hallucinate column names not in schema
  • No syntax guarantee — free-form output can be invalid
  • AND-only conditions
""") gr.HTML(""" """) demo.launch(theme=theme, css=CSS)