mirror of
https://github.com/gradio-app/gradio.git
synced 2025-01-30 11:00:11 +08:00
Block-Components
- create general structure - move Textbox into component.py
This commit is contained in:
parent
c8411c75c6
commit
9451597224
@ -24,8 +24,10 @@ with xray_blocks:
|
||||
with gr.Row():
|
||||
xray_scan = gr.inputs.Image()
|
||||
xray_results = gr.outputs.JSON()
|
||||
new_results = gr.components.Textbox()
|
||||
xray_run = gr.Button("Run")
|
||||
xray_run.click(xray_model, inputs=[disease, xray_scan], outputs=xray_results)
|
||||
xray_run.click(xray_model, inputs=[disease, xray_scan], outputs=new_results)
|
||||
|
||||
with gr.Tab("CT Scan"):
|
||||
with gr.Row():
|
||||
|
@ -1,5 +1,8 @@
|
||||
import pkg_resources
|
||||
|
||||
import gradio.component as components
|
||||
import gradio.inputs as inputs
|
||||
import gradio.outputs as outputs
|
||||
from gradio.blocks import Blocks, Column, Row, Tab
|
||||
from gradio.flagging import (
|
||||
CSVLogger,
|
||||
|
@ -1,6 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from typing import Any, Dict, Optional
|
||||
import warnings
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
from gradio import processing_utils
|
||||
from gradio.blocks import Block
|
||||
@ -8,25 +13,36 @@ from gradio.blocks import Block
|
||||
|
||||
class Component(Block):
|
||||
"""
|
||||
A class for defining the methods that all gradio input and output components should have.
|
||||
A base class for defining the methods that all gradio input and output components should have.
|
||||
"""
|
||||
|
||||
def __init__(self, label, requires_permissions=False):
|
||||
def __init__(
|
||||
self, label: str, requires_permissions: bool = False, optional: bool = False
|
||||
):
|
||||
self.label = label
|
||||
self.requires_permissions = requires_permissions
|
||||
self.component_type = "input"
|
||||
self.set_interpret_parameters()
|
||||
self.optional = optional
|
||||
self.input = False
|
||||
self.output = False
|
||||
super().__init__()
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def __repr__(self):
|
||||
return '{}(label="{}")'.format(type(self).__name__, self.label)
|
||||
return f"{type(self).__name__} (label={self.label})"
|
||||
|
||||
def get_template_context(self):
|
||||
"""
|
||||
:return: a dictionary with context variables for the javascript file associated with the context
|
||||
"""
|
||||
return {"name": self.__class__.__name__.lower(), "label": self.label}
|
||||
return {
|
||||
"name": self.__class__.__name__.lower(),
|
||||
"label": self.label,
|
||||
"optional": self.optional,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
@ -95,3 +111,233 @@ class Component(Block):
|
||||
for shortcut, parameters in sub_cls.get_shortcut_implementations().items():
|
||||
shortcuts[shortcut] = (sub_cls, parameters)
|
||||
return shortcuts
|
||||
|
||||
# Input Functionalities
|
||||
def preprocess(self, x: Any) -> Any:
|
||||
"""
|
||||
Any preprocessing needed to be performed on function input.
|
||||
"""
|
||||
return x
|
||||
|
||||
def serialize(self, x: Any, called_directly: bool) -> Any:
|
||||
"""
|
||||
Convert from a human-readable version of the input (path of an image, URL of a video, etc.) into the interface to a serialized version (e.g. base64) to pass into an API. May do different things if the interface is called() vs. used via GUI.
|
||||
Parameters:
|
||||
x (Any): Input to interface
|
||||
called_directly (bool): if true, the interface was called(), otherwise, it is being used via the GUI
|
||||
"""
|
||||
return x
|
||||
|
||||
def preprocess_example(self, x: Any) -> Any:
|
||||
"""
|
||||
Any preprocessing needed to be performed on an example before being passed to the main function.
|
||||
"""
|
||||
return x
|
||||
|
||||
def set_interpret_parameters(self):
|
||||
"""
|
||||
Set any parameters for interpretation.
|
||||
"""
|
||||
return self
|
||||
|
||||
def get_interpretation_neighbors(self, x: Any) -> Tuple[List[Any], Dict[Any], bool]:
|
||||
"""
|
||||
Generates values similar to input to be used to interpret the significance of the input in the final output.
|
||||
Parameters:
|
||||
x (Any): Input to interface
|
||||
Returns: (neighbor_values, interpret_kwargs, interpret_by_removal)
|
||||
neighbor_values (List[Any]): Neighboring values to input x to compute for interpretation
|
||||
interpret_kwargs (Dict[Any]): Keyword arguments to be passed to get_interpretation_scores
|
||||
interpret_by_removal (bool): If True, returned neighbors are values where the interpreted subsection was removed. If False, returned neighbors are values where the interpreted subsection was modified to a different value.
|
||||
"""
|
||||
return [], {}, True
|
||||
|
||||
def get_interpretation_scores(
|
||||
self, x: Any, neighbors: List[Any], scores: List[float], **kwargs
|
||||
) -> List[Any]:
|
||||
"""
|
||||
Arrange the output values from the neighbors into interpretation scores for the interface to render.
|
||||
Parameters:
|
||||
x (Any): Input to interface
|
||||
neighbors (List[Any]): Neighboring values to input x used for interpretation.
|
||||
scores (List[float]): Output value corresponding to each neighbor in neighbors
|
||||
kwargs (Dict[str, Any]): Any additional arguments passed from get_interpretation_neighbors.
|
||||
Returns:
|
||||
(List[Any]): Arrangement of interpretation scores for interfaces to render.
|
||||
"""
|
||||
pass
|
||||
|
||||
def generate_sample(self) -> Any:
|
||||
"""
|
||||
Returns a sample value of the input that would be accepted by the api. Used for api documentation.
|
||||
"""
|
||||
pass
|
||||
|
||||
# Output Functionalities
|
||||
def postprocess(self, y):
|
||||
"""
|
||||
Any postprocessing needed to be performed on function output.
|
||||
"""
|
||||
return y
|
||||
|
||||
def deserialize(self, x):
|
||||
"""
|
||||
Convert from serialized output (e.g. base64 representation) from a call() to the interface to a human-readable version of the output (path of an image, etc.)
|
||||
"""
|
||||
return x
|
||||
|
||||
|
||||
class Textbox(Component):
|
||||
"""
|
||||
Component creates a textbox for user to enter input. Provides a string as an argument to the wrapped function.
|
||||
Input type: str
|
||||
Demos: hello_world, diff_texts
|
||||
|
||||
Component creates a textbox to render output text or number.
|
||||
Output type: Union[str, float, int]
|
||||
Demos: hello_world, sentence_builder
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
lines: int = 1,
|
||||
placeholder: Optional[str] = None,
|
||||
default: str = "",
|
||||
label: Optional[str] = None,
|
||||
numeric: Optional[bool] = False,
|
||||
type: Optional[str] = "str",
|
||||
optional: bool = False,
|
||||
):
|
||||
"""
|
||||
Parameters:
|
||||
lines (int): number of line rows to provide in textarea.
|
||||
placeholder (str): placeholder hint to provide behind textarea.
|
||||
default (str): default text to provide in textarea.
|
||||
label (str): component name in interface.
|
||||
numeric (bool): DEPRECATED.
|
||||
type (str): DEPRECATED.
|
||||
optional (bool): DEPRECATED
|
||||
"""
|
||||
self.lines = lines
|
||||
self.placeholder = placeholder
|
||||
self.default = default
|
||||
self.type = "str"
|
||||
if numeric:
|
||||
warnings.warn(
|
||||
"The 'numeric' type has been deprecated. Use the Number component instead.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
if type:
|
||||
warnings.warn(
|
||||
"The 'type' parameter has been deprecated. Use the Number component instead if you need it.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
self.test_input = default
|
||||
self.interpret_by_tokens = True
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"lines": self.lines,
|
||||
"placeholder": self.placeholder,
|
||||
"default": self.default,
|
||||
**super().get_template_context(),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"text": {},
|
||||
"textbox": {"lines": 7},
|
||||
}
|
||||
|
||||
def preprocess(self, x: str) -> str | float:
|
||||
"""
|
||||
Parameters:
|
||||
x (str): text input
|
||||
"""
|
||||
if self.type == "str":
|
||||
return x
|
||||
elif self.type == "number":
|
||||
return float(x)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Unknown type: "
|
||||
+ str(self.type)
|
||||
+ ". Please choose from: 'str', 'number'."
|
||||
)
|
||||
|
||||
def preprocess_example(self, x: str) -> str:
|
||||
"""
|
||||
Returns:
|
||||
(str): Text representing function input
|
||||
"""
|
||||
return x
|
||||
|
||||
def set_interpret_parameters(
|
||||
self, separator: str = " ", replacement: Optional[str] = None
|
||||
):
|
||||
"""
|
||||
Calculates interpretation score of characters in input by splitting input into tokens, then using a "leave one out" method to calculate the score of each token by removing each token and measuring the delta of the output value.
|
||||
Parameters:
|
||||
separator (str): Separator to use to split input into tokens.
|
||||
replacement (str): In the "leave one out" step, the text that the token should be replaced with. If None, the token is removed altogether.
|
||||
"""
|
||||
self.interpretation_separator = separator
|
||||
self.interpretation_replacement = replacement
|
||||
return self
|
||||
|
||||
def tokenize(self, x: str) -> Tuple[List[str], List[str], None]:
|
||||
"""
|
||||
Tokenizes an input string by dividing into "words" delimited by self.interpretation_separator
|
||||
"""
|
||||
tokens = x.split(self.interpretation_separator)
|
||||
leave_one_out_strings = []
|
||||
for index in range(len(tokens)):
|
||||
leave_one_out_set = list(tokens)
|
||||
if self.interpretation_replacement is None:
|
||||
leave_one_out_set.pop(index)
|
||||
else:
|
||||
leave_one_out_set[index] = self.interpretation_replacement
|
||||
leave_one_out_strings.append(
|
||||
self.interpretation_separator.join(leave_one_out_set)
|
||||
)
|
||||
return tokens, leave_one_out_strings, None
|
||||
|
||||
def get_masked_inputs(
|
||||
self, tokens: List[str], binary_mask_matrix: List[List[int]]
|
||||
) -> List[str]:
|
||||
"""
|
||||
Constructs partially-masked sentences for SHAP interpretation
|
||||
"""
|
||||
masked_inputs = []
|
||||
for binary_mask_vector in binary_mask_matrix:
|
||||
masked_input = np.array(tokens)[np.array(binary_mask_vector, dtype=bool)]
|
||||
masked_inputs.append(self.interpretation_separator.join(masked_input))
|
||||
return masked_inputs
|
||||
|
||||
def get_interpretation_scores(
|
||||
self, x, neighbors, scores: List[float], tokens: List[str], masks=None
|
||||
) -> List[Tuple[str, float]]:
|
||||
"""
|
||||
Returns:
|
||||
(List[Tuple[str, float]]): Each tuple set represents a set of characters and their corresponding interpretation score.
|
||||
"""
|
||||
result = []
|
||||
for token, score in zip(tokens, scores):
|
||||
result.append((token, score))
|
||||
result.append((self.interpretation_separator, 0))
|
||||
return result
|
||||
|
||||
def generate_sample(self) -> str:
|
||||
return "Hello World"
|
||||
|
||||
def postprocess(self, y: str):
|
||||
"""
|
||||
Parameters:
|
||||
y (str): text output
|
||||
Returns:
|
||||
str(y)
|
||||
|
||||
"""
|
||||
return str(y)
|
||||
|
147
gradio/inputs.py
147
gradio/inputs.py
@ -19,7 +19,7 @@ import PIL
|
||||
from ffmpy import FFmpeg
|
||||
|
||||
from gradio import processing_utils, test_data
|
||||
from gradio.component import Component
|
||||
from gradio.component import Component, Textbox
|
||||
|
||||
if TYPE_CHECKING: # Only import for type checking (is False at runtime).
|
||||
from gradio import Interface
|
||||
@ -108,151 +108,6 @@ class InputComponent(Component):
|
||||
}
|
||||
|
||||
|
||||
class Textbox(InputComponent):
|
||||
"""
|
||||
Component creates a textbox for user to enter input. Provides a string as an argument to the wrapped function.
|
||||
Input type: str
|
||||
Demos: hello_world, diff_texts
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
lines: int = 1,
|
||||
placeholder: Optional[str] = None,
|
||||
default: str = "",
|
||||
numeric: Optional[bool] = False,
|
||||
type: Optional[str] = "str",
|
||||
label: Optional[str] = None,
|
||||
optional: bool = False,
|
||||
):
|
||||
"""
|
||||
Parameters:
|
||||
lines (int): number of line rows to provide in textarea.
|
||||
placeholder (str): placeholder hint to provide behind textarea.
|
||||
default (str): default text to provide in textarea.
|
||||
numeric (bool): DEPRECATED. Whether the input should be parsed as a number instead of a string.
|
||||
type (str): DEPRECATED. Type of value to be returned by component. "str" returns a string, "number" returns a float value. Use Number component in place of number type.
|
||||
label (str): component name in interface.
|
||||
optional (bool): this parameter is ignored.
|
||||
"""
|
||||
self.lines = lines
|
||||
self.placeholder = placeholder
|
||||
self.default = default
|
||||
if numeric or type == "number":
|
||||
warnings.warn(
|
||||
"The 'numeric' type has been deprecated. Use the Number input component instead.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
self.type = "number"
|
||||
else:
|
||||
self.type = type
|
||||
if default == "":
|
||||
self.test_input = {
|
||||
"str": "the quick brown fox jumped over the lazy dog",
|
||||
"number": 786.92,
|
||||
}.get(type)
|
||||
else:
|
||||
self.test_input = default
|
||||
self.interpret_by_tokens = True
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {
|
||||
"lines": self.lines,
|
||||
"placeholder": self.placeholder,
|
||||
"default": self.default,
|
||||
**super().get_template_context(),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"text": {},
|
||||
"textbox": {"lines": 7},
|
||||
}
|
||||
|
||||
def preprocess(self, x: str) -> str | float:
|
||||
"""
|
||||
Parameters:
|
||||
x (str): text input
|
||||
"""
|
||||
if self.type == "str":
|
||||
return x
|
||||
elif self.type == "number":
|
||||
return float(x)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Unknown type: "
|
||||
+ str(self.type)
|
||||
+ ". Please choose from: 'str', 'number'."
|
||||
)
|
||||
|
||||
def preprocess_example(self, x: str) -> str:
|
||||
"""
|
||||
Returns:
|
||||
(str): Text representing function input
|
||||
"""
|
||||
return x
|
||||
|
||||
def set_interpret_parameters(
|
||||
self, separator: str = " ", replacement: Optional[str] = None
|
||||
):
|
||||
"""
|
||||
Calculates interpretation score of characters in input by splitting input into tokens, then using a "leave one out" method to calculate the score of each token by removing each token and measuring the delta of the output value.
|
||||
Parameters:
|
||||
separator (str): Separator to use to split input into tokens.
|
||||
replacement (str): In the "leave one out" step, the text that the token should be replaced with. If None, the token is removed altogether.
|
||||
"""
|
||||
self.interpretation_separator = separator
|
||||
self.interpretation_replacement = replacement
|
||||
return self
|
||||
|
||||
def tokenize(self, x: str) -> Tuple[List[str], List[str], None]:
|
||||
"""
|
||||
Tokenizes an input string by dividing into "words" delimited by self.interpretation_separator
|
||||
"""
|
||||
tokens = x.split(self.interpretation_separator)
|
||||
leave_one_out_strings = []
|
||||
for index in range(len(tokens)):
|
||||
leave_one_out_set = list(tokens)
|
||||
if self.interpretation_replacement is None:
|
||||
leave_one_out_set.pop(index)
|
||||
else:
|
||||
leave_one_out_set[index] = self.interpretation_replacement
|
||||
leave_one_out_strings.append(
|
||||
self.interpretation_separator.join(leave_one_out_set)
|
||||
)
|
||||
return tokens, leave_one_out_strings, None
|
||||
|
||||
def get_masked_inputs(
|
||||
self, tokens: List[str], binary_mask_matrix: List[List[int]]
|
||||
) -> List[str]:
|
||||
"""
|
||||
Constructs partially-masked sentences for SHAP interpretation
|
||||
"""
|
||||
masked_inputs = []
|
||||
for binary_mask_vector in binary_mask_matrix:
|
||||
masked_input = np.array(tokens)[np.array(binary_mask_vector, dtype=bool)]
|
||||
masked_inputs.append(self.interpretation_separator.join(masked_input))
|
||||
return masked_inputs
|
||||
|
||||
def get_interpretation_scores(
|
||||
self, x, neighbors, scores: List[float], tokens: List[str], masks=None
|
||||
) -> List[Tuple[str, float]]:
|
||||
"""
|
||||
Returns:
|
||||
(List[Tuple[str, float]]): Each tuple set represents a set of characters and their corresponding interpretation score.
|
||||
"""
|
||||
result = []
|
||||
for token, score in zip(tokens, scores):
|
||||
result.append((token, score))
|
||||
result.append((self.interpretation_separator, 0))
|
||||
return result
|
||||
|
||||
def generate_sample(self) -> str:
|
||||
return "Hello World"
|
||||
|
||||
|
||||
class Number(InputComponent):
|
||||
"""
|
||||
Component creates a field for user to enter numeric input. Provides a number as an argument to the wrapped function.
|
||||
|
@ -21,7 +21,7 @@ import PIL
|
||||
from ffmpy import FFmpeg
|
||||
|
||||
from gradio import processing_utils
|
||||
from gradio.component import Component
|
||||
from gradio.component import Component, Textbox
|
||||
|
||||
if TYPE_CHECKING: # Only import for type checking (is False at runtime).
|
||||
from gradio import Interface
|
||||
@ -49,50 +49,6 @@ class OutputComponent(Component):
|
||||
return x
|
||||
|
||||
|
||||
class Textbox(OutputComponent):
|
||||
"""
|
||||
Component creates a textbox to render output text or number.
|
||||
Output type: Union[str, float, int]
|
||||
Demos: hello_world, sentence_builder
|
||||
"""
|
||||
|
||||
def __init__(self, type: str = "auto", label: Optional[str] = None):
|
||||
"""
|
||||
Parameters:
|
||||
type (str): Type of value to be passed to component. "str" expects a string, "number" expects a float value, "auto" detects return type.
|
||||
label (str): component name in interface.
|
||||
"""
|
||||
self.type = type
|
||||
super().__init__(label)
|
||||
|
||||
def get_template_context(self):
|
||||
return {**super().get_template_context()}
|
||||
|
||||
@classmethod
|
||||
def get_shortcut_implementations(cls):
|
||||
return {
|
||||
"text": {"type": "str"},
|
||||
"textbox": {"type": "str"},
|
||||
"number": {"type": "number"},
|
||||
}
|
||||
|
||||
def postprocess(self, y):
|
||||
"""
|
||||
Parameters:
|
||||
y (str): text output
|
||||
Returns:
|
||||
(Union[str, number]): output value
|
||||
"""
|
||||
if self.type == "str" or self.type == "auto":
|
||||
return str(y)
|
||||
elif self.type == "number":
|
||||
return y
|
||||
else:
|
||||
raise ValueError(
|
||||
"Unknown type: " + self.type + ". Please choose from: 'str', 'number'"
|
||||
)
|
||||
|
||||
|
||||
class Label(OutputComponent):
|
||||
"""
|
||||
Component outputs a classification label, along with confidence scores of top categories if provided. Confidence scores are represented as a dictionary mapping labels to scores between 0 and 1.
|
||||
|
Loading…
Reference in New Issue
Block a user