Spaces:
Running
Running
File size: 8,733 Bytes
b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 93a9858 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca 5327524 b6da9ca | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | """
File upload loader -- supports CSV, SQLite/DB files, and Excel workbooks.
CSV: single table "data_table" -> WikiSQL-format schema (no FK/PK)
SQLite/DB: copy to temp path, read multi-table schema via PRAGMA -> Spider-format schema
Excel: each sheet -> one table in temp SQLite -> Spider-format schema
The schema string format matches what models were trained on:
CSV -> WikiSQL format (process_wikisql.build_schema_string)
SQLite/Excel -> Spider format (table ( col*:type , ... ) | FK: ...)
"""
import shutil
import sqlite3
import sys
import tempfile
from pathlib import Path
import pandas as pd
_SRC_DIR = Path(__file__).resolve().parent.parent # src/
if str(_SRC_DIR) not in sys.path:
sys.path.insert(0, str(_SRC_DIR))
from process_wikisql import build_schema_string as _wikisql_schema # noqa: E402
TABLE_NAME = "data_table"
_UPLOAD_DB_PATH = Path(tempfile.gettempdir()) / "_uploaded_data.sqlite"
MAX_PREVIEW_ROWS = 500
# ---------------------------------------------------------------------------
# Shared helpers
# ---------------------------------------------------------------------------
def _infer_wikisql_types(df: pd.DataFrame) -> list:
return ["real" if pd.api.types.is_numeric_dtype(dt) else "text" for dt in df.dtypes]
def _lowercase_text_columns(df: pd.DataFrame, types: list) -> pd.DataFrame:
"""WikiSQL-trained models expect lowercase string literals in WHERE clauses."""
df = df.copy()
for col, t in zip(df.columns, types):
if t == "text":
df[col] = df[col].apply(lambda v: v.lower() if isinstance(v, str) else v)
return df
def _sqlite_col_type(declared_type: str) -> str:
"""Map SQLite declared type -> 'number' or 'text' for schema string."""
upper = declared_type.upper()
if any(k in upper for k in ("INT", "REAL", "FLOAT", "NUMERIC", "DECIMAL", "DOUBLE")):
return "number"
return "text"
def _preview_from_db(db_path: str) -> dict:
"""Return preview rows from first table and total row count across all tables."""
conn = sqlite3.connect(db_path)
cur = conn.cursor()
tables = [r[0] for r in cur.execute(
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name"
).fetchall()]
total_rows = 0
first_table_df = None
for tbl in tables:
cnt = cur.execute(f'SELECT COUNT(*) FROM "{tbl}"').fetchone()[0]
total_rows += cnt
if first_table_df is None:
first_table_df = pd.read_sql_query(
f'SELECT * FROM "{tbl}" LIMIT {MAX_PREVIEW_ROWS}', conn
)
conn.close()
if first_table_df is None or first_table_df.empty:
return {"columns": [], "rows": [], "row_count": 0, "truncated": False}
preview_df = first_table_df.astype(object).where(first_table_df.notna(), None)
return {
"columns": list(first_table_df.columns),
"rows": preview_df.values.tolist(),
"row_count": total_rows,
"truncated": total_rows > MAX_PREVIEW_ROWS,
}
def get_table_names(db_path: str) -> list:
"""Return all user table names in a SQLite database (alphabetical order)."""
conn = sqlite3.connect(db_path)
tables = [r[0] for r in conn.execute(
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name"
).fetchall()]
conn.close()
return tables
def get_preview_for_table(db_path: str, table: str) -> dict:
"""Return preview rows (up to MAX_PREVIEW_ROWS) from a specific table."""
conn = sqlite3.connect(db_path)
total = conn.execute(f'SELECT COUNT(*) FROM "{table}"').fetchone()[0]
df = pd.read_sql_query(f'SELECT * FROM "{table}" LIMIT {MAX_PREVIEW_ROWS}', conn)
conn.close()
df = df.astype(object).where(df.notna(), None)
return {
"columns": list(df.columns),
"rows": df.values.tolist(),
"row_count": total,
"truncated": total > MAX_PREVIEW_ROWS,
}
def _build_spider_schema_from_sqlite(db_path: str) -> str:
"""Read schema from a SQLite file and return a Spider-format schema string.
Format: table ( col*:type , col2:type ) | table2 ( ... ) | foreign_keys: t.c = t2.c , ...
"""
conn = sqlite3.connect(db_path)
cur = conn.cursor()
tables = [r[0] for r in cur.execute(
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name"
).fetchall()]
table_parts = []
fk_parts = []
for tbl in tables:
tbl_lower = tbl.lower()
cur.execute(f'PRAGMA table_info("{tbl}")')
cols = cur.fetchall() # (cid, name, type, notnull, default, pk)
col_strs = []
for col in cols:
col_name = col[1].lower()
col_type = _sqlite_col_type(col[2])
pk_marker = "*" if col[5] > 0 else ""
col_strs.append(f"{col_name}{pk_marker}:{col_type}")
table_parts.append(f"{tbl_lower} ( {' , '.join(col_strs)} )")
cur.execute(f'PRAGMA foreign_key_list("{tbl}")')
for fk in cur.fetchall(): # (id, seq, ref_table, from_col, to_col, ...)
ref_table = fk[2].lower()
from_col = fk[3].lower()
to_col = fk[4].lower()
fk_parts.append(f"{tbl_lower}.{from_col} = {ref_table}.{to_col}")
conn.close()
schema = " | ".join(table_parts)
if fk_parts:
schema += " | foreign_keys: " + " , ".join(fk_parts)
return schema
# ---------------------------------------------------------------------------
# CSV loader (unchanged from original, single-table WikiSQL format)
# ---------------------------------------------------------------------------
def load_csv_to_sqlite(file_obj_or_path) -> dict:
"""Load a CSV file into a single-table SQLite DB and return metadata."""
df = pd.read_csv(file_obj_or_path)
header = list(df.columns)
types = _infer_wikisql_types(df)
df = _lowercase_text_columns(df, types)
conn = sqlite3.connect(str(_UPLOAD_DB_PATH))
try:
df.to_sql(TABLE_NAME, conn, index=False, if_exists="replace")
finally:
conn.close()
schema_string = _wikisql_schema(header, types=types)
preview_df = df.head(MAX_PREVIEW_ROWS).astype(object).where(df.head(MAX_PREVIEW_ROWS).notna(), None)
return {
"db_path": str(_UPLOAD_DB_PATH),
"schema_string": schema_string,
"columns": header,
"row_count": len(df),
"rows": preview_df.values.tolist(),
"truncated": len(df) > MAX_PREVIEW_ROWS,
}
# ---------------------------------------------------------------------------
# SQLite / .db file loader (multi-table, Spider format)
# ---------------------------------------------------------------------------
def load_sqlite_file(file_obj) -> dict:
"""Copy an uploaded .sqlite/.db file to temp location and build schema."""
# Write uploaded bytes to temp file
with open(str(_UPLOAD_DB_PATH), "wb") as out:
shutil.copyfileobj(file_obj, out)
schema_string = _build_spider_schema_from_sqlite(str(_UPLOAD_DB_PATH))
preview = _preview_from_db(str(_UPLOAD_DB_PATH))
return {
"db_path": str(_UPLOAD_DB_PATH),
"schema_string": schema_string,
**preview,
}
# ---------------------------------------------------------------------------
# Excel loader (each sheet = one table, Spider format)
# ---------------------------------------------------------------------------
def load_excel_to_sqlite(file_obj) -> dict:
"""Load an Excel workbook: each sheet becomes a table in the temp SQLite DB."""
xl = pd.ExcelFile(file_obj)
sheet_names = xl.sheet_names
conn = sqlite3.connect(str(_UPLOAD_DB_PATH))
try:
for sheet in sheet_names:
df = xl.parse(sheet)
# Sanitize table name: lowercase, spaces to underscores
tbl_name = sheet.lower().replace(" ", "_")
df.to_sql(tbl_name, conn, index=False, if_exists="replace")
conn.commit()
finally:
conn.close()
schema_string = _build_spider_schema_from_sqlite(str(_UPLOAD_DB_PATH))
preview = _preview_from_db(str(_UPLOAD_DB_PATH))
return {
"db_path": str(_UPLOAD_DB_PATH),
"schema_string": schema_string,
**preview,
}
# ---------------------------------------------------------------------------
# Model input builder
# ---------------------------------------------------------------------------
def build_input(question: str, schema_string: str) -> str:
"""Build model input string from a pre-built schema string (any format)."""
return f"question: {question.strip()} | schema: {schema_string}"
|