Giter VIP home page Giter VIP logo

Comments (8)

liquidcarbon avatar liquidcarbon commented on June 9, 2024

Code:


@app.get("/sql/{base64query}", response_class=HTMLResponse)
def query_db(base64query: str|None = None):
    decoded = Q.from_base64(base64query)
    q = Q(decoded.format(**TABLES))  # this is to query tables defined elsewhere using string formatting
    log.debug(q)
    try:
        if not q.is_safe:
            raise Exception("naughty!")
        df = q.df()
    except Exception as e:
        df = pd.DataFrame({"error": [e.__str__()]})

    with gr.Blocks() as gradio_sql_interface:
        sql_code = gr.Code(value=decoded, language="sql", label="SQL Query", interactive=True)
        button = gr.Button("run") #, link=f"/sql/{Q(sql_code.value).base64}")
        button.click(None, [], [], js=f"window.open('/sql/{Q(sql_code.value).base64}', '_top')")
    gr.mount_gradio_app(app, gradio_sql_interface, path="/sqlgradio")
 
    query_result_html = render(...)  # jinja template here with all the jQuery stuff
    html = f"""
    <head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
    </head>
    <div class="container-fluid py-1 bg-light-subtle">
    <h3>QPRST!</h3>
    <div class="row m-3 bg-light-subtle">
        <div class="col-4">
            <iframe id="sql_iframe" src="/sqlgradio" width="100%" height="100%"></iframe>
        </div>
        <div class="col-8">
            {query_result_html}
        </div>
    </div>
    </div>

    """
    return html

where Q is just a string with extra attributes:

import base64
import duckdb
class Q(str):
    UNSAFE = ["CREATE", "DELETE", "DROP", "INSERT", "UPDATE"]
    
    def __init__(self, query: str):
        self.is_safe = not any([cmd in query.upper() for cmd in self.UNSAFE])

    def run(self, sql_engine=None):    
        try:
            if sql_engine is None:
                return self.run_duckdb()
            else:
                return self.run_sql(sql_engine)
        except Exception as e:
            pass   
    
    def run_duckdb(self):
        return duckdb.sql(self)

    def df(self, sql_engine=None):
        result = self.run(sql_engine=sql_engine)
        if result is None: return
        result_df = result.df()
        return result_df


    @property
    def base64(self):
        return base64.b64encode(self.encode()).decode()

    @classmethod
    def from_base64(cls, b64):
        """Initializing from base64-encoded URL paths."""
        return cls(base64.b64decode(b64).decode())

from gradio.

abidlabs avatar abidlabs commented on June 9, 2024

Hi @liquidcarbon, for general questions like this (that are not feature requests or bug reports), please ask in our Discord server where we have a larger community that can help answer these questions. (I'll close this issue)

from gradio.

liquidcarbon avatar liquidcarbon commented on June 9, 2024

@abidlabs thanks for your message. I saw that for general questions you're invited to go to Discord but I thought this could belong under new guide or feature request.

There is not a lot of examples in the docs on solutions related to FastAPI and gradio. I'd be happy to contribute one if you find this use case interesting, but I need some help :)

Personally, I'm excited about gradio because it becomes much easier to integrate nascent ML projects into existing FastAPI infra. It is my impression that though gradio mainly serves ML UI use cases, it is underappreciated as a general purpose tool for building interesting apps with (almost) pure python. I think FastAPI backend is a huge advantage of gradio compared to, say, Streamlit (Tornado and no plans for supporting others per streamlit/streamlit#4567).

from gradio.

abidlabs avatar abidlabs commented on June 9, 2024

For sure, thanks @liquidcarbon! I think this is possible with Gradio currently, so it doesn't need to be feature request

from gradio.

liquidcarbon avatar liquidcarbon commented on June 9, 2024

Perhaps a guide request then?

from gradio.

abidlabs avatar abidlabs commented on June 9, 2024

Its a bit niche as a Guide, instead I would publish your app as a public Space on Hugging Face (which supports FastAPI apps) and then it would get good visibility and serve as an informal guide to other users.

from gradio.

liquidcarbon avatar liquidcarbon commented on June 9, 2024

ok I'm mostly there https://huggingface.co/spaces/liquidcarbon/duckdb-fastapi-gradio
I almost gave up, finally ran into #7464 (comment) that shows how the same function can process both inputs from blocks and from requests

image

import gradio as gr
import pandas as pd
from fastapi import FastAPI
from fastapi.responses import HTMLResponse, RedirectResponse
from itables import to_html_datatable

from sql import Q

app = FastAPI()

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("""SELECT 42 AS answer, 'LU & E' AS question""")
        base64query = decoded.base64
    else:
        decoded = Q.from_base64(base64query)
    href = format_href(base64query)
    result = f"""<iframe src="/q/{base64query}" width="90%" height="90%"></iframe>"""
    return (decoded, href, result)

def format_href(url: str):
    href=f"localhost:7860/sql/{url}"
    return f"""<a href="{href}">{href}</a>"""

@app.get("/q/{base64query}", response_class=HTMLResponse)
def query_db(base64query: str|None = None):
    decoded = Q.from_base64(base64query)
    df = decoded.df()
    html = to_html_datatable(df)
    return f"""
        <h3>{decoded}</h3>
        <div>{html}</div>
    """

with gr.Blocks() as gradio_sql_interface:
    with gr.Row():
        with gr.Column():
            header = gr.Markdown("# SQL Editor")
            sql_code = gr.Code(language="sql", label="SQL Query", interactive=True)
            copy_button = gr.HTML()
            button = gr.Button("run")
        with gr.Column():
            markdown = gr.Markdown("# RESULTS")
            results = gr.HTML()
    button.click(query_from_request, [sql_code], [sql_code, copy_button, results]) 
    gradio_sql_interface.load(query_from_request, [sql_code], [sql_code, copy_button, results], queue=True)

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")

from gradio.

abidlabs avatar abidlabs commented on June 9, 2024

Awesome so is everything working now or did you run into any bugs / issues?

from gradio.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.