mirror of
https://github.com/gradio-app/gradio.git
synced 2024-11-21 01:01:05 +08:00
API Docs with support for Blocks (#1397)
* backend * updated PyPi version to 3.0.10 * updated PyPi version to 3.0.9b10 * fixes * updated PyPi version to 3.0.9b11 * changes * changes * changes git push * changes * undo * fixes Co-authored-by: Ali Abid <aabid94@gmail.com>
This commit is contained in:
parent
f6414d3c33
commit
42cee33dcf
@ -38,6 +38,7 @@ With this model you can lorem ipsum
|
||||
inputs=[disease, xray_scan],
|
||||
outputs=xray_results,
|
||||
status_tracker=xray_progress,
|
||||
api_name="xray_model"
|
||||
)
|
||||
|
||||
with gr.TabItem("CT Scan"):
|
||||
@ -51,6 +52,7 @@ With this model you can lorem ipsum
|
||||
inputs=[disease, ct_scan],
|
||||
outputs=ct_results,
|
||||
status_tracker=ct_progress,
|
||||
api_name="ct_model"
|
||||
)
|
||||
|
||||
upload_btn = gr.Button("Upload Results")
|
||||
|
@ -8,7 +8,7 @@ import random
|
||||
import sys
|
||||
import time
|
||||
import webbrowser
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple
|
||||
from typing import TYPE_CHECKING, Any, AnyStr, Callable, Dict, List, Optional, Tuple
|
||||
|
||||
import anyio
|
||||
from anyio import CapacityLimiter
|
||||
@ -85,6 +85,7 @@ class Block:
|
||||
outputs: Optional[Component | List[Component]],
|
||||
preprocess: bool = True,
|
||||
postprocess: bool = True,
|
||||
api_name: Optional[AnyStr] = None,
|
||||
js: Optional[str] = False,
|
||||
no_target: bool = False,
|
||||
status_tracker: Optional[StatusTracker] = None,
|
||||
@ -99,6 +100,7 @@ class Block:
|
||||
outputs: output list
|
||||
preprocess: whether to run the preprocess methods of components
|
||||
postprocess: whether to run the postprocess methods of components
|
||||
api_name: Defining this parameter exposes the endpoint in the api docs
|
||||
js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components
|
||||
no_target: if True, sets "targets" to [], used for Blocks "load" event
|
||||
status_tracker: StatusTracker to visualize function progress
|
||||
@ -115,20 +117,25 @@ class Block:
|
||||
outputs = [outputs]
|
||||
|
||||
Context.root_block.fns.append(BlockFunction(fn, preprocess, postprocess))
|
||||
Context.root_block.dependencies.append(
|
||||
{
|
||||
"targets": [self._id] if not no_target else [],
|
||||
"trigger": event_name,
|
||||
"inputs": [block._id for block in inputs],
|
||||
"outputs": [block._id for block in outputs],
|
||||
"backend_fn": fn is not None,
|
||||
"js": js,
|
||||
"status_tracker": status_tracker._id
|
||||
if status_tracker is not None
|
||||
else None,
|
||||
"queue": queue,
|
||||
}
|
||||
)
|
||||
dependency = {
|
||||
"targets": [self._id] if not no_target else [],
|
||||
"trigger": event_name,
|
||||
"inputs": [block._id for block in inputs],
|
||||
"outputs": [block._id for block in outputs],
|
||||
"backend_fn": fn is not None,
|
||||
"js": js,
|
||||
"status_tracker": status_tracker._id
|
||||
if status_tracker is not None
|
||||
else None,
|
||||
"queue": queue,
|
||||
"api_name": api_name,
|
||||
}
|
||||
if api_name is not None:
|
||||
dependency["documentation"] = [
|
||||
[component.document_parameters("input") for component in inputs],
|
||||
[component.document_parameters("output") for component in outputs],
|
||||
]
|
||||
Context.root_block.dependencies.append(dependency)
|
||||
|
||||
def get_config(self):
|
||||
return {
|
||||
|
@ -244,6 +244,21 @@ class IOComponent(Component):
|
||||
self._style["container"] = container
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def document_parameters(cls, target):
|
||||
if target == "input":
|
||||
doc = inspect.getdoc(cls.preprocess)
|
||||
if "Parameters:\nx (" in doc:
|
||||
return doc.split("Parameters:\nx ")[1].split("\n")[0]
|
||||
return None
|
||||
elif target == "output":
|
||||
doc = inspect.getdoc(cls.postprocess)
|
||||
if "Returns:\n" in doc:
|
||||
return doc.split("Returns:\n")[1].split("\n")[0]
|
||||
return None
|
||||
else:
|
||||
raise ValueError("Invalid doumentation target.")
|
||||
|
||||
|
||||
class Textbox(Changeable, Submittable, IOComponent):
|
||||
"""
|
||||
@ -329,6 +344,10 @@ class Textbox(Changeable, Submittable, IOComponent):
|
||||
def preprocess(self, x: str | None) -> Any:
|
||||
"""
|
||||
Any preprocessing needed to be performed on function input.
|
||||
Parameters:
|
||||
x (str): text
|
||||
Returns:
|
||||
(str): text
|
||||
"""
|
||||
if x is None:
|
||||
return None
|
||||
@ -415,6 +434,10 @@ class Textbox(Changeable, Submittable, IOComponent):
|
||||
def postprocess(self, y: str | None):
|
||||
"""
|
||||
Any postprocessing needed to be performed on function output.
|
||||
Parameters:
|
||||
y (str | None): text
|
||||
Returns:
|
||||
(str | None): text
|
||||
"""
|
||||
if y is None:
|
||||
return None
|
||||
@ -518,21 +541,21 @@ class Number(Changeable, Submittable, IOComponent):
|
||||
"__type__": "update",
|
||||
}
|
||||
|
||||
def preprocess(self, x: int | float | None) -> int | float | None:
|
||||
def preprocess(self, x: float | None) -> float | None:
|
||||
"""
|
||||
Parameters:
|
||||
x (int | float | None): numeric input as a string
|
||||
x (float | None): numeric input
|
||||
Returns:
|
||||
(int | float | None): number representing function input
|
||||
(float | None): number representing function input
|
||||
"""
|
||||
if x is None:
|
||||
return None
|
||||
return self.round_to_precision(x, self.precision)
|
||||
|
||||
def preprocess_example(self, x: int | float | None) -> int | float | None:
|
||||
def preprocess_example(self, x: float | None) -> float | None:
|
||||
"""
|
||||
Returns:
|
||||
(int | float | None): Number representing function input
|
||||
(float | None): Number representing function input
|
||||
"""
|
||||
if x is None:
|
||||
return None
|
||||
@ -584,18 +607,18 @@ class Number(Changeable, Submittable, IOComponent):
|
||||
interpretation.insert(int(len(interpretation) / 2), [x, None])
|
||||
return interpretation
|
||||
|
||||
def generate_sample(self) -> int | float:
|
||||
def generate_sample(self) -> float:
|
||||
return self.round_to_precision(1, self.precision)
|
||||
|
||||
# Output Functionalities
|
||||
def postprocess(self, y: int | float | None) -> int | float | None:
|
||||
def postprocess(self, y: float | None) -> float | None:
|
||||
"""
|
||||
Any postprocessing needed to be performed on function output.
|
||||
|
||||
Parameters:
|
||||
y (int | float | None): numeric output
|
||||
y (float | None): numeric output
|
||||
Returns:
|
||||
(int | float | None): number representing function output
|
||||
(float | None): number representing function output
|
||||
"""
|
||||
if y is None:
|
||||
return None
|
||||
@ -740,9 +763,13 @@ class Slider(Changeable, IOComponent):
|
||||
|
||||
# Output Functionalities
|
||||
|
||||
def postprocess(self, y: int | float | None):
|
||||
def postprocess(self, y: float | None):
|
||||
"""
|
||||
Any postprocessing needed to be performed on function output.
|
||||
Parameters:
|
||||
y (float | None): numeric output
|
||||
Returns:
|
||||
(float): numeric output or minimum number if None
|
||||
"""
|
||||
return self.minimum if y is None else y
|
||||
|
||||
@ -867,6 +894,10 @@ class Checkbox(Changeable, IOComponent):
|
||||
def postprocess(self, y):
|
||||
"""
|
||||
Any postprocessing needed to be performed on function output.
|
||||
Parameters:
|
||||
y (bool): boolean output
|
||||
Returns:
|
||||
(bool): boolean output
|
||||
"""
|
||||
return y
|
||||
|
||||
@ -1015,6 +1046,10 @@ class CheckboxGroup(Changeable, IOComponent):
|
||||
def postprocess(self, y):
|
||||
"""
|
||||
Any postprocessing needed to be performed on function output.
|
||||
Parameters:
|
||||
y (List[str]): List of selected choices
|
||||
Returns:
|
||||
(List[str]): List of selected choices
|
||||
"""
|
||||
return [] if y is None else y
|
||||
|
||||
@ -1160,6 +1195,10 @@ class Radio(Changeable, IOComponent):
|
||||
def postprocess(self, y):
|
||||
"""
|
||||
Any postprocessing needed to be performed on function output.
|
||||
Parameters:
|
||||
y (str): string of choice
|
||||
Returns:
|
||||
(str): string of choice
|
||||
"""
|
||||
return (
|
||||
y if y is not None else self.choices[0] if len(self.choices) > 0 else None
|
||||
@ -3407,9 +3446,7 @@ class Model3D(Changeable, Editable, Clearable, IOComponent):
|
||||
Parameters:
|
||||
y (str): path to the model
|
||||
Returns:
|
||||
(str): file name
|
||||
(str): file extension
|
||||
(str): base64 url data
|
||||
(Dict[name (str): file name, data (str): base64 url data] | None)
|
||||
"""
|
||||
if y is None:
|
||||
return y
|
||||
@ -3494,8 +3531,7 @@ class Plot(Changeable, Clearable, IOComponent):
|
||||
Parameters:
|
||||
y (str): plot data
|
||||
Returns:
|
||||
(str): plot type
|
||||
(str): plot base64 or json
|
||||
(Dict[type (str): plot type, plot (str): plot base64 | json] | None)
|
||||
"""
|
||||
if y is None:
|
||||
return None
|
||||
|
@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple
|
||||
from typing import TYPE_CHECKING, Any, AnyStr, Callable, Dict, List, Optional, Tuple
|
||||
|
||||
from gradio.blocks import Block
|
||||
|
||||
@ -15,6 +15,7 @@ class Changeable(Block):
|
||||
inputs: List[Component],
|
||||
outputs: List[Component],
|
||||
status_tracker: Optional[StatusTracker] = None,
|
||||
api_name: AnyStr = None,
|
||||
queue: Optional[bool] = None,
|
||||
_js: Optional[str] = None,
|
||||
_preprocess: bool = True,
|
||||
@ -26,6 +27,7 @@ class Changeable(Block):
|
||||
inputs: List of inputs
|
||||
outputs: List of outputs
|
||||
status_tracker: StatusTracker to visualize function progress
|
||||
api_name: Defining this parameter exposes the endpoint in the api docs
|
||||
_js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of input and outputs components, return should be a list of values for output component.
|
||||
Returns: None
|
||||
"""
|
||||
@ -35,6 +37,7 @@ class Changeable(Block):
|
||||
inputs,
|
||||
outputs,
|
||||
status_tracker=status_tracker,
|
||||
api_name=api_name,
|
||||
js=_js,
|
||||
preprocess=_preprocess,
|
||||
postprocess=_postprocess,
|
||||
@ -49,6 +52,7 @@ class Clickable(Block):
|
||||
inputs: List[Component],
|
||||
outputs: List[Component],
|
||||
status_tracker: Optional[StatusTracker] = None,
|
||||
api_name: AnyStr = None,
|
||||
queue=None,
|
||||
_js: Optional[str] = None,
|
||||
_preprocess: bool = True,
|
||||
@ -60,6 +64,7 @@ class Clickable(Block):
|
||||
inputs: List of inputs
|
||||
outputs: List of outputs
|
||||
status_tracker: StatusTracker to visualize function progress
|
||||
api_name: Defining this parameter exposes the endpoint in the api docs
|
||||
_js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components.
|
||||
_preprocess: If False, will not run preprocessing of component data before running 'fn'.
|
||||
_postprocess: If False, will not run postprocessing of component data before returning 'fn' output.
|
||||
@ -71,6 +76,7 @@ class Clickable(Block):
|
||||
inputs,
|
||||
outputs,
|
||||
status_tracker=status_tracker,
|
||||
api_name=api_name,
|
||||
queue=queue,
|
||||
js=_js,
|
||||
preprocess=_preprocess,
|
||||
@ -85,6 +91,7 @@ class Submittable(Block):
|
||||
inputs: List[Component],
|
||||
outputs: List[Component],
|
||||
status_tracker: Optional[StatusTracker] = None,
|
||||
api_name: AnyStr = None,
|
||||
queue: Optional[bool] = None,
|
||||
_js: Optional[str] = None,
|
||||
_preprocess: bool = True,
|
||||
@ -96,6 +103,7 @@ class Submittable(Block):
|
||||
inputs: List of inputs
|
||||
outputs: List of outputs
|
||||
status_tracker: StatusTracker to visualize function progress
|
||||
api_name: Defining this parameter exposes the endpoint in the api docs
|
||||
_js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components.
|
||||
Returns: None
|
||||
"""
|
||||
@ -105,6 +113,7 @@ class Submittable(Block):
|
||||
inputs,
|
||||
outputs,
|
||||
status_tracker=status_tracker,
|
||||
api_name=api_name,
|
||||
js=_js,
|
||||
preprocess=_preprocess,
|
||||
postprocess=_postprocess,
|
||||
@ -118,6 +127,7 @@ class Editable(Block):
|
||||
fn: Callable,
|
||||
inputs: List[Component],
|
||||
outputs: List[Component],
|
||||
api_name: AnyStr = None,
|
||||
queue: Optional[bool] = None,
|
||||
_js: Optional[str] = None,
|
||||
_preprocess: bool = True,
|
||||
@ -128,6 +138,7 @@ class Editable(Block):
|
||||
fn: Callable function
|
||||
inputs: List of inputs
|
||||
outputs: List of outputs
|
||||
api_name: Defining this parameter exposes the endpoint in the api docs
|
||||
_js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components.
|
||||
Returns: None
|
||||
"""
|
||||
@ -136,6 +147,7 @@ class Editable(Block):
|
||||
fn,
|
||||
inputs,
|
||||
outputs,
|
||||
api_name=api_name,
|
||||
js=_js,
|
||||
preprocess=_preprocess,
|
||||
postprocess=_postprocess,
|
||||
@ -149,6 +161,7 @@ class Clearable(Block):
|
||||
fn: Callable,
|
||||
inputs: List[Component],
|
||||
outputs: List[Component],
|
||||
api_name: AnyStr = None,
|
||||
queue: Optional[bool] = None,
|
||||
_js: Optional[str] = None,
|
||||
_preprocess: bool = True,
|
||||
@ -159,6 +172,7 @@ class Clearable(Block):
|
||||
fn: Callable function
|
||||
inputs: List of inputs
|
||||
outputs: List of outputs
|
||||
api_name: Defining this parameter exposes the endpoint in the api docs
|
||||
_js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components.
|
||||
Returns: None
|
||||
"""
|
||||
@ -167,6 +181,7 @@ class Clearable(Block):
|
||||
fn,
|
||||
inputs,
|
||||
outputs,
|
||||
api_name=api_name,
|
||||
js=_js,
|
||||
preprocess=_preprocess,
|
||||
postprocess=_postprocess,
|
||||
@ -180,6 +195,7 @@ class Playable(Block):
|
||||
fn: Callable,
|
||||
inputs: List[Component],
|
||||
outputs: List[Component],
|
||||
api_name: AnyStr = None,
|
||||
queue: Optional[bool] = None,
|
||||
_js: Optional[str] = None,
|
||||
_preprocess: bool = True,
|
||||
@ -190,6 +206,7 @@ class Playable(Block):
|
||||
fn: Callable function
|
||||
inputs: List of inputs
|
||||
outputs: List of outputs
|
||||
api_name: Defining this parameter exposes the endpoint in the api docs
|
||||
_js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components.
|
||||
Returns: None
|
||||
"""
|
||||
@ -198,6 +215,7 @@ class Playable(Block):
|
||||
fn,
|
||||
inputs,
|
||||
outputs,
|
||||
api_name=api_name,
|
||||
js=_js,
|
||||
preprocess=_preprocess,
|
||||
postprocess=_postprocess,
|
||||
@ -209,6 +227,7 @@ class Playable(Block):
|
||||
fn: Callable,
|
||||
inputs: List[Component],
|
||||
outputs: List[Component],
|
||||
api_name: Optional[AnyStr] = None,
|
||||
queue: Optional[bool] = None,
|
||||
_js: Optional[str] = None,
|
||||
_preprocess: bool = True,
|
||||
@ -219,6 +238,7 @@ class Playable(Block):
|
||||
fn: Callable function
|
||||
inputs: List of inputs
|
||||
outputs: List of outputs
|
||||
api_name: Defining this parameter exposes the endpoint in the api docs
|
||||
_js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components.
|
||||
Returns: None
|
||||
"""
|
||||
@ -227,6 +247,7 @@ class Playable(Block):
|
||||
fn,
|
||||
inputs,
|
||||
outputs,
|
||||
api_name=api_name,
|
||||
js=_js,
|
||||
preprocess=_preprocess,
|
||||
postprocess=_postprocess,
|
||||
@ -238,6 +259,7 @@ class Playable(Block):
|
||||
fn: Callable,
|
||||
inputs: List[Component],
|
||||
outputs: List[Component],
|
||||
api_name: AnyStr = None,
|
||||
queue: Optional[bool] = None,
|
||||
_js: Optional[str] = None,
|
||||
_preprocess: bool = True,
|
||||
@ -248,6 +270,7 @@ class Playable(Block):
|
||||
fn: Callable function
|
||||
inputs: List of inputs
|
||||
outputs: List of outputs
|
||||
api_name: Defining this parameter exposes the endpoint in the api docs
|
||||
_js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components.
|
||||
Returns: None
|
||||
"""
|
||||
@ -256,6 +279,7 @@ class Playable(Block):
|
||||
fn,
|
||||
inputs,
|
||||
outputs,
|
||||
api_name=api_name,
|
||||
js=_js,
|
||||
preprocess=_preprocess,
|
||||
postprocess=_postprocess,
|
||||
@ -269,6 +293,7 @@ class Streamable(Block):
|
||||
fn: Callable,
|
||||
inputs: List[Component],
|
||||
outputs: List[Component],
|
||||
api_name: AnyStr = None,
|
||||
queue: Optional[bool] = None,
|
||||
_js: Optional[str] = None,
|
||||
_preprocess: bool = True,
|
||||
@ -279,6 +304,7 @@ class Streamable(Block):
|
||||
fn: Callable function
|
||||
inputs: List of inputs
|
||||
outputs: List of outputs
|
||||
api_name: Defining this parameter exposes the endpoint in the api docs
|
||||
_js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components.
|
||||
Returns: None
|
||||
"""
|
||||
@ -288,6 +314,7 @@ class Streamable(Block):
|
||||
fn,
|
||||
inputs,
|
||||
outputs,
|
||||
api_name=api_name,
|
||||
js=_js,
|
||||
preprocess=_preprocess,
|
||||
postprocess=_postprocess,
|
||||
|
@ -519,6 +519,7 @@ class Interface(Blocks):
|
||||
submit_fn,
|
||||
self.input_components,
|
||||
self.output_components,
|
||||
api_name="predict",
|
||||
status_tracker=status_tracker,
|
||||
)
|
||||
clear_btn.click(
|
||||
|
100
gradio/routes.py
100
gradio/routes.py
@ -226,47 +226,19 @@ class App(FastAPI):
|
||||
if Path(app.cwd).resolve() in Path(path).resolve().parents:
|
||||
return FileResponse(Path(path).resolve())
|
||||
|
||||
@app.get("/api", response_class=HTMLResponse) # Needed for Spaces
|
||||
@app.get("/api/", response_class=HTMLResponse)
|
||||
def api_docs(request: Request):
|
||||
inputs = [type(inp) for inp in app.blocks.input_components]
|
||||
outputs = [type(out) for out in app.blocks.output_components]
|
||||
input_types_doc, input_types = get_types(inputs, "input")
|
||||
output_types_doc, output_types = get_types(outputs, "output")
|
||||
input_names = [inp.get_block_name() for inp in app.blocks.input_components]
|
||||
output_names = [
|
||||
out.get_block_name() for out in app.blocks.output_components
|
||||
]
|
||||
if app.blocks.examples is not None:
|
||||
sample_inputs = app.blocks.examples[0]
|
||||
else:
|
||||
sample_inputs = [
|
||||
inp.generate_sample() for inp in app.blocks.input_components
|
||||
]
|
||||
docs = {
|
||||
"inputs": input_names,
|
||||
"outputs": output_names,
|
||||
"len_inputs": len(inputs),
|
||||
"len_outputs": len(outputs),
|
||||
"inputs_lower": [name.lower() for name in input_names],
|
||||
"outputs_lower": [name.lower() for name in output_names],
|
||||
"input_types": input_types,
|
||||
"output_types": output_types,
|
||||
"input_types_doc": input_types_doc,
|
||||
"output_types_doc": output_types_doc,
|
||||
"sample_inputs": sample_inputs,
|
||||
"auth": app.blocks.auth,
|
||||
"local_login_url": urllib.parse.urljoin(app.blocks.local_url, "login"),
|
||||
"local_api_url": urllib.parse.urljoin(
|
||||
app.blocks.local_url, "api/predict"
|
||||
),
|
||||
}
|
||||
return templates.TemplateResponse(
|
||||
"api_docs.html", {"request": request, **docs}
|
||||
)
|
||||
@app.post("/api/queue/push/", dependencies=[Depends(login_check)])
|
||||
async def queue_push(body: QueuePushBody):
|
||||
job_hash, queue_position = queueing.push(body)
|
||||
return {"hash": job_hash, "queue_position": queue_position}
|
||||
|
||||
@app.post("/api/predict/", dependencies=[Depends(login_check)])
|
||||
async def predict(body: PredictBody, username: str = Depends(get_current_user)):
|
||||
@app.post("/api/queue/status/", dependencies=[Depends(login_check)])
|
||||
async def queue_status(body: QueueStatusBody):
|
||||
status, data = queueing.get_status(body.hash)
|
||||
return {"status": status, "data": data}
|
||||
|
||||
async def run_predict(
|
||||
body: PredictBody, username: str = Depends(get_current_user)
|
||||
):
|
||||
if hasattr(body, "session_hash"):
|
||||
if body.session_hash not in app.state_holder:
|
||||
app.state_holder[body.session_hash] = {
|
||||
@ -291,15 +263,24 @@ class App(FastAPI):
|
||||
raise error
|
||||
return output
|
||||
|
||||
@app.post("/api/queue/push/", dependencies=[Depends(login_check)])
|
||||
async def queue_push(body: QueuePushBody):
|
||||
job_hash, queue_position = queueing.push(body)
|
||||
return {"hash": job_hash, "queue_position": queue_position}
|
||||
|
||||
@app.post("/api/queue/status/", dependencies=[Depends(login_check)])
|
||||
async def queue_status(body: QueueStatusBody):
|
||||
status, data = queueing.get_status(body.hash)
|
||||
return {"status": status, "data": data}
|
||||
@app.post("/api/{api_name}", dependencies=[Depends(login_check)])
|
||||
@app.post("/api/{api_name}/", dependencies=[Depends(login_check)])
|
||||
async def predict(
|
||||
api_name: str, body: PredictBody, username: str = Depends(get_current_user)
|
||||
):
|
||||
if body.fn_index is None:
|
||||
for i, fn in enumerate(app.blocks.dependencies):
|
||||
if fn["api_name"] == api_name:
|
||||
body.fn_index = i
|
||||
break
|
||||
if body.fn_index is None:
|
||||
return JSONResponse(
|
||||
content={
|
||||
"error": f"This app has no endpoint /api/{api_name}/."
|
||||
},
|
||||
status_code=500,
|
||||
)
|
||||
return await run_predict(body=body, username=username)
|
||||
|
||||
return app
|
||||
|
||||
@ -329,19 +310,14 @@ def safe_join(directory: str, path: str) -> Optional[str]:
|
||||
return posixpath.join(directory, filename)
|
||||
|
||||
|
||||
def get_types(cls_set: List[Type], component: str):
|
||||
def get_types(cls_set: List[Type]):
|
||||
docset = []
|
||||
types = []
|
||||
if component == "input":
|
||||
for cls in cls_set:
|
||||
doc = inspect.getdoc(cls.preprocess)
|
||||
doc_lines = doc.split("\n")
|
||||
docset.append(doc_lines[1].split(":")[-1])
|
||||
types.append(doc_lines[1].split(")")[0].split("(")[-1])
|
||||
else:
|
||||
for cls in cls_set:
|
||||
doc = inspect.getdoc(cls.postprocess)
|
||||
doc_lines = doc.split("\n")
|
||||
docset.append(doc_lines[-1].split(":")[-1])
|
||||
types.append(doc_lines[-1].split(")")[0].split("(")[-1])
|
||||
for cls in cls_set:
|
||||
doc = inspect.getdoc(cls)
|
||||
doc_lines = doc.split("\n")
|
||||
for line in doc_lines:
|
||||
if "value (" in line:
|
||||
types.append(line.split("value (")[1].split(")")[0])
|
||||
docset.append(doc_lines[1].split(":")[-1])
|
||||
return docset, types
|
||||
|
File diff suppressed because one or more lines are too long
@ -6,10 +6,10 @@ else
|
||||
echo "Uploading to pypi"
|
||||
set -e
|
||||
git pull origin main
|
||||
old_version=$(grep -Po "(?<=version=\")[^\"]+(?=\")" setup.py)
|
||||
old_version=$(ggrep -Po "(?<=version=\")[^\"]+(?=\")" setup.py)
|
||||
echo "Current version is $old_version. New version?"
|
||||
read new_version
|
||||
sed -i "s/version=\"$old_version\"/version=\"$new_version\"/g" setup.py
|
||||
gsed -i "s/version=\"$old_version\"/version=\"$new_version\"/g" setup.py
|
||||
|
||||
echo -n $new_version > gradio/version.txt
|
||||
rm -rf gradio/templates/frontend
|
||||
|
132
ui/packages/app/src/ApiDocs.svelte
Normal file
132
ui/packages/app/src/ApiDocs.svelte
Normal file
@ -0,0 +1,132 @@
|
||||
<script lang="ts">
|
||||
interface Component {
|
||||
id: number;
|
||||
props: {
|
||||
name: string;
|
||||
label?: string;
|
||||
};
|
||||
}
|
||||
interface Dependency {
|
||||
inputs: Array<number>;
|
||||
outputs: Array<number>;
|
||||
api_name: string | null;
|
||||
documentation?: Array<Array<string | null>>;
|
||||
}
|
||||
export let components: Array<Component>;
|
||||
export let dependencies: Array<Dependency>;
|
||||
export let root: string;
|
||||
|
||||
if (root === "") {
|
||||
root = window.location.href;
|
||||
}
|
||||
|
||||
let just_copied = -1;
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<h2 class="text-3xl text-center mb-6">
|
||||
API Docs for
|
||||
<span class="italic text-amber-500">
|
||||
{root}
|
||||
</span>
|
||||
</h2>
|
||||
<div class="flex flex-col gap-6">
|
||||
{#each dependencies as dependency, d}
|
||||
{#if dependency.documentation}
|
||||
<div
|
||||
class="bg-gray-50 border border-gray-100 dark:bg-gray-800 dark:border-gray-700 p-6 rounded"
|
||||
>
|
||||
<h3 class="text-3xl text-amber-500 font-semibold mb-2">
|
||||
POST /api/{dependency.api_name}
|
||||
</h3>
|
||||
<div class="mb-6">
|
||||
Full URL: <span class="underline"
|
||||
>{root}api/{dependency.api_name}</span
|
||||
>
|
||||
<button
|
||||
class="ml-1 px-2 py-0.5 rounded bg-gray-200 dark:bg-gray-700"
|
||||
on:click={() => {
|
||||
navigator.clipboard.writeText(
|
||||
root + "api/" + dependency.api_name
|
||||
);
|
||||
just_copied = d;
|
||||
setTimeout(() => {
|
||||
just_copied = -1;
|
||||
}, 500);
|
||||
}}
|
||||
>
|
||||
{#if just_copied === d}copied!{:else}copy{/if}
|
||||
</button>
|
||||
</div>
|
||||
<h4 class="text-2xl mt-6 mb-4">Input Payload</h4>
|
||||
<div
|
||||
class="block mb-4 text-lg bg-gray-100 dark:bg-gray-700 p-4 font-mono"
|
||||
>
|
||||
{<br />
|
||||
"data": [<br />
|
||||
{#each dependency.documentation[0] as dependency_doc, i}
|
||||
{dependency_doc?.substring(
|
||||
0,
|
||||
dependency_doc.indexOf(")") + 1
|
||||
)},
|
||||
<span class="text-pink-400 dark:text-pink-600"
|
||||
>// represents {dependency_doc?.substring(
|
||||
dependency_doc.indexOf(": ") + 2
|
||||
)} of
|
||||
{((label) => {
|
||||
return label ? "'" + label + "'" : "the";
|
||||
})(
|
||||
components.filter((c) => c.id === dependency.inputs[i])[0]
|
||||
.props.label
|
||||
)}
|
||||
|
||||
<span class="capitalize"
|
||||
>{components.filter((c) => c.id === dependency.inputs[i])[0]
|
||||
.props.name}</span
|
||||
> component
|
||||
</span>
|
||||
<br />
|
||||
{/each}
|
||||
]<br />
|
||||
}
|
||||
</div>
|
||||
<h4 class="text-2xl mt-6 mb-4">Response Object</h4>
|
||||
<div
|
||||
class="block mb-4 text-lg bg-gray-100 dark:bg-gray-700 p-4 font-mono"
|
||||
>
|
||||
{<br />
|
||||
"data": [<br />
|
||||
{#each dependency.documentation[1] as dependency_doc, i}
|
||||
{dependency_doc?.substring(
|
||||
0,
|
||||
dependency_doc.indexOf(")") + 1
|
||||
)},
|
||||
<span class="text-pink-400 dark:text-pink-600"
|
||||
>// represents {dependency_doc?.substring(
|
||||
dependency_doc.indexOf(": ") + 2
|
||||
)} of
|
||||
{((label) => {
|
||||
return label ? "'" + label + "'" : "the";
|
||||
})(
|
||||
components.filter((c) => c.id === dependency.outputs[i])[0]
|
||||
.props.label
|
||||
)}
|
||||
<span class="capitalize"
|
||||
>{components.filter((c) => c.id === dependency.outputs[i])[0]
|
||||
.props.name}</span
|
||||
> component
|
||||
</span>
|
||||
<br />
|
||||
{/each}
|
||||
],<br />
|
||||
"duration": (float)
|
||||
<span class="text-pink-400 dark:text-pink-600">
|
||||
// number of seconds to run function call</span
|
||||
><br />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
@ -8,6 +8,7 @@
|
||||
import { _ } from "svelte-i18n";
|
||||
import { setupi18n } from "./i18n";
|
||||
import Render from "./Render.svelte";
|
||||
import ApiDocs from "./ApiDocs.svelte";
|
||||
import { tick } from "svelte";
|
||||
setupi18n();
|
||||
|
||||
@ -44,6 +45,8 @@
|
||||
status_tracker: number | null;
|
||||
status?: string;
|
||||
queue: boolean | null;
|
||||
api_name: string | null;
|
||||
documentation?: Array<Array<string>>;
|
||||
}
|
||||
|
||||
export let root: string;
|
||||
@ -77,6 +80,8 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
let show_api_docs = dependencies.some((d) => "documentation" in d);
|
||||
let api_docs_visible = false;
|
||||
|
||||
function is_dep(
|
||||
id: number,
|
||||
@ -389,7 +394,9 @@
|
||||
class="mx-auto container px-4 py-6 dark:bg-gray-950"
|
||||
class:flex-grow={(window.__gradio_mode__ = "app")}
|
||||
>
|
||||
{#if ready}
|
||||
{#if api_docs_visible}
|
||||
<ApiDocs {components} {dependencies} {root} />
|
||||
{:else if ready}
|
||||
<Render
|
||||
component={rootNode.component}
|
||||
id={rootNode.id}
|
||||
@ -404,12 +411,25 @@
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
<footer class="flex justify-center pb-6">
|
||||
<footer
|
||||
class="flex justify-center pb-6 text-gray-300 dark:text-gray-500 font-semibold"
|
||||
>
|
||||
{#if show_api_docs}
|
||||
<div
|
||||
class="cursor-pointer hover:text-gray-400 dark:hover:text-gray-400 transition-colors"
|
||||
on:click={() => {
|
||||
api_docs_visible = !api_docs_visible;
|
||||
}}
|
||||
>
|
||||
{#if api_docs_visible}hide{:else}view{/if} api
|
||||
</div>
|
||||
•
|
||||
{/if}
|
||||
<a
|
||||
href="https://gradio.app"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
class="group text-gray-300 dark:text-gray-500 hover:text-gray-400 dark:hover:text-gray-400 transition-colors font-semibold text-sm"
|
||||
class="group hover:text-gray-400 dark:hover:text-gray-400 transition-colors"
|
||||
>
|
||||
{$_("interface.built_with_Gradio")}
|
||||
<img
|
||||
|
@ -16,6 +16,7 @@
|
||||
export let value: Array<string> | null = null;
|
||||
export let style: Styles = {};
|
||||
|
||||
$: console.log(">", value);
|
||||
let selected_image: number | null = null;
|
||||
|
||||
$: previous =
|
||||
|
Loading…
Reference in New Issue
Block a user