File size: 3,455 Bytes
82815c9
 
 
 
 
 
 
 
 
 
 
 
1873f22
82815c9
 
 
1873f22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82815c9
 
1873f22
 
 
 
 
 
 
 
 
 
 
 
 
 
82815c9
 
 
 
 
 
 
 
 
 
 
1873f22
82815c9
 
 
 
ccc9015
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82815c9
ccc9015
 
1873f22
ccc9015
82815c9
ccc9015
82815c9
ccc9015
82815c9
ccc9015
1873f22
ccc9015
82815c9
 
ccc9015
 
82815c9
 
 
 
 
 
 
ccc9015
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
__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()

@app.get("/q/{base64query}", response_class=HTMLResponse)
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")

@app.get("/")
@app.get("/sql")
@app.get("/sql/")
def redirect_to_example():
    return RedirectResponse("/sql/?q=example")