mirror of
https://github.com/gradio-app/gradio.git
synced 2024-12-21 02:19:59 +08:00
126 lines
6.7 KiB
Markdown
126 lines
6.7 KiB
Markdown
|
# Gradio Components: The Key Concepts
|
||
|
|
||
|
In this section, we discuss a few important concepts when it comes to components in Gradio.
|
||
|
It's important to understand these concepts when developing your own component.
|
||
|
Otherwise, your component may behave very different to other Gradio components!
|
||
|
|
||
|
Tip: You can skip this section if you are familiar with the internals of the Gradio library, such as each component's preprocess and postprocess methods.
|
||
|
|
||
|
## Interactive vs Static
|
||
|
|
||
|
Every component in Gradio comes in a `static` variant, and most come in an `interactive` version as well.
|
||
|
The `static` version is used when a component is displaying a value, and the user can **NOT** change that value by interacting with it.
|
||
|
The `interactive` version is used when the user is able to change the value by interacting with the Gradio UI.
|
||
|
|
||
|
Let's see some examples:
|
||
|
|
||
|
```python
|
||
|
import gradio as gr
|
||
|
|
||
|
with gr.Blocks() as demo:
|
||
|
gr.Textbox(value="Hello", interactive=True)
|
||
|
gr.Textbox(value="Hello", interactive=False)
|
||
|
|
||
|
demo.launch()
|
||
|
|
||
|
```
|
||
|
This will display two textboxes.
|
||
|
The only difference: you'll be able to edit the value of the Gradio component on top, and you won't be able to edit the variant on the bottom (i.e. the textbox will be disabled).
|
||
|
|
||
|
Perhaps a more interesting example is with the `Image` component:
|
||
|
|
||
|
```python
|
||
|
import gradio as gr
|
||
|
|
||
|
with gr.Blocks() as demo:
|
||
|
gr.Image(interactive=True)
|
||
|
gr.Image(interactive=False)
|
||
|
|
||
|
demo.launch()
|
||
|
```
|
||
|
|
||
|
The interactive version of the component is much more complex -- you can upload and edit images, draw sketches, etc. -- while the static version does not do any of that.
|
||
|
|
||
|
Not every component has an interactive version.
|
||
|
For example, the `gr.AnnotatedImage` only appears as a static version since there's no way to interactively change the value of the annotations or the image.
|
||
|
|
||
|
### What you need to remember
|
||
|
|
||
|
* Gradio will use the interactive version (if available) of a component if that component is used as the **input** to any event; otherwise, the static version will be used.
|
||
|
|
||
|
* When you design custom components, you **must** accept the boolean interactive keyword in the constructor of your Python class. In the frontend, accept the `interactive` property, a `bool` which represents whether the component is `static` or `interactive`.
|
||
|
|
||
|
## The value and how it is preprocessed/postprocessed
|
||
|
|
||
|
The most important attribute of a component is its `value`.
|
||
|
Every component has a `value`.
|
||
|
The value that is typically set by the user in the frontend (if the component is interactive) or displayed to the user (if it is static).
|
||
|
It is also this value that is sent to the backend function when a user triggers an event, or returned by the user's function e.g. at the end of a prediction.
|
||
|
|
||
|
So this value is passed around quite a bit, but sometimes the format of the value needs to change between the frontend and backend.
|
||
|
Take a look at this example:
|
||
|
|
||
|
```python
|
||
|
import numpy as np
|
||
|
import gradio as gr
|
||
|
|
||
|
def sepia(input_img):
|
||
|
sepia_filter = np.array([
|
||
|
[0.393, 0.769, 0.189],
|
||
|
[0.349, 0.686, 0.168],
|
||
|
[0.272, 0.534, 0.131]
|
||
|
])
|
||
|
sepia_img = input_img.dot(sepia_filter.T)
|
||
|
sepia_img /= sepia_img.max()
|
||
|
return sepia_img
|
||
|
|
||
|
demo = gr.Interface(sepia, gr.Image(shape=(200, 200)), "image")
|
||
|
demo.launch()
|
||
|
```
|
||
|
|
||
|
This will create a Gradio app which has an `Image` component as the input and the output.
|
||
|
In the frontend, the Image component will actually **upload** the file to the server and send the **filepath** but this is converted to a `numpy` array before it is sent to a user's function.
|
||
|
Conversely, when the user returns a `numpy` array from their function, the numpy array is converted to a file so that it can be sent to the frontend and displayed by the `Image` component.
|
||
|
|
||
|
Tip: By default, the `Image` component sends numpy arrays to the python function because it is a common choice for machine learning engineers, though the Image component also supports other formats using the `type` parameter. Read the `Image` docs [here](https://www.gradio.app/docs/image) to learn more.
|
||
|
|
||
|
Each component does two conversions:
|
||
|
|
||
|
1. `preprocess`: Converts the `value` from the format sent by the frontend to the format expected by the python function. This usually involves going from a web-friendly **JSON** structure to a **python-native** data structure, like a `numpy` array or `PIL` image. The `Audio`, `Image` components are good examples of `preprocess` methods.
|
||
|
|
||
|
2. `postprocess`: Converts the value returned by the python function to the format expected by the frontend. This usually involves going from a **python-native** data-structure, like a `PIL` image to a **JSON** structure.
|
||
|
|
||
|
### What you need to remember
|
||
|
|
||
|
* Every component must implement `preprocess` and `postprocess` methods. In the rare event that no conversion needs to happen, simply return the value as-is. `Textbox` and `Number` are examples of this.
|
||
|
|
||
|
* As a component author, **YOU** control the format of the data displayed in the frontend as well as the format of the data someone using your component will receive. Think of an ergonomic data-structure a **python** developer will find intuitive, and control the conversion from a **Web-friendly JSON** data structure (and vice-versa) with `preprocess` and `postprocess.`
|
||
|
|
||
|
## The "Example Version" of a Component
|
||
|
|
||
|
Gradio apps support providing example inputs -- and these are very useful in helping users get started using your Gradio app.
|
||
|
In `gr.Interface`, you can provide examples using the `examples` keyword, and in `Blocks`, you can provide examples using the special `gr.Examples` component.
|
||
|
|
||
|
At the bottom of this screenshot, we show a miniature example image of a cheetah that, when clicked, will populate the same image in the input Image component:
|
||
|
|
||
|
![img](https://user-images.githubusercontent.com/1778297/277548211-a3cb2133-2ffc-4cdf-9a83-3e8363b57ea6.png)
|
||
|
|
||
|
|
||
|
To enable the example view, you must have the following two files in the top of the `frontend` directory:
|
||
|
|
||
|
* `Example.svelte`: this corresponds to the "example version" of your component
|
||
|
* `Index.svelte`: this corresponds to the "regular version"
|
||
|
|
||
|
In the backend, you typically don't need to do anything unless you would like to modify the user-provided `value` of the examples to something else before it is sent to the frontend.
|
||
|
You can do this in the `as_example` method of the component.
|
||
|
|
||
|
The `Example.svelte` and `as_example` methods will be covered in greater depth in the dedicated [frontend](./frontend) and [backend](./backend) guides.
|
||
|
|
||
|
### What you need to remember
|
||
|
|
||
|
* If you expect your component to be used as input, it is important to define an "Example" view.
|
||
|
* If you don't, Gradio will use a default one but it won't be as informative as it can be!
|
||
|
|
||
|
## Conclusion
|
||
|
|
||
|
Now that you know the most important pieces to remember about Gradio components, you can start to design and build your own!
|