Spaces:
Running
Running
__doc__ = """ | |
This FastAPI app uses gradio components with SQL code input | |
and HTML table output. The query is executed using DuckDB. | |
The query results are shown in an iframe where the table | |
is styled and made interactive using Datatables.net scripts. | |
""" | |
import gradio as gr | |
import pandas as pd | |
from fastapi import FastAPI | |
from fastapi.responses import HTMLResponse, RedirectResponse | |
from itables import options as itoptions, to_html_datatable | |
from sql import Q | |
itoptions.classes = "display compact cell-border" | |
itoptions.column_filters = "footer" | |
EXAMPLE1 = """ | |
SELECT | |
Symbol, | |
Number, | |
Mass, | |
Abundance | |
FROM 'https://raw.githubusercontent.com/ekwan/cctk/master/cctk/data/isotopes.csv' | |
""" | |
EXAMPLE2 = """ | |
SELECT | |
42 AS answer, | |
'Life, Universe & Everything' AS question | |
""" | |
app = FastAPI() | |
def query_db(base64query: str|None = None): | |
"""Endpoint for running b64-encoded SQL queries.""" | |
decoded = Q.from_base64(base64query) | |
df = decoded.df() | |
html = to_html_datatable(df) | |
return f""" | |
<head> | |
<link rel="stylesheet" href="https://cdn.datatables.net/2.0.5/css/dataTables.dataTables.min.css" /> | |
</head> | |
<div>{html}</div> | |
<hr><pre>{decoded}</pre> | |
""" | |
def query_from_request(query, request: gr.Request): | |
"""Process query from input block or from initial request. | |
https://github.com/gradio-app/gradio/issues/7464#issuecomment-1960161591 | |
""" | |
if not query: | |
query_params = request.query_params | |
base64query = dict(query_params).get("q") | |
else: | |
base64query = Q(query).base64 | |
if base64query in (None, "example"): | |
decoded = Q(EXAMPLE2) | |
base64query = decoded.base64 | |
else: | |
decoded = Q.from_base64(base64query) | |
_host = request.headers.get("Host") | |
if "huggingface.co/spaces" in _host: | |
# modify URL to access endpoints that aren't available on default app landing page | |
split_url = _host.rsplit("/", maxsplit=2) | |
hf_user, hf_space = split_url[1], split_url[2] | |
host = f"https://{hf_user}-{hf_space}.hf.space" | |
else: | |
host = _host | |
editor_url = f"{host}/sql/?q={base64query}" | |
query_url = f"{host}/q/{base64query}" | |
result = f""" | |
<div id="resultContainer"> | |
<iframe src="/q/{base64query}" width="90%" height="90%"></iframe> | |
</div>""" | |
return (decoded, editor_url, query_url, result) | |
with gr.Blocks( | |
title="Gradio DuckDB Editor", | |
css="#resultContainer {height: 75vh;}" | |
) as gradio_sql_interface: | |
with gr.Row(): | |
with gr.Column(scale=1): | |
header = gr.Markdown("# SQL Editor") | |
sql_code = gr.Code(language="sql", label="SQL Query", lines=32, interactive=True) | |
button = gr.Button("run") | |
editor_url = gr.Code(label="Share Editor URL", lines=1) | |
query_url = gr.Code(label="Share Query Results URL", lines=1) | |
with gr.Column(scale=2): | |
markdown = gr.Markdown("# RESULTS") | |
results = gr.HTML() | |
button.click(query_from_request, [sql_code], [sql_code, editor_url, query_url, results]) | |
gradio_sql_interface.load(query_from_request, [sql_code], [sql_code, editor_url, query_url, results]) | |
app = gr.mount_gradio_app(app, gradio_sql_interface, path="/sql") | |
def redirect_to_example(): | |
return RedirectResponse("/sql/?q=example") |