From b84a35b7b91eca947f787648ceb361b1d023427b Mon Sep 17 00:00:00 2001
From: Ali Abdalla
` in `gr.Markdown()` or `gr.Chatbot()`. For multiple new lines, a developer must add multiple `
` tags.\n\n### Full Changelog:\n\n- Safer version of `gr.HuggingFaceDatasetSaver` using HTTP methods instead of git pull/push by [@Wauplin](https://github.com/Wauplin) in [PR 3973](https://github.com/gradio-app/gradio/pull/3973)\n\n#\n\n## 3.28.1\n\n### New Features:\n\n- Add a \"clear mask\" button to `gr.Image` sketch modes, by [@space-nuko](https://github.com/space-nuko) in [PR 3615](https://github.com/gradio-app/gradio/pull/3615)\n\n### Bug Fixes:\n\n- Fix dropdown default value not appearing by [@aliabid94](https://github.com/aliabid94) in [PR 3996](https://github.com/gradio-app/gradio/pull/3996).\n- Fix faded coloring of output textboxes in iOS / Safari by [@aliabid94](https://github.com/aliabid94) in [PR 3993](https://github.com/gradio-app/gradio/pull/3993)\n\n#\n\n### Testing and Infrastructure Changes:\n\n- CI: Simplified Python CI workflow by [@akx](https://github.com/akx) in [PR 3982](https://github.com/gradio-app/gradio/pull/3982)\n- Upgrade pyright to 1.1.305 by [@akx](https://github.com/akx) in [PR 4042](https://github.com/gradio-app/gradio/pull/4042)\n- More Ruff rules are enabled and lint errors fixed by [@akx](https://github.com/akx) in [PR 4038](https://github.com/gradio-app/gradio/pull/4038)\n\n#\n\n#\n\n#\n\n## 3.28.0\n\n### Bug Fixes:\n\n- Fix duplicate play commands in full-screen mode of 'video'. by [@tomchang25](https://github.com/tomchang25) in [PR 3968](https://github.com/gradio-app/gradio/pull/3968).\n- Fix the issue of the UI stuck caused by the 'selected' of DataFrame not being reset. by [@tomchang25](https://github.com/tomchang25) in [PR 3916](https://github.com/gradio-app/gradio/pull/3916).\n- Fix issue where `gr.Video()` would not work inside a `gr.Tab()` by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3891](https://github.com/gradio-app/gradio/pull/3891)\n- Fixed issue with old_value check in File. by [@tomchang25](https://github.com/tomchang25) in [PR 3859](https://github.com/gradio-app/gradio/pull/3859).\n- Fixed bug where all bokeh plots appeared in the same div by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3896](https://github.com/gradio-app/gradio/pull/3896)\n- Fixed image outputs to automatically take full output image height, unless explicitly set, by [@aliabid94](https://github.com/aliabid94) in [PR 3905](https://github.com/gradio-app/gradio/pull/3905)\n- Fix issue in `gr.Gallery()` where setting height causes aspect ratio of images to collapse by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3830](https://github.com/gradio-app/gradio/pull/3830)\n- Fix issue where requesting for a non-existing file would trigger a 500 error by [@micky2be](https://github.com/micky2be) in `[PR 3895](https://github.com/gradio-app/gradio/pull/3895)`.\n- Fix bugs with abspath about symlinks, and unresolvable path on Windows by [@micky2be](https://github.com/micky2be) in `[PR 3895](https://github.com/gradio-app/gradio/pull/3895)`.\n- Fixes type in client `Status` enum by [@10zinten](https://github.com/10zinten) in [PR 3931](https://github.com/gradio-app/gradio/pull/3931)\n- Fix `gr.ChatBot` to handle image url [tye-singwa](https://github.com/tye-signwa) in [PR 3953](https://github.com/gradio-app/gradio/pull/3953)\n- Move Google Tag Manager related initialization code to analytics-enabled block by [@akx](https://github.com/akx) in [PR 3956](https://github.com/gradio-app/gradio/pull/3956)\n- Fix bug where port was not reused if the demo was closed and then re-launched by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3896](https://github.com/gradio-app/gradio/pull/3959)\n- Fixes issue where dropdown does not position itself at selected element when opened [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3639](https://github.com/gradio-app/gradio/pull/3639)\n\n### Documentation Changes:\n\n- Make use of `gr` consistent across the docs by [@duerrsimon](https://github.com/duerrsimon) in [PR 3901](https://github.com/gradio-app/gradio/pull/3901)\n- Fixed typo in theming-guide.md by [@eltociear](https://github.com/eltociear) in [PR 3952](https://github.com/gradio-app/gradio/pull/3952)\n\n### Testing and Infrastructure Changes:\n\n- CI: Python backend lint is only run once, by [@akx](https://github.com/akx) in [PR 3960](https://github.com/gradio-app/gradio/pull/3960)\n- Format invocations and concatenations were replaced by f-strings where possible by [@akx](https://github.com/akx) in [PR 3984](https://github.com/gradio-app/gradio/pull/3984)\n- Linting rules were made more strict and issues fixed by [@akx](https://github.com/akx) in [PR 3979](https://github.com/gradio-app/gradio/pull/3979).\n\n### Breaking Changes:\n\n- Some re-exports in `gradio.themes` utilities (introduced in 3.24.0) have been eradicated.\n By [@akx](https://github.com/akx) in [PR 3958](https://github.com/gradio-app/gradio/pull/3958)\n\n### Full Changelog:\n\n- Add DESCRIPTION.md to image_segmentation demo by [@aliabd](https://github.com/aliabd) in [PR 3866](https://github.com/gradio-app/gradio/pull/3866)\n- Fix error in running `gr.themes.builder()` by [@deepkyu](https://github.com/deepkyu) in [PR 3869](https://github.com/gradio-app/gradio/pull/3869)\n- Fixed a JavaScript TypeError when loading custom JS with `_js` and setting `outputs` to `None` in `gradio.Blocks()` by [@DavG25](https://github.com/DavG25) in [PR 3883](https://github.com/gradio-app/gradio/pull/3883)\n- Fixed bg_background_fill theme property to expand to whole background, block_radius to affect form elements as well, and added block_label_shadow theme property by [@aliabid94](https://github.com/aliabid94) in [PR 3590](https://github.com/gradio-app/gradio/pull/3590)\n\n#\n\n## 3.27.0\n\n### New Features:\n\n###### AnnotatedImage Component\n\nNew AnnotatedImage component allows users to highlight regions of an image, either by providing bounding boxes, or 0-1 pixel masks. This component is useful for tasks such as image segmentation, object detection, and image captioning.\n\n![AnnotatedImage screenshot](https://user-images.githubusercontent.com/7870876/232142720-86e0020f-beaf-47b9-a843-689c9621f09c.gif)\n\nExample usage:\n\n```python\nwith gr.Blocks() as demo:\n img = gr.Image()\n img_section = gr.AnnotatedImage()\n def mask(img):\n top_left_corner = [0, 0, 20, 20]\n random_mask = np.random.randint(0, 2, img.shape[:2])\n return (img, [(top_left_corner, \"left corner\"), (random_mask, \"random\")])\n img.change(mask, img, img_section)\n```\n\nSee the [image_segmentation demo](https://github.com/gradio-app/gradio/tree/main/demo/image_segmentation) for a full example. By [@aliabid94](https://github.com/aliabid94) in [PR 3836](https://github.com/gradio-app/gradio/pull/3836)\n\n#\n\n#\n\n#\n\n#\n\n#\n\n#\n\n## 3.26.0\n\n### New Features:\n\n###### `Video` component supports subtitles\n\n- Allow the video component to accept subtitles as input, by [@tomchang25](https://github.com/tomchang25) in [PR 3673](https://github.com/gradio-app/gradio/pull/3673). To provide subtitles, simply return a tuple consisting of `(path_to_video, path_to_subtitles)` from your function. Both `.srt` and `.vtt` formats are supported:\n\n```py\nwith gr.Blocks() as demo:\n gr.Video((\"video.mp4\", \"captions.srt\"))\n```\n\n### Bug Fixes:\n\n- Fix code markdown support in `gr.Chatbot()` component by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3816](https://github.com/gradio-app/gradio/pull/3816)\n\n### Documentation Changes:\n\n- Updates the \"view API\" page in Gradio apps to use the `gradio_client` library by [@aliabd](https://github.com/aliabd) in [PR 3765](https://github.com/gradio-app/gradio/pull/3765)\n\n- Read more about how to use the `gradio_client` library here: https://gradio.app/getting-started-with-the-python-client/\n\n#\n\n#\n\n#\n\n#\n\n## 3.25.0\n\n### New Features:\n\n- Improve error messages when number of inputs/outputs to event handlers mismatch, by [@space-nuko](https://github.com/space-nuko) in [PR 3519](https://github.com/gradio-app/gradio/pull/3519)\n\n- Add `select` listener to Images, allowing users to click on any part of an image and get the coordinates of the click by [@aliabid94](https://github.com/aliabid94) in [PR 3786](https://github.com/gradio-app/gradio/pull/3786).\n\n```python\nwith gr.Blocks() as demo:\n img = gr.Image()\n textbox = gr.Textbox()\n\n def select_handler(img, evt: gr.SelectData):\n selected_pixel = img[evt.index[1], evt.index[0]]\n return f\"Selected pixel: {selected_pixel}\"\n\n img.select(select_handler, img, textbox)\n```\n\n![Recording 2023-04-08 at 17 44 39](https://user-images.githubusercontent.com/7870876/230748572-90a2a8d5-116d-4769-bb53-5516555fbd0f.gif)\n\n### Bug Fixes:\n\n- Increase timeout for sending analytics data by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3647](https://github.com/gradio-app/gradio/pull/3647)\n- Fix bug where http token was not accessed over websocket connections by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3735](https://github.com/gradio-app/gradio/pull/3735)\n- Add ability to specify `rows`, `columns` and `object-fit` in `style()` for `gr.Gallery()` component by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3586](https://github.com/gradio-app/gradio/pull/3586)\n- Fix bug where recording an audio file through the microphone resulted in a corrupted file name by [@abidlabs](https://github.com/abidlabs) in [PR 3770](https://github.com/gradio-app/gradio/pull/3770)\n- Added \"ssl_verify\" to blocks.launch method to allow for use of self-signed certs by [@garrettsutula](https://github.com/garrettsutula) in [PR 3873](https://github.com/gradio-app/gradio/pull/3873)\n- Fix bug where iterators where not being reset for processes that terminated early by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3777](https://github.com/gradio-app/gradio/pull/3777)\n- Fix bug where the upload button was not properly handling the `file_count='multiple'` case by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3782](https://github.com/gradio-app/gradio/pull/3782)\n- Fix bug where use Via API button was giving error by [@Devang-C](https://github.com/Devang-C) in [PR 3783](https://github.com/gradio-app/gradio/pull/3783)\n\n### Documentation Changes:\n\n- Fix invalid argument docstrings, by [@akx](https://github.com/akx) in [PR 3740](https://github.com/gradio-app/gradio/pull/3740)\n\n#\n\n#\n\n### Full Changelog:\n\n- Fixed IPv6 listening to work with bracket [::1] notation, by [@dsully](https://github.com/dsully) in [PR 3695](https://github.com/gradio-app/gradio/pull/3695)\n\n#\n\n## 3.24.1\n\n### New Features:\n\n- No changes to highlight.\n\n### Bug Fixes:\n\n- Fixes Chatbot issue where new lines were being created every time a message was sent back and forth by [@aliabid94](https://github.com/aliabid94) in [PR 3717](https://github.com/gradio-app/gradio/pull/3717).\n- Fixes data updating in DataFrame invoking a `select` event once the dataframe has been selected. By [@yiyuezhuo](https://github.com/yiyuezhuo) in [PR 3861](https://github.com/gradio-app/gradio/pull/3861)\n- Fixes false positive warning which is due to too strict type checking by [@yiyuezhuo](https://github.com/yiyuezhuo) in [PR 3837](https://github.com/gradio-app/gradio/pull/3837).\n\n#\n\n#\n\n#\n\n#\n\n#\n\n## 3.24.0\n\n### New Features:\n\n- Trigger the release event when Slider number input is released or unfocused by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3589](https://github.com/gradio-app/gradio/pull/3589)\n- Created Theme Builder, which allows users to create themes without writing any code, by [@aliabid94](https://github.com/aliabid94) in [PR 3664](https://github.com/gradio-app/gradio/pull/3664). Launch by:\n\n ```python\n import gradio as gr\n gr.themes.builder()\n ```\n\n ![Theme Builder](https://user-images.githubusercontent.com/7870876/228204929-d71cbba5-69c2-45b3-bd20-e3a201d98b12.png)\n\n- The `Dropdown` component now has a `allow_custom_value` parameter that lets users type in custom values not in the original list of choices.\n- The `Colorpicker` component now has a `.blur()` event\n\n###### Added a download button for videos! \ud83d\udce5\n\n![download_video](https://user-images.githubusercontent.com/41651716/227009612-9bc5fb72-2a44-4c55-9b7b-a0fa098e7f25.gif)\n\nBy [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3581](https://github.com/gradio-app/gradio/pull/3581).\n\n- Trigger the release event when Slider number input is released or unfocused by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3589](https://github.com/gradio-app/gradio/pull/3589)\n\n### Bug Fixes:\n\n- Fixed bug where text for altair plots was not legible in dark mode by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3555](https://github.com/gradio-app/gradio/pull/3555)\n- Fixes `Chatbot` and `Image` components so that files passed during processing are added to a directory where they can be served from, by [@abidlabs](https://github.com/abidlabs) in [PR 3523](https://github.com/gradio-app/gradio/pull/3523)\n- Use Gradio API server to send telemetry using `huggingface_hub` [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3488](https://github.com/gradio-app/gradio/pull/3488)\n- Fixes an an issue where if the Blocks scope was not exited, then State could be shared across sessions, by [@abidlabs](https://github.com/abidlabs) in [PR 3600](https://github.com/gradio-app/gradio/pull/3600)\n- Ensures that `gr.load()` loads and applies the upstream theme, by [@abidlabs](https://github.com/abidlabs) in [PR 3641](https://github.com/gradio-app/gradio/pull/3641)\n- Fixed bug where \"or\" was not being localized in file upload text by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3599](https://github.com/gradio-app/gradio/pull/3599)\n- Fixed bug where chatbot does not autoscroll inside of a tab, row or column by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3637](https://github.com/gradio-app/gradio/pull/3637)\n- Fixed bug where textbox shrinks when `lines` set to larger than 20 by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3637](https://github.com/gradio-app/gradio/pull/3637)\n- Ensure CSS has fully loaded before rendering the application, by [@pngwn](https://github.com/pngwn) in [PR 3573](https://github.com/gradio-app/gradio/pull/3573)\n- Support using an empty list as `gr.Dataframe` value, by [@space-nuko](https://github.com/space-nuko) in [PR 3646](https://github.com/gradio-app/gradio/pull/3646)\n- Fixed `gr.Image` not filling the entire element size, by [@space-nuko](https://github.com/space-nuko) in [PR 3649](https://github.com/gradio-app/gradio/pull/3649)\n- Make `gr.Code` support the `lines` property, by [@space-nuko](https://github.com/space-nuko) in [PR 3651](https://github.com/gradio-app/gradio/pull/3651)\n- Fixes certain `_js` return values being double wrapped in an array, by [@space-nuko](https://github.com/space-nuko) in [PR 3594](https://github.com/gradio-app/gradio/pull/3594)\n- Correct the documentation of `gr.File` component to state that its preprocessing method converts the uploaded file to a temporary file, by @RussellLuo in [PR 3660](https://github.com/gradio-app/gradio/pull/3660)\n- Fixed bug in Serializer ValueError text by [@osanseviero](https://github.com/osanseviero) in [PR 3669](https://github.com/gradio-app/gradio/pull/3669)\n- Fix default parameter argument and `gr.Progress` used in same function, by [@space-nuko](https://github.com/space-nuko) in [PR 3671](https://github.com/gradio-app/gradio/pull/3671)\n- Hide `Remove All` button in `gr.Dropdown` single-select mode by [@space-nuko](https://github.com/space-nuko) in [PR 3678](https://github.com/gradio-app/gradio/pull/3678)\n- Fix broken spaces in docs by [@aliabd](https://github.com/aliabd) in [PR 3698](https://github.com/gradio-app/gradio/pull/3698)\n- Fix items in `gr.Dropdown` besides the selected item receiving a checkmark, by [@space-nuko](https://github.com/space-nuko) in [PR 3644](https://github.com/gradio-app/gradio/pull/3644)\n- Fix several `gr.Dropdown` issues and improve usability, by [@space-nuko](https://github.com/space-nuko) in [PR 3705](https://github.com/gradio-app/gradio/pull/3705)\n\n### Documentation Changes:\n\n- Makes some fixes to the Theme Guide related to naming of variables, by [@abidlabs](https://github.com/abidlabs) in [PR 3561](https://github.com/gradio-app/gradio/pull/3561)\n- Documented `HuggingFaceDatasetJSONSaver` by [@osanseviero](https://github.com/osanseviero) in [PR 3604](https://github.com/gradio-app/gradio/pull/3604)\n- Makes some additions to documentation of `Audio` and `State` components, and fixes the `pictionary` demo by [@abidlabs](https://github.com/abidlabs) in [PR 3611](https://github.com/gradio-app/gradio/pull/3611)\n- Fix outdated sharing your app guide by [@aliabd](https://github.com/aliabd) in [PR 3699](https://github.com/gradio-app/gradio/pull/3699)\n\n### Testing and Infrastructure Changes:\n\n- Removed heavily-mocked tests related to comet_ml, wandb, and mlflow as they added a significant amount of test dependencies that prevented installation of test dependencies on Windows environments. By [@abidlabs](https://github.com/abidlabs) in [PR 3608](https://github.com/gradio-app/gradio/pull/3608)\n- Added Windows continuous integration, by [@space-nuko](https://github.com/space-nuko) in [PR 3628](https://github.com/gradio-app/gradio/pull/3628)\n- Switched linting from flake8 + isort to `ruff`, by [@akx](https://github.com/akx) in [PR 3710](https://github.com/gradio-app/gradio/pull/3710)\n\n#\n\n### Full Changelog:\n\n- Mobile responsive iframes in themes guide by [@aliabd](https://github.com/aliabd) in [PR 3562](https://github.com/gradio-app/gradio/pull/3562)\n- Remove extra $demo from theme guide by [@aliabd](https://github.com/aliabd) in [PR 3563](https://github.com/gradio-app/gradio/pull/3563)\n- Set the theme name to be the upstream repo name when loading from the hub by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3595](https://github.com/gradio-app/gradio/pull/3595)\n- Copy everything in website Dockerfile, fix build issues by [@aliabd](https://github.com/aliabd) in [PR 3659](https://github.com/gradio-app/gradio/pull/3659)\n- Raise error when an event is queued but the queue is not configured by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3640](https://github.com/gradio-app/gradio/pull/3640)\n- Allows users to apss in a string name for a built-in theme, by [@abidlabs](https://github.com/abidlabs) in [PR 3641](https://github.com/gradio-app/gradio/pull/3641)\n- Added `orig_name` to Video output in the backend so that the front end can set the right name for downloaded video files by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3700](https://github.com/gradio-app/gradio/pull/3700)\n\n#\n\n## 3.23.0\n\n### New Features:\n\n###### Theme Sharing!\n\nOnce you have created a theme, you can upload it to the HuggingFace Hub to let others view it, use it, and build off of it! You can also download, reuse, and remix other peoples' themes. See https://gradio.app/theming-guide/ for more details.\n\nBy [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3428](https://github.com/gradio-app/gradio/pull/3428)\n\n### Bug Fixes:\n\n- Removes leading spaces from all lines of code uniformly in the `gr.Code()` component. By [@abidlabs](https://github.com/abidlabs) in [PR 3556](https://github.com/gradio-app/gradio/pull/3556)\n- Fixed broken login page, by [@aliabid94](https://github.com/aliabid94) in [PR 3529](https://github.com/gradio-app/gradio/pull/3529)\n\n#\n\n#\n\n#\n\n### Full Changelog:\n\n- Fix rendering of dropdowns to take more space, and related bugs, by [@aliabid94](https://github.com/aliabid94) in [PR 3549](https://github.com/gradio-app/gradio/pull/3549)\n\n#\n\n## 3.22.1\n\n#\n\n### Bug Fixes:\n\n- Restore label bars by [@aliabid94](https://github.com/aliabid94) in [PR 3507](https://github.com/gradio-app/gradio/pull/3507)\n\n#\n\n#\n\n#\n\n#\n\n#\n\n## 3.22.0\n\n### New Features:\n\n###### Official Theme release\n\nGradio now supports a new theme system, which allows you to customize the look and feel of your app. You can now use the `theme=` kwarg to pass in a prebuilt theme, or customize your own! See https://gradio.app/theming-guide/ for more details. By [@aliabid94](https://github.com/aliabid94) in [PR 3470](https://github.com/gradio-app/gradio/pull/3470) and [PR 3497](https://github.com/gradio-app/gradio/pull/3497)\n\n###### `elem_classes`\n\nAdd keyword argument `elem_classes` to Components to control class names of components, in the same manner as existing `elem_id`.\nBy [@aliabid94](https://github.com/aliabid94) in [PR 3466](https://github.com/gradio-app/gradio/pull/3466)\n\n### Bug Fixes:\n\n- Fixes the File.upload() event trigger which broke as part of the change in how we uploaded files by [@abidlabs](https://github.com/abidlabs) in [PR 3462](https://github.com/gradio-app/gradio/pull/3462)\n- Fixed issue with `gr.Request` object failing to handle dictionaries when nested keys couldn't be converted to variable names [#3454](https://github.com/gradio-app/gradio/issues/3454) by [@radames](https://github.com/radames) in [PR 3459](https://github.com/gradio-app/gradio/pull/3459)\n- Fixed bug where css and client api was not working properly when mounted in a subpath by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3482](https://github.com/gradio-app/gradio/pull/3482)\n\n### Documentation Changes:\n\n- Document gr.Error in the docs by [@aliabd](https://github.com/aliabd) in [PR 3465](https://github.com/gradio-app/gradio/pull/3465)\n\n### Testing and Infrastructure Changes:\n\n- Pinned `pyright==1.1.298` for stability by [@abidlabs](https://github.com/abidlabs) in [PR 3475](https://github.com/gradio-app/gradio/pull/3475)\n- Removed `IOComponent.add_interactive_to_config()` by [@space-nuko](https://github.com/space-nuko) in [PR 3476](https://github.com/gradio-app/gradio/pull/3476)\n- Removed `IOComponent.generate_sample()` by [@space-nuko](https://github.com/space-nuko) in [PR 3475](https://github.com/gradio-app/gradio/pull/3483)\n\n#\n\n### Full Changelog:\n\n- Revert primary button background color in dark mode by [@aliabid94](https://github.com/aliabid94) in [PR 3468](https://github.com/gradio-app/gradio/pull/3468)\n\n#\n\n## 3.21.0\n\n### New Features:\n\n###### Theme Sharing \ud83c\udfa8 \ud83e\udd1d\n\nYou can now share your gradio themes with the world!\n\nAfter creating a theme, you can upload it to the HuggingFace Hub to let others view it, use it, and build off of it!\n\n###### Uploading\n\nThere are two ways to upload a theme, via the theme class instance or the command line.\n\n1. Via the class instance\n\n```python\nmy_theme.push_to_hub(repo_name=\"my_theme\",\n version=\"0.2.0\",\n hf_token=\"...\")\n```\n\n2. Via the command line\n\nFirst save the theme to disk\n\n```python\nmy_theme.dump(filename=\"my_theme.json\")\n```\n\nThen use the `upload_theme` command:\n\n```bash\nupload_theme\\\n\"my_theme.json\"\\\n\"my_theme\"\\\n\"0.2.0\"\\\n\"
` in `gr.Markdown()` or `gr.Chatbot()`. For multiple new lines, a developer must add multiple `
` tags.\n\n### Full Changelog:\n\n- Safer version of `gr.HuggingFaceDatasetSaver` using HTTP methods instead of git pull/push by [@Wauplin](https://github.com/Wauplin) in [PR 3973](https://github.com/gradio-app/gradio/pull/3973)\n\n#\n\n## 3.28.1\n\n### New Features:\n\n- Add a \"clear mask\" button to `gr.Image` sketch modes, by [@space-nuko](https://github.com/space-nuko) in [PR 3615](https://github.com/gradio-app/gradio/pull/3615)\n\n### Bug Fixes:\n\n- Fix dropdown default value not appearing by [@aliabid94](https://github.com/aliabid94) in [PR 3996](https://github.com/gradio-app/gradio/pull/3996).\n- Fix faded coloring of output textboxes in iOS / Safari by [@aliabid94](https://github.com/aliabid94) in [PR 3993](https://github.com/gradio-app/gradio/pull/3993)\n\n#\n\n### Testing and Infrastructure Changes:\n\n- CI: Simplified Python CI workflow by [@akx](https://github.com/akx) in [PR 3982](https://github.com/gradio-app/gradio/pull/3982)\n- Upgrade pyright to 1.1.305 by [@akx](https://github.com/akx) in [PR 4042](https://github.com/gradio-app/gradio/pull/4042)\n- More Ruff rules are enabled and lint errors fixed by [@akx](https://github.com/akx) in [PR 4038](https://github.com/gradio-app/gradio/pull/4038)\n\n#\n\n#\n\n#\n\n## 3.28.0\n\n### Bug Fixes:\n\n- Fix duplicate play commands in full-screen mode of 'video'. by [@tomchang25](https://github.com/tomchang25) in [PR 3968](https://github.com/gradio-app/gradio/pull/3968).\n- Fix the issue of the UI stuck caused by the 'selected' of DataFrame not being reset. by [@tomchang25](https://github.com/tomchang25) in [PR 3916](https://github.com/gradio-app/gradio/pull/3916).\n- Fix issue where `gr.Video()` would not work inside a `gr.Tab()` by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3891](https://github.com/gradio-app/gradio/pull/3891)\n- Fixed issue with old_value check in File. by [@tomchang25](https://github.com/tomchang25) in [PR 3859](https://github.com/gradio-app/gradio/pull/3859).\n- Fixed bug where all bokeh plots appeared in the same div by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3896](https://github.com/gradio-app/gradio/pull/3896)\n- Fixed image outputs to automatically take full output image height, unless explicitly set, by [@aliabid94](https://github.com/aliabid94) in [PR 3905](https://github.com/gradio-app/gradio/pull/3905)\n- Fix issue in `gr.Gallery()` where setting height causes aspect ratio of images to collapse by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3830](https://github.com/gradio-app/gradio/pull/3830)\n- Fix issue where requesting for a non-existing file would trigger a 500 error by [@micky2be](https://github.com/micky2be) in `[PR 3895](https://github.com/gradio-app/gradio/pull/3895)`.\n- Fix bugs with abspath about symlinks, and unresolvable path on Windows by [@micky2be](https://github.com/micky2be) in `[PR 3895](https://github.com/gradio-app/gradio/pull/3895)`.\n- Fixes type in client `Status` enum by [@10zinten](https://github.com/10zinten) in [PR 3931](https://github.com/gradio-app/gradio/pull/3931)\n- Fix `gr.ChatBot` to handle image url [tye-singwa](https://github.com/tye-signwa) in [PR 3953](https://github.com/gradio-app/gradio/pull/3953)\n- Move Google Tag Manager related initialization code to analytics-enabled block by [@akx](https://github.com/akx) in [PR 3956](https://github.com/gradio-app/gradio/pull/3956)\n- Fix bug where port was not reused if the demo was closed and then re-launched by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3896](https://github.com/gradio-app/gradio/pull/3959)\n- Fixes issue where dropdown does not position itself at selected element when opened [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3639](https://github.com/gradio-app/gradio/pull/3639)\n\n### Documentation Changes:\n\n- Make use of `gr` consistent across the docs by [@duerrsimon](https://github.com/duerrsimon) in [PR 3901](https://github.com/gradio-app/gradio/pull/3901)\n- Fixed typo in theming-guide.md by [@eltociear](https://github.com/eltociear) in [PR 3952](https://github.com/gradio-app/gradio/pull/3952)\n\n### Testing and Infrastructure Changes:\n\n- CI: Python backend lint is only run once, by [@akx](https://github.com/akx) in [PR 3960](https://github.com/gradio-app/gradio/pull/3960)\n- Format invocations and concatenations were replaced by f-strings where possible by [@akx](https://github.com/akx) in [PR 3984](https://github.com/gradio-app/gradio/pull/3984)\n- Linting rules were made more strict and issues fixed by [@akx](https://github.com/akx) in [PR 3979](https://github.com/gradio-app/gradio/pull/3979).\n\n### Breaking Changes:\n\n- Some re-exports in `gradio.themes` utilities (introduced in 3.24.0) have been eradicated.\n By [@akx](https://github.com/akx) in [PR 3958](https://github.com/gradio-app/gradio/pull/3958)\n\n### Full Changelog:\n\n- Add DESCRIPTION.md to image_segmentation demo by [@aliabd](https://github.com/aliabd) in [PR 3866](https://github.com/gradio-app/gradio/pull/3866)\n- Fix error in running `gr.themes.builder()` by [@deepkyu](https://github.com/deepkyu) in [PR 3869](https://github.com/gradio-app/gradio/pull/3869)\n- Fixed a JavaScript TypeError when loading custom JS with `_js` and setting `outputs` to `None` in `gradio.Blocks()` by [@DavG25](https://github.com/DavG25) in [PR 3883](https://github.com/gradio-app/gradio/pull/3883)\n- Fixed bg_background_fill theme property to expand to whole background, block_radius to affect form elements as well, and added block_label_shadow theme property by [@aliabid94](https://github.com/aliabid94) in [PR 3590](https://github.com/gradio-app/gradio/pull/3590)\n\n#\n\n## 3.27.0\n\n### New Features:\n\n###### AnnotatedImage Component\n\nNew AnnotatedImage component allows users to highlight regions of an image, either by providing bounding boxes, or 0-1 pixel masks. This component is useful for tasks such as image segmentation, object detection, and image captioning.\n\n![AnnotatedImage screenshot](https://user-images.githubusercontent.com/7870876/232142720-86e0020f-beaf-47b9-a843-689c9621f09c.gif)\n\nExample usage:\n\n```python\nwith gr.Blocks() as demo:\n img = gr.Image()\n img_section = gr.AnnotatedImage()\n def mask(img):\n top_left_corner = [0, 0, 20, 20]\n random_mask = np.random.randint(0, 2, img.shape[:2])\n return (img, [(top_left_corner, \"left corner\"), (random_mask, \"random\")])\n img.change(mask, img, img_section)\n```\n\nSee the [image_segmentation demo](https://github.com/gradio-app/gradio/tree/main/demo/image_segmentation) for a full example. By [@aliabid94](https://github.com/aliabid94) in [PR 3836](https://github.com/gradio-app/gradio/pull/3836)\n\n#\n\n#\n\n#\n\n#\n\n#\n\n#\n\n## 3.26.0\n\n### New Features:\n\n###### `Video` component supports subtitles\n\n- Allow the video component to accept subtitles as input, by [@tomchang25](https://github.com/tomchang25) in [PR 3673](https://github.com/gradio-app/gradio/pull/3673). To provide subtitles, simply return a tuple consisting of `(path_to_video, path_to_subtitles)` from your function. Both `.srt` and `.vtt` formats are supported:\n\n```py\nwith gr.Blocks() as demo:\n gr.Video((\"video.mp4\", \"captions.srt\"))\n```\n\n### Bug Fixes:\n\n- Fix code markdown support in `gr.Chatbot()` component by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3816](https://github.com/gradio-app/gradio/pull/3816)\n\n### Documentation Changes:\n\n- Updates the \"view API\" page in Gradio apps to use the `gradio_client` library by [@aliabd](https://github.com/aliabd) in [PR 3765](https://github.com/gradio-app/gradio/pull/3765)\n\n- Read more about how to use the `gradio_client` library here: https://gradio.app/getting-started-with-the-python-client/\n\n#\n\n#\n\n#\n\n#\n\n## 3.25.0\n\n### New Features:\n\n- Improve error messages when number of inputs/outputs to event handlers mismatch, by [@space-nuko](https://github.com/space-nuko) in [PR 3519](https://github.com/gradio-app/gradio/pull/3519)\n\n- Add `select` listener to Images, allowing users to click on any part of an image and get the coordinates of the click by [@aliabid94](https://github.com/aliabid94) in [PR 3786](https://github.com/gradio-app/gradio/pull/3786).\n\n```python\nwith gr.Blocks() as demo:\n img = gr.Image()\n textbox = gr.Textbox()\n\n def select_handler(img, evt: gr.SelectData):\n selected_pixel = img[evt.index[1], evt.index[0]]\n return f\"Selected pixel: {selected_pixel}\"\n\n img.select(select_handler, img, textbox)\n```\n\n![Recording 2023-04-08 at 17 44 39](https://user-images.githubusercontent.com/7870876/230748572-90a2a8d5-116d-4769-bb53-5516555fbd0f.gif)\n\n### Bug Fixes:\n\n- Increase timeout for sending analytics data by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3647](https://github.com/gradio-app/gradio/pull/3647)\n- Fix bug where http token was not accessed over websocket connections by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3735](https://github.com/gradio-app/gradio/pull/3735)\n- Add ability to specify `rows`, `columns` and `object-fit` in `style()` for `gr.Gallery()` component by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3586](https://github.com/gradio-app/gradio/pull/3586)\n- Fix bug where recording an audio file through the microphone resulted in a corrupted file name by [@abidlabs](https://github.com/abidlabs) in [PR 3770](https://github.com/gradio-app/gradio/pull/3770)\n- Added \"ssl_verify\" to blocks.launch method to allow for use of self-signed certs by [@garrettsutula](https://github.com/garrettsutula) in [PR 3873](https://github.com/gradio-app/gradio/pull/3873)\n- Fix bug where iterators where not being reset for processes that terminated early by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3777](https://github.com/gradio-app/gradio/pull/3777)\n- Fix bug where the upload button was not properly handling the `file_count='multiple'` case by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3782](https://github.com/gradio-app/gradio/pull/3782)\n- Fix bug where use Via API button was giving error by [@Devang-C](https://github.com/Devang-C) in [PR 3783](https://github.com/gradio-app/gradio/pull/3783)\n\n### Documentation Changes:\n\n- Fix invalid argument docstrings, by [@akx](https://github.com/akx) in [PR 3740](https://github.com/gradio-app/gradio/pull/3740)\n\n#\n\n#\n\n### Full Changelog:\n\n- Fixed IPv6 listening to work with bracket [::1] notation, by [@dsully](https://github.com/dsully) in [PR 3695](https://github.com/gradio-app/gradio/pull/3695)\n\n#\n\n## 3.24.1\n\n### New Features:\n\n- No changes to highlight.\n\n### Bug Fixes:\n\n- Fixes Chatbot issue where new lines were being created every time a message was sent back and forth by [@aliabid94](https://github.com/aliabid94) in [PR 3717](https://github.com/gradio-app/gradio/pull/3717).\n- Fixes data updating in DataFrame invoking a `select` event once the dataframe has been selected. By [@yiyuezhuo](https://github.com/yiyuezhuo) in [PR 3861](https://github.com/gradio-app/gradio/pull/3861)\n- Fixes false positive warning which is due to too strict type checking by [@yiyuezhuo](https://github.com/yiyuezhuo) in [PR 3837](https://github.com/gradio-app/gradio/pull/3837).\n\n#\n\n#\n\n#\n\n#\n\n#\n\n## 3.24.0\n\n### New Features:\n\n- Trigger the release event when Slider number input is released or unfocused by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3589](https://github.com/gradio-app/gradio/pull/3589)\n- Created Theme Builder, which allows users to create themes without writing any code, by [@aliabid94](https://github.com/aliabid94) in [PR 3664](https://github.com/gradio-app/gradio/pull/3664). Launch by:\n\n ```python\n import gradio as gr\n gr.themes.builder()\n ```\n\n ![Theme Builder](https://user-images.githubusercontent.com/7870876/228204929-d71cbba5-69c2-45b3-bd20-e3a201d98b12.png)\n\n- The `Dropdown` component now has a `allow_custom_value` parameter that lets users type in custom values not in the original list of choices.\n- The `Colorpicker` component now has a `.blur()` event\n\n###### Added a download button for videos! \ud83d\udce5\n\n![download_video](https://user-images.githubusercontent.com/41651716/227009612-9bc5fb72-2a44-4c55-9b7b-a0fa098e7f25.gif)\n\nBy [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3581](https://github.com/gradio-app/gradio/pull/3581).\n\n- Trigger the release event when Slider number input is released or unfocused by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3589](https://github.com/gradio-app/gradio/pull/3589)\n\n### Bug Fixes:\n\n- Fixed bug where text for altair plots was not legible in dark mode by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3555](https://github.com/gradio-app/gradio/pull/3555)\n- Fixes `Chatbot` and `Image` components so that files passed during processing are added to a directory where they can be served from, by [@abidlabs](https://github.com/abidlabs) in [PR 3523](https://github.com/gradio-app/gradio/pull/3523)\n- Use Gradio API server to send telemetry using `huggingface_hub` [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3488](https://github.com/gradio-app/gradio/pull/3488)\n- Fixes an an issue where if the Blocks scope was not exited, then State could be shared across sessions, by [@abidlabs](https://github.com/abidlabs) in [PR 3600](https://github.com/gradio-app/gradio/pull/3600)\n- Ensures that `gr.load()` loads and applies the upstream theme, by [@abidlabs](https://github.com/abidlabs) in [PR 3641](https://github.com/gradio-app/gradio/pull/3641)\n- Fixed bug where \"or\" was not being localized in file upload text by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3599](https://github.com/gradio-app/gradio/pull/3599)\n- Fixed bug where chatbot does not autoscroll inside of a tab, row or column by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3637](https://github.com/gradio-app/gradio/pull/3637)\n- Fixed bug where textbox shrinks when `lines` set to larger than 20 by [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3637](https://github.com/gradio-app/gradio/pull/3637)\n- Ensure CSS has fully loaded before rendering the application, by [@pngwn](https://github.com/pngwn) in [PR 3573](https://github.com/gradio-app/gradio/pull/3573)\n- Support using an empty list as `gr.Dataframe` value, by [@space-nuko](https://github.com/space-nuko) in [PR 3646](https://github.com/gradio-app/gradio/pull/3646)\n- Fixed `gr.Image` not filling the entire element size, by [@space-nuko](https://github.com/space-nuko) in [PR 3649](https://github.com/gradio-app/gradio/pull/3649)\n- Make `gr.Code` support the `lines` property, by [@space-nuko](https://github.com/space-nuko) in [PR 3651](https://github.com/gradio-app/gradio/pull/3651)\n- Fixes certain `_js` return values being double wrapped in an array, by [@space-nuko](https://github.com/space-nuko) in [PR 3594](https://github.com/gradio-app/gradio/pull/3594)\n- Correct the documentation of `gr.File` component to state that its preprocessing method converts the uploaded file to a temporary file, by @RussellLuo in [PR 3660](https://github.com/gradio-app/gradio/pull/3660)\n- Fixed bug in Serializer ValueError text by [@osanseviero](https://github.com/osanseviero) in [PR 3669](https://github.com/gradio-app/gradio/pull/3669)\n- Fix default parameter argument and `gr.Progress` used in same function, by [@space-nuko](https://github.com/space-nuko) in [PR 3671](https://github.com/gradio-app/gradio/pull/3671)\n- Hide `Remove All` button in `gr.Dropdown` single-select mode by [@space-nuko](https://github.com/space-nuko) in [PR 3678](https://github.com/gradio-app/gradio/pull/3678)\n- Fix broken spaces in docs by [@aliabd](https://github.com/aliabd) in [PR 3698](https://github.com/gradio-app/gradio/pull/3698)\n- Fix items in `gr.Dropdown` besides the selected item receiving a checkmark, by [@space-nuko](https://github.com/space-nuko) in [PR 3644](https://github.com/gradio-app/gradio/pull/3644)\n- Fix several `gr.Dropdown` issues and improve usability, by [@space-nuko](https://github.com/space-nuko) in [PR 3705](https://github.com/gradio-app/gradio/pull/3705)\n\n### Documentation Changes:\n\n- Makes some fixes to the Theme Guide related to naming of variables, by [@abidlabs](https://github.com/abidlabs) in [PR 3561](https://github.com/gradio-app/gradio/pull/3561)\n- Documented `HuggingFaceDatasetJSONSaver` by [@osanseviero](https://github.com/osanseviero) in [PR 3604](https://github.com/gradio-app/gradio/pull/3604)\n- Makes some additions to documentation of `Audio` and `State` components, and fixes the `pictionary` demo by [@abidlabs](https://github.com/abidlabs) in [PR 3611](https://github.com/gradio-app/gradio/pull/3611)\n- Fix outdated sharing your app guide by [@aliabd](https://github.com/aliabd) in [PR 3699](https://github.com/gradio-app/gradio/pull/3699)\n\n### Testing and Infrastructure Changes:\n\n- Removed heavily-mocked tests related to comet_ml, wandb, and mlflow as they added a significant amount of test dependencies that prevented installation of test dependencies on Windows environments. By [@abidlabs](https://github.com/abidlabs) in [PR 3608](https://github.com/gradio-app/gradio/pull/3608)\n- Added Windows continuous integration, by [@space-nuko](https://github.com/space-nuko) in [PR 3628](https://github.com/gradio-app/gradio/pull/3628)\n- Switched linting from flake8 + isort to `ruff`, by [@akx](https://github.com/akx) in [PR 3710](https://github.com/gradio-app/gradio/pull/3710)\n\n#\n\n### Full Changelog:\n\n- Mobile responsive iframes in themes guide by [@aliabd](https://github.com/aliabd) in [PR 3562](https://github.com/gradio-app/gradio/pull/3562)\n- Remove extra $demo from theme guide by [@aliabd](https://github.com/aliabd) in [PR 3563](https://github.com/gradio-app/gradio/pull/3563)\n- Set the theme name to be the upstream repo name when loading from the hub by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3595](https://github.com/gradio-app/gradio/pull/3595)\n- Copy everything in website Dockerfile, fix build issues by [@aliabd](https://github.com/aliabd) in [PR 3659](https://github.com/gradio-app/gradio/pull/3659)\n- Raise error when an event is queued but the queue is not configured by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3640](https://github.com/gradio-app/gradio/pull/3640)\n- Allows users to apss in a string name for a built-in theme, by [@abidlabs](https://github.com/abidlabs) in [PR 3641](https://github.com/gradio-app/gradio/pull/3641)\n- Added `orig_name` to Video output in the backend so that the front end can set the right name for downloaded video files by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3700](https://github.com/gradio-app/gradio/pull/3700)\n\n#\n\n## 3.23.0\n\n### New Features:\n\n###### Theme Sharing!\n\nOnce you have created a theme, you can upload it to the HuggingFace Hub to let others view it, use it, and build off of it! You can also download, reuse, and remix other peoples' themes. See https://gradio.app/theming-guide/ for more details.\n\nBy [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3428](https://github.com/gradio-app/gradio/pull/3428)\n\n### Bug Fixes:\n\n- Removes leading spaces from all lines of code uniformly in the `gr.Code()` component. By [@abidlabs](https://github.com/abidlabs) in [PR 3556](https://github.com/gradio-app/gradio/pull/3556)\n- Fixed broken login page, by [@aliabid94](https://github.com/aliabid94) in [PR 3529](https://github.com/gradio-app/gradio/pull/3529)\n\n#\n\n#\n\n#\n\n### Full Changelog:\n\n- Fix rendering of dropdowns to take more space, and related bugs, by [@aliabid94](https://github.com/aliabid94) in [PR 3549](https://github.com/gradio-app/gradio/pull/3549)\n\n#\n\n## 3.22.1\n\n#\n\n### Bug Fixes:\n\n- Restore label bars by [@aliabid94](https://github.com/aliabid94) in [PR 3507](https://github.com/gradio-app/gradio/pull/3507)\n\n#\n\n#\n\n#\n\n#\n\n#\n\n## 3.22.0\n\n### New Features:\n\n###### Official Theme release\n\nGradio now supports a new theme system, which allows you to customize the look and feel of your app. You can now use the `theme=` kwarg to pass in a prebuilt theme, or customize your own! See https://gradio.app/theming-guide/ for more details. By [@aliabid94](https://github.com/aliabid94) in [PR 3470](https://github.com/gradio-app/gradio/pull/3470) and [PR 3497](https://github.com/gradio-app/gradio/pull/3497)\n\n###### `elem_classes`\n\nAdd keyword argument `elem_classes` to Components to control class names of components, in the same manner as existing `elem_id`.\nBy [@aliabid94](https://github.com/aliabid94) in [PR 3466](https://github.com/gradio-app/gradio/pull/3466)\n\n### Bug Fixes:\n\n- Fixes the File.upload() event trigger which broke as part of the change in how we uploaded files by [@abidlabs](https://github.com/abidlabs) in [PR 3462](https://github.com/gradio-app/gradio/pull/3462)\n- Fixed issue with `gr.Request` object failing to handle dictionaries when nested keys couldn't be converted to variable names [#3454](https://github.com/gradio-app/gradio/issues/3454) by [@radames](https://github.com/radames) in [PR 3459](https://github.com/gradio-app/gradio/pull/3459)\n- Fixed bug where css and client api was not working properly when mounted in a subpath by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3482](https://github.com/gradio-app/gradio/pull/3482)\n\n### Documentation Changes:\n\n- Document gr.Error in the docs by [@aliabd](https://github.com/aliabd) in [PR 3465](https://github.com/gradio-app/gradio/pull/3465)\n\n### Testing and Infrastructure Changes:\n\n- Pinned `pyright==1.1.298` for stability by [@abidlabs](https://github.com/abidlabs) in [PR 3475](https://github.com/gradio-app/gradio/pull/3475)\n- Removed `IOComponent.add_interactive_to_config()` by [@space-nuko](https://github.com/space-nuko) in [PR 3476](https://github.com/gradio-app/gradio/pull/3476)\n- Removed `IOComponent.generate_sample()` by [@space-nuko](https://github.com/space-nuko) in [PR 3475](https://github.com/gradio-app/gradio/pull/3483)\n\n#\n\n### Full Changelog:\n\n- Revert primary button background color in dark mode by [@aliabid94](https://github.com/aliabid94) in [PR 3468](https://github.com/gradio-app/gradio/pull/3468)\n\n#\n\n## 3.21.0\n\n### New Features:\n\n###### Theme Sharing \ud83c\udfa8 \ud83e\udd1d\n\nYou can now share your gradio themes with the world!\n\nAfter creating a theme, you can upload it to the HuggingFace Hub to let others view it, use it, and build off of it!\n\n###### Uploading\n\nThere are two ways to upload a theme, via the theme class instance or the command line.\n\n1. Via the class instance\n\n```python\nmy_theme.push_to_hub(repo_name=\"my_theme\",\n version=\"0.2.0\",\n hf_token=\"...\")\n```\n\n2. Via the command line\n\nFirst save the theme to disk\n\n```python\nmy_theme.dump(filename=\"my_theme.json\")\n```\n\nThen use the `upload_theme` command:\n\n```bash\nupload_theme\\\n\"my_theme.json\"\\\n\"my_theme\"\\\n\"0.2.0\"\\\n\"
\"\n \"\ud83c\udf99\ufe0f Learn more about UniSpeech-SAT | \"\n \"\ud83d\udcda UniSpeech-SAT paper | \"\n \"\ud83d\udcda X-Vector paper\"\n \"
\"\n)\nexamples = [\n [\"samples/cate_blanch.mp3\", \"samples/cate_blanch_2.mp3\"],\n [\"samples/cate_blanch.mp3\", \"samples/heath_ledger.mp3\"],\n]\n\ninterface = gr.Interface(\n fn=similarity_fn,\n inputs=inputs,\n outputs=output,\n layout=\"horizontal\",\n allow_flagging=False,\n live=False,\n examples=examples,\n cache_examples=False\n)\ninterface.launch()\n", - "text": "This demo identifies if two speakers are the same person using Gradio's Audio and HTML components." - } - ] - } -] +[{"category": "\ud83d\udd8a\ufe0f Text & Natural Language Processing", "demos": [{"name": "Hello World", "dir": "hello_world", "code": "import gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\ndemo = gr.Interface(fn=greet, inputs=\"text\", outputs=\"text\")\n \nif __name__ == \"__main__\":\n demo.launch() ", "text": "The simplest possible Gradio demo. It wraps a 'Hello {name}!' function in an Interface that accepts and returns text."}, {"name": "Text Generation", "dir": "text_generation", "code": "import gradio as gr\nfrom transformers import pipeline\n\ngenerator = pipeline('text-generation', model='gpt2')\n\ndef generate(text):\n result = generator(text, max_length=30, num_return_sequences=1)\n return result[0][\"generated_text\"]\n\nexamples = [\n [\"The Moon's orbit around Earth has\"],\n [\"The smooth Borealis basin in the Northern Hemisphere covers 40%\"],\n]\n\ndemo = gr.Interface(\n fn=generate,\n inputs=gr.inputs.Textbox(lines=5, label=\"Input Text\"),\n outputs=gr.outputs.Textbox(label=\"Generated Text\"),\n examples=examples\n)\n\ndemo.launch()\n", "text": "This text generation demo takes in input text and returns generated text. It uses the Transformers library to set up the model and has two examples."}, {"name": "Autocomplete", "dir": "autocomplete", "code": "import gradio as gr\nimport os\n\n# save your HF API token from https:/hf.co/settings/tokens as an env variable to avoid rate limiting\nauth_token = os.getenv(\"auth_token\")\n\n# load a model from https://hf.co/models as an interface, then use it as an api \n# you can remove the api_key parameter if you don't care about rate limiting. \napi = gr.load(\"huggingface/gpt2-xl\", hf_token=auth_token)\n\ndef complete_with_gpt(text):\n return text[:-50] + api(text[-50:])\n\nwith gr.Blocks() as demo:\n textbox = gr.Textbox(placeholder=\"Type here...\", lines=4)\n btn = gr.Button(\"Autocomplete\")\n \n # define what will run when the button is clicked, here the textbox is used as both an input and an output\n btn.click(fn=complete_with_gpt, inputs=textbox, outputs=textbox, queue=False)\n\ndemo.launch()", "text": "This text generation demo works like autocomplete. There's only one textbox and it's used for both the input and the output. The demo loads the model as an interface, and uses that interface as an API. It then uses blocks to create the UI. All of this is done in less than 10 lines of code."}, {"name": "Sentiment Analysis", "dir": "sentiment_analysis", "code": "import gradio as gr\nimport nltk\nfrom nltk.sentiment.vader import SentimentIntensityAnalyzer\n\nnltk.download(\"vader_lexicon\")\nsid = SentimentIntensityAnalyzer()\n\ndef sentiment_analysis(text):\n scores = sid.polarity_scores(text)\n del scores[\"compound\"]\n return scores\n\ndemo = gr.Interface(\n fn=sentiment_analysis, \n inputs=gr.Textbox(placeholder=\"Enter a positive or negative sentence here...\"), \n outputs=\"label\", \n interpretation=\"default\",\n examples=[[\"This is wonderful!\"]])\n\ndemo.launch()", "text": "This sentiment analaysis demo takes in input text and returns its classification for either positive, negative or neutral using Gradio's Label output. It also uses the default interpretation method so users can click the Interpret button after a submission and see which words had the biggest effect on the output."}, {"name": "Named Entity Recognition", "dir": "text_analysis", "code": "import gradio as gr\nimport os\nos.system('python -m spacy download en_core_web_sm')\nimport spacy\nfrom spacy import displacy\n\nnlp = spacy.load(\"en_core_web_sm\")\n\ndef text_analysis(text):\n doc = nlp(text)\n html = displacy.render(doc, style=\"dep\", page=True)\n html = (\n \"\"\n \"\ud83c\udf99\ufe0f Learn more about UniSpeech-SAT | \"\n \"\ud83d\udcda UniSpeech-SAT paper | \"\n \"\ud83d\udcda X-Vector paper\"\n \"
\"\n)\nexamples = [\n [\"samples/cate_blanch.mp3\", \"samples/cate_blanch_2.mp3\"],\n [\"samples/cate_blanch.mp3\", \"samples/heath_ledger.mp3\"],\n]\n\ninterface = gr.Interface(\n fn=similarity_fn,\n inputs=inputs,\n outputs=output,\n layout=\"horizontal\",\n allow_flagging=False,\n live=False,\n examples=examples,\n cache_examples=False\n)\ninterface.launch()\n", "text": "This demo identifies if two speakers are the same person using Gradio's Audio and HTML components."}]}] \ No newline at end of file diff --git a/js/_website/src/routes/docs/docs.json b/js/_website/src/routes/docs/docs.json index 04e9cda481623..34a9fc6ffb60e 100644 --- a/js/_website/src/routes/docs/docs.json +++ b/js/_website/src/routes/docs/docs.json @@ -1,19453 +1 @@ -{ - "docs": { - "building": { - "simplecsvlogger": { - "class": null, - "name": "SimpleCSVLogger", - "description": "A simplified implementation of the FlaggingCallback abstract class provided for illustrative purposes. Each flagged sample (both the input and output data) is logged to a CSV file on the machine running the gradio app.", - "tags": {}, - "parameters": [ - { - "name": "self", - "annotation": "When you demo a machine learning model, you might want to collect data from users who try the model, particularly data points in which the model is not behaving as expected. Capturing these \"hard\" data points is valuable because it allows you to improve your machine learning model and make it more reliable and robust.
\n\nGradio simplifies the collection of this data by including a Flag button with every Interface
. This allows a user or tester to easily send data back to the machine where the demo is running. In this Guide, we discuss more about how to use the flagging feature, both with gradio.Interface
as well as with gradio.Blocks
.
gradio.Interface
Flagging with Gradio's Interface
is especially easy. By default, underneath the output components, there is a button marked Flag. When a user testing your model sees input with interesting output, they can click the flag button to send the input and output data back to the machine where the demo is running. The sample is saved to a CSV log file (by default). If the demo involves images, audio, video, or other types of files, these are saved separately in a parallel directory and the paths to these files are saved in the CSV file.
There are four parameters in gradio.Interface
that control how flagging works. We will go over them in greater detail.
allow_flagging
: this parameter can be set to either \"manual\"
(default), \"auto\"
, or \"never\"
. manual
: users will see a button to flag, and samples are only flagged when the button is clicked.auto
: users will not see a button to flag, but every sample will be flagged automatically. never
: users will not see a button to flag, and no sample will be flagged. flagging_options
: this parameter can be either None
(default) or a list of strings.\nNone
, then the user simply clicks on the Flag button and no additional options are shown.[\"Incorrect\", \"Ambiguous\"]
, then buttons labeled Flag as Incorrect and Flag as Ambiguous appear. This only applies if allow_flagging
is \"manual\"
.flagging_dir
: this parameter takes a string.\nflagging_callback
: this parameter takes an instance of a subclass of the FlaggingCallback
class\ngr.CSVLogger
gr.HuggingFaceDatasetSaver
which can allow you to pipe any flagged data into a HuggingFace Dataset. (See more below.)Within the directory provided by the flagging_dir
argument, a CSV file will log the flagged data.
Here's an example: The code below creates the calculator interface embedded below it:
\n\nimport gradio as gr\n\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n return num1 / num2\n\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n allow_flagging=\"manual\"\n)\n\niface.launch()\n
When you click the flag button above, the directory where the interface was launched will include a new flagged subfolder, with a csv file inside it. This csv file includes all the data that was flagged.
\n\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output,timestamp\n5,add,7,12,2022-01-31 11:40:51.093412\n6,subtract,1.5,4.5,2022-01-31 03:25:32.023542\n
If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well. For example an image
input to image
output interface will create the following structure.
+-- flagged/\n| +-- logs.csv\n| +-- image/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output timestamp\nim/0.png,Output/0.png,2022-02-04 19:49:58.026963\nim/1.png,Output/1.png,2022-02-02 10:40:51.093412\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of these choices when flagging, and the option will be saved as an additional column to the CSV.
If we go back to the calculator example, the following code will create the interface embedded below it.
\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n allow_flagging=\"manual\",\n flagging_options=[\"wrong sign\", \"off by one\", \"other\"]\n)\n\niface.launch()\n
When users click the flag button, the csv file will now include a column indicating the selected option.
\n\nflagged/logs.csv
\n\nnum1,operation,num2,Output,flag,timestamp\n5,add,7,-12,wrong sign,2022-02-04 11:40:51.093412\n6,subtract,1.5,3.5,off by one,2022-02-04 11:42:32.062512\n
Sometimes, saving the data to a local CSV file doesn't make sense. For example, on Hugging Face\nSpaces, developers typically don't have access to the underlying ephemeral machine hosting the Gradio\ndemo. That's why, by default, flagging is turned off in Hugging Face Space. However,\nyou may want to do something else with the flagged data.
\n\nWe've made this super easy with the flagging_callback
parameter.
For example, below we're going to pipe flagged data from our calculator example into a Hugging Face Dataset, e.g. so that we can build a \"crowd-sourced\" dataset:
\n\nimport os\n\nHF_TOKEN = os.getenv('HF_TOKEN')\nhf_writer = gr.HuggingFaceDatasetSaver(HF_TOKEN, \"crowdsourced-calculator-demo\")\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n description=\"Check out the crowd-sourced dataset at: [https://huggingface.co/datasets/aliabd/crowdsourced-calculator-demo](https://huggingface.co/datasets/aliabd/crowdsourced-calculator-demo)\",\n allow_flagging=\"manual\",\n flagging_options=[\"wrong sign\", \"off by one\", \"other\"],\n flagging_callback=hf_writer\n)\n\niface.launch()\n
Notice that we define our own \ninstance of gradio.HuggingFaceDatasetSaver
using our Hugging Face token and\nthe name of a dataset we'd like to save samples to. In addition, we also set allow_flagging=\"manual\"
\nbecause on Hugging Face Spaces, allow_flagging
is set to \"never\"
by default. Here's our demo:
You can now see all the examples flagged above in this public Hugging Face dataset.
\n\n\n\nWe created the gradio.HuggingFaceDatasetSaver
class, but you can pass your own custom class as long as it inherits from FLaggingCallback
defined in this file. If you create a cool callback, contribute it to the repo!
What about if you are using gradio.Blocks
? On one hand, you have even more flexibility\nwith Blocks -- you can write whatever Python code you want to run when a button is clicked,\nand assign that using the built-in events in Blocks.
At the same time, you might want to use an existing FlaggingCallback
to avoid writing extra code.\nThis requires two steps:
.setup()
somewhere in the code prior to the \nfirst time you flag data.flag()
method,\nmaking sure to collect the arguments correctly and disabling the typical preprocessing. Here is an example with an image sepia filter Blocks demo that lets you flag\ndata using the default CSVLogger
:
import numpy as np\nimport gradio as gr\n\ndef sepia(input_img, strength):\n sepia_filter = strength * np.array(\n [[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]\n ) + (1-strength) * np.identity(3)\n sepia_img = input_img.dot(sepia_filter.T)\n sepia_img /= sepia_img.max()\n return sepia_img\n\ncallback = gr.CSVLogger()\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n img_input = gr.Image()\n strength = gr.Slider(0, 1, 0.5)\n img_output = gr.Image()\n with gr.Row():\n btn = gr.Button(\"Flag\")\n\n # This needs to be called at some point prior to the first call to callback.flag()\n callback.setup([img_input, strength, img_output], \"flagged_data_points\")\n\n img_input.change(sepia, [img_input, strength], img_output)\n strength.change(sepia, [img_input, strength], img_output)\n\n # We can choose which components to flag -- in this case, we'll flag all of them\n btn.click(lambda *args: callback.flag(args), [img_input, strength, img_output], None, preprocess=False)\n\ndemo.launch()\n\n
Important Note: please make sure your users understand when the data they submit is being saved, and what you plan on doing with it. This is especially important when you use allow_flagging=auto
(when all of the data submitted through the demo is being flagged)
When you demo a machine learning model, you might want to collect data from users who try the model, particularly data points in which the model is not behaving as expected. Capturing these \"hard\" data points is valuable because it allows you to improve your machine learning model and make it more reliable and robust.
\n\nGradio simplifies the collection of this data by including a Flag button with every Interface
. This allows a user or tester to easily send data back to the machine where the demo is running. In this Guide, we discuss more about how to use the flagging feature, both with gradio.Interface
as well as with gradio.Blocks
.
gradio.Interface
Flagging with Gradio's Interface
is especially easy. By default, underneath the output components, there is a button marked Flag. When a user testing your model sees input with interesting output, they can click the flag button to send the input and output data back to the machine where the demo is running. The sample is saved to a CSV log file (by default). If the demo involves images, audio, video, or other types of files, these are saved separately in a parallel directory and the paths to these files are saved in the CSV file.
There are four parameters in gradio.Interface
that control how flagging works. We will go over them in greater detail.
allow_flagging
: this parameter can be set to either \"manual\"
(default), \"auto\"
, or \"never\"
. manual
: users will see a button to flag, and samples are only flagged when the button is clicked.auto
: users will not see a button to flag, but every sample will be flagged automatically. never
: users will not see a button to flag, and no sample will be flagged. flagging_options
: this parameter can be either None
(default) or a list of strings.\nNone
, then the user simply clicks on the Flag button and no additional options are shown.[\"Incorrect\", \"Ambiguous\"]
, then buttons labeled Flag as Incorrect and Flag as Ambiguous appear. This only applies if allow_flagging
is \"manual\"
.flagging_dir
: this parameter takes a string.\nflagging_callback
: this parameter takes an instance of a subclass of the FlaggingCallback
class\ngr.CSVLogger
gr.HuggingFaceDatasetSaver
which can allow you to pipe any flagged data into a HuggingFace Dataset. (See more below.)Within the directory provided by the flagging_dir
argument, a CSV file will log the flagged data.
Here's an example: The code below creates the calculator interface embedded below it:
\n\nimport gradio as gr\n\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n return num1 / num2\n\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n allow_flagging=\"manual\"\n)\n\niface.launch()\n
When you click the flag button above, the directory where the interface was launched will include a new flagged subfolder, with a csv file inside it. This csv file includes all the data that was flagged.
\n\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output,timestamp\n5,add,7,12,2022-01-31 11:40:51.093412\n6,subtract,1.5,4.5,2022-01-31 03:25:32.023542\n
If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well. For example an image
input to image
output interface will create the following structure.
+-- flagged/\n| +-- logs.csv\n| +-- image/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output timestamp\nim/0.png,Output/0.png,2022-02-04 19:49:58.026963\nim/1.png,Output/1.png,2022-02-02 10:40:51.093412\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of these choices when flagging, and the option will be saved as an additional column to the CSV.
If we go back to the calculator example, the following code will create the interface embedded below it.
\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n allow_flagging=\"manual\",\n flagging_options=[\"wrong sign\", \"off by one\", \"other\"]\n)\n\niface.launch()\n
When users click the flag button, the csv file will now include a column indicating the selected option.
\n\nflagged/logs.csv
\n\nnum1,operation,num2,Output,flag,timestamp\n5,add,7,-12,wrong sign,2022-02-04 11:40:51.093412\n6,subtract,1.5,3.5,off by one,2022-02-04 11:42:32.062512\n
Sometimes, saving the data to a local CSV file doesn't make sense. For example, on Hugging Face\nSpaces, developers typically don't have access to the underlying ephemeral machine hosting the Gradio\ndemo. That's why, by default, flagging is turned off in Hugging Face Space. However,\nyou may want to do something else with the flagged data.
\n\nWe've made this super easy with the flagging_callback
parameter.
For example, below we're going to pipe flagged data from our calculator example into a Hugging Face Dataset, e.g. so that we can build a \"crowd-sourced\" dataset:
\n\nimport os\n\nHF_TOKEN = os.getenv('HF_TOKEN')\nhf_writer = gr.HuggingFaceDatasetSaver(HF_TOKEN, \"crowdsourced-calculator-demo\")\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n description=\"Check out the crowd-sourced dataset at: [https://huggingface.co/datasets/aliabd/crowdsourced-calculator-demo](https://huggingface.co/datasets/aliabd/crowdsourced-calculator-demo)\",\n allow_flagging=\"manual\",\n flagging_options=[\"wrong sign\", \"off by one\", \"other\"],\n flagging_callback=hf_writer\n)\n\niface.launch()\n
Notice that we define our own \ninstance of gradio.HuggingFaceDatasetSaver
using our Hugging Face token and\nthe name of a dataset we'd like to save samples to. In addition, we also set allow_flagging=\"manual\"
\nbecause on Hugging Face Spaces, allow_flagging
is set to \"never\"
by default. Here's our demo:
You can now see all the examples flagged above in this public Hugging Face dataset.
\n\n\n\nWe created the gradio.HuggingFaceDatasetSaver
class, but you can pass your own custom class as long as it inherits from FLaggingCallback
defined in this file. If you create a cool callback, contribute it to the repo!
What about if you are using gradio.Blocks
? On one hand, you have even more flexibility\nwith Blocks -- you can write whatever Python code you want to run when a button is clicked,\nand assign that using the built-in events in Blocks.
At the same time, you might want to use an existing FlaggingCallback
to avoid writing extra code.\nThis requires two steps:
.setup()
somewhere in the code prior to the \nfirst time you flag data.flag()
method,\nmaking sure to collect the arguments correctly and disabling the typical preprocessing. Here is an example with an image sepia filter Blocks demo that lets you flag\ndata using the default CSVLogger
:
import numpy as np\nimport gradio as gr\n\ndef sepia(input_img, strength):\n sepia_filter = strength * np.array(\n [[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]\n ) + (1-strength) * np.identity(3)\n sepia_img = input_img.dot(sepia_filter.T)\n sepia_img /= sepia_img.max()\n return sepia_img\n\ncallback = gr.CSVLogger()\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n img_input = gr.Image()\n strength = gr.Slider(0, 1, 0.5)\n img_output = gr.Image()\n with gr.Row():\n btn = gr.Button(\"Flag\")\n\n # This needs to be called at some point prior to the first call to callback.flag()\n callback.setup([img_input, strength, img_output], \"flagged_data_points\")\n\n img_input.change(sepia, [img_input, strength], img_output)\n strength.change(sepia, [img_input, strength], img_output)\n\n # We can choose which components to flag -- in this case, we'll flag all of them\n btn.click(lambda *args: callback.flag(args), [img_input, strength, img_output], None, preprocess=False)\n\ndemo.launch()\n\n
Important Note: please make sure your users understand when the data they submit is being saved, and what you plan on doing with it. This is especially important when you use allow_flagging=auto
(when all of the data submitted through the demo is being flagged)
We took a quick look at Blocks in the Quickstart. Let's dive deeper. This guide will cover the how Blocks are structured, event listeners and their types, running events continuously, updating configurations, and using dictionaries vs lists.
\n\nTake a look at the demo below.
\n\nimport gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\nwith gr.Blocks() as demo:\n name = gr.Textbox(label=\"Name\")\n output = gr.Textbox(label=\"Output Box\")\n greet_btn = gr.Button(\"Greet\")\n greet_btn.click(fn=greet, inputs=name, outputs=output, api_name=\"greet\")\n\n\ndemo.launch()\n
with gr.Blocks() as demo:
clause. The Blocks app code will be contained within this clause.Interface
. However, instead of being passed to some constructor, Components are automatically added to the Blocks as they are created within the with
clause.click()
event listener. Event listeners define the data flow within the app. In the example above, the listener ties the two Textboxes together. The Textbox name
acts as the input and Textbox output
acts as the output to the greet
method. This dataflow is triggered when the Button greet_btn
is clicked. Like an Interface, an event listener can take multiple inputs or outputs.In the example above, you'll notice that you are able to edit Textbox name
, but not Textbox output
. This is because any Component that acts as an input to an event listener is made interactive. However, since Textbox output
acts only as an output, Gradio determines that it should not be made interactive. You can override the default behavior and directly configure the interactivity of a Component with the boolean interactive
keyword argument.
output = gr.Textbox(label=\"Output\", interactive=True)\n
Note: What happens if a Gradio component is neither an input nor an output? If a component is constructed with a default value, then it is presumed to be displaying content and is rendered non-interactive. Otherwise, it is rendered interactive. Again, this behavior can be overridden by specifying a value for the interactive
argument.
Take a look at the demo below:
\n\nimport gradio as gr\n\ndef welcome(name):\n return f\"Welcome to Gradio, {name}!\"\n\nwith gr.Blocks() as demo:\n gr.Markdown(\n \"\"\"\n # Hello World!\n Start typing below to see the output.\n \"\"\")\n inp = gr.Textbox(placeholder=\"What is your name?\")\n out = gr.Textbox()\n inp.change(welcome, inp, out)\n\ndemo.launch()\n
Instead of being triggered by a click, the welcome
function is triggered by typing in the Textbox inp
. This is due to the change()
event listener. Different Components support different event listeners. For example, the Video
Component supports a play()
event listener, triggered when a user presses play. See the Docs for the event listeners for each Component.
A Blocks app is not limited to a single data flow the way Interfaces are. Take a look at the demo below:
\n\nimport gradio as gr\n\ndef increase(num):\n return num + 1\n\nwith gr.Blocks() as demo:\n a = gr.Number(label=\"a\")\n b = gr.Number(label=\"b\")\n btoa = gr.Button(\"a > b\")\n atob = gr.Button(\"b > a\")\n atob.click(increase, a, b)\n btoa.click(increase, b, a)\n\ndemo.launch()\n
Note that num1
can act as input to num2
, and also vice-versa! As your apps get more complex, you will have many data flows connecting various Components.
Here's an example of a \"multi-step\" demo, where the output of one model (a speech-to-text model) gets fed into the next model (a sentiment classifier).
\n\nfrom transformers import pipeline\n\nimport gradio as gr\n\nasr = pipeline(\"automatic-speech-recognition\", \"facebook/wav2vec2-base-960h\")\nclassifier = pipeline(\"text-classification\")\n\n\ndef speech_to_text(speech):\n text = asr(speech)[\"text\"]\n return text\n\n\ndef text_to_sentiment(text):\n return classifier(text)[0][\"label\"]\n\n\ndemo = gr.Blocks()\n\nwith demo:\n audio_file = gr.Audio(type=\"filepath\")\n text = gr.Textbox()\n label = gr.Label()\n\n b1 = gr.Button(\"Recognize Speech\")\n b2 = gr.Button(\"Classify Sentiment\")\n\n b1.click(speech_to_text, inputs=audio_file, outputs=text)\n b2.click(text_to_sentiment, inputs=text, outputs=label)\n\ndemo.launch()\n\n
The event listeners you've seen so far have a single input component. If you'd like to have multiple input components pass data to the function, you have two options on how the function can accept input component values:
\n\nLet's see an example of each:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n a = gr.Number(label=\"a\")\n b = gr.Number(label=\"b\")\n with gr.Row():\n add_btn = gr.Button(\"Add\")\n sub_btn = gr.Button(\"Subtract\")\n c = gr.Number(label=\"sum\")\n\n def add(num1, num2):\n return num1 + num2\n add_btn.click(add, inputs=[a, b], outputs=c)\n\n def sub(data):\n return data[a] - data[b]\n sub_btn.click(sub, inputs={a, b}, outputs=c)\n\n\ndemo.launch()\n
Both add()
and sub()
take a
and b
as inputs. However, the syntax is different between these listeners.
add_btn
listener, we pass the inputs as a list. The function add()
takes each of these inputs as arguments. The value of a
maps to the argument num1
, and the value of b
maps to the argument num2
.sub_btn
listener, we pass the inputs as a set (note the curly brackets!). The function sub()
takes a single dictionary argument data
, where the keys are the input components, and the values are the values of those components.It is a matter of preference which syntax you prefer! For functions with many input components, option 2 may be easier to manage.
\n\nSimilarly, you may return values for multiple output components either as:
\n\nLet's first see an example of (1), where we set the values of two output components by returning two values:
\n\nwith gr.Blocks() as demo:\n food_box = gr.Number(value=10, label=\"Food Count\")\n status_box = gr.Textbox()\n def eat(food):\n if food > 0:\n return food - 1, \"full\"\n else:\n return 0, \"hungry\"\n gr.Button(\"EAT\").click(\n fn=eat, \n inputs=food_box,\n outputs=[food_box, status_box]\n )\n
Above, each return statement returns two values corresponding to food_box
and status_box
, respectively.
Instead of returning a list of values corresponding to each output component in order, you can also return a dictionary, with the key corresponding to the output component and the value as the new value. This also allows you to skip updating some output components.
\n\nwith gr.Blocks() as demo:\n food_box = gr.Number(value=10, label=\"Food Count\")\n status_box = gr.Textbox()\n def eat(food):\n if food > 0:\n return {food_box: food - 1, status_box: \"full\"}\n else:\n return {status_box: \"hungry\"}\n gr.Button(\"EAT\").click(\n fn=eat, \n inputs=food_box,\n outputs=[food_box, status_box]\n )\n
Notice how when there is no food, we only update the status_box
element. We skipped updating the food_box
component.
Dictionary returns are helpful when an event listener affects many components on return, or conditionally affects outputs and not others.
\n\nKeep in mind that with dictionary returns, we still need to specify the possible outputs in the event listener.
\n\nThe return value of an event listener function is usually the updated value of the corresponding output Component. Sometimes we want to update the configuration of the Component as well, such as the visibility. In this case, we return a gr.update()
object instead of just the update Component value.
import gradio as gr\n\ndef change_textbox(choice):\n if choice == \"short\":\n return gr.update(lines=2, visible=True, value=\"Short story: \")\n elif choice == \"long\":\n return gr.update(lines=8, visible=True, value=\"Long story...\")\n else:\n return gr.update(visible=False)\n\nwith gr.Blocks() as demo:\n radio = gr.Radio(\n [\"short\", \"long\", \"none\"], label=\"Essay Length to Write?\"\n )\n text = gr.Textbox(lines=2, interactive=True)\n radio.change(fn=change_textbox, inputs=radio, outputs=text)\n\ndemo.launch()\n
See how we can configure the Textbox itself through the gr.update()
method. The value=
argument can still be used to update the value along with Component configuration.
You can also run events consecutively by using the then
method of an event listener. This will run an event after the previous event has finished running. This is useful for running events that update components in multiple steps.
For example, in the chatbot example below, we first update the chatbot with the user message immediately, and then update the chatbot with the computer response after a simulated delay.
\n\nimport gradio as gr\nimport random\nimport time\n\nwith gr.Blocks() as demo:\n chatbot = gr.Chatbot()\n msg = gr.Textbox()\n clear = gr.Button(\"Clear\")\n\n def user(user_message, history):\n return \"\", history + [[user_message, None]]\n\n def bot(history):\n bot_message = random.choice([\"How are you?\", \"I love you\", \"I'm very hungry\"])\n time.sleep(2)\n history[-1][1] = bot_message\n return history\n\n msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(\n bot, chatbot, chatbot\n )\n clear.click(lambda: None, None, chatbot, queue=False)\n\ndemo.queue()\ndemo.launch()\n\n
The .then()
method of an event listener executes the subsequent event regardless of whether the previous event raised any errors. If you'd like to only run subsequent events if the previous event executed successfully, use the .success()
method, which takes the same arguments as .then()
.
You can run events on a fixed schedule using the every
parameter of the event listener. This will run the event\nevery
number of seconds while the client connection is open. If the connection is closed, the event will stop running after the following iteration.\nNote that this does not take into account the runtime of the event itself. So a function\nwith a 1 second runtime running with every=5
, would actually run every 6 seconds.
Here is an example of a sine curve that updates every second!
\n\nimport math\nimport gradio as gr\nimport plotly.express as px\nimport numpy as np\n\n\nplot_end = 2 * math.pi\n\n\ndef get_plot(period=1):\n global plot_end\n x = np.arange(plot_end - 2 * math.pi, plot_end, 0.02)\n y = np.sin(2*math.pi*period * x)\n fig = px.line(x=x, y=y)\n plot_end += 2 * math.pi\n if plot_end > 1000:\n plot_end = 2 * math.pi\n return fig\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n gr.Markdown(\"Change the value of the slider to automatically update the plot\")\n period = gr.Slider(label=\"Period of plot\", value=1, minimum=0, maximum=10, step=1)\n plot = gr.Plot(label=\"Plot (updates every half second)\")\n\n dep = demo.load(get_plot, None, plot, every=1)\n period.change(get_plot, period, plot, every=1, cancels=[dep])\n\n\nif __name__ == \"__main__\":\n demo.queue().launch()\n\n
You can gather specific data about an event by adding the associated event data class as a type hint to an argument in the event listener function.
\n\nFor example, event data for .select()
can be type hinted by a gradio.SelectData
argument. This event is triggered when a user selects some part of the triggering component, and the event data includes information about what the user specifically selected. If a user selected a specific word in a Textbox
, a specific image in a Gallery
, or a specific cell in a DataFrame
, the event data argument would contain information about the specific selection.
In the 2 player tic-tac-toe demo below, a user can select a cell in the DataFrame
to make a move. The event data argument contains information about the specific cell that was selected. We can first check to see if the cell is empty, and then update the cell with the user's move.
import gradio as gr\n\nwith gr.Blocks() as demo:\n turn = gr.Textbox(\"X\", interactive=False, label=\"Turn\")\n board = gr.Dataframe(value=[[\"\", \"\", \"\"]] * 3, interactive=False, type=\"array\")\n\n def place(board, turn, evt: gr.SelectData):\n if evt.value:\n return board, turn\n board[evt.index[0]][evt.index[1]] = turn\n turn = \"O\" if turn == \"X\" else \"X\"\n return board, turn\n\n board.select(place, [board, turn], [board, turn])\n\ndemo.launch()\n
By default, Components in Blocks are arranged vertically. Let's take a look at how we can rearrange Components. Under the hood, this layout structure uses the flexbox model of web development.
\n\nElements within a with gr.Row
clause will all be displayed horizontally. For example, to display two Buttons side by side:
with gr.Blocks() as demo:\n with gr.Row():\n btn1 = gr.Button(\"Button 1\")\n btn2 = gr.Button(\"Button 2\")\n
To make every element in a Row have the same height, use the equal_height
argument of the style
method.
with gr.Blocks() as demo:\n with gr.Row().style(equal_height=True):\n textbox = gr.Textbox()\n btn2 = gr.Button(\"Button 2\")\n
The widths of elements in a Row can be controlled via a combination of scale
and min_width
arguments that are present in every Component.
scale
is an integer that defines how an element will take up space in a Row. If scale is set to 0
, and element will not expand to take up space. If scale is set to 1
or greater, the element well expand. Multiple elements in a row will expand proportional to their scale. Below, btn1
will expand twice as much as btn2
, while btn0
will not expand at all:with gr.Blocks() as demo:\n with gr.Row():\n btn0 = gr.Button(\"Button 0\", scale=0)\n btn1 = gr.Button(\"Button 1\", scale=1)\n btn2 = gr.Button(\"Button 2\", scale=2)\n
min_width
will set the minimum width the element will take. The Row will wrap if there isn't sufficient space to satisfy all min_width
values.Learn more about Rows in the docs.
\n\nComponents within a Column will be placed vertically atop each other. Since the vertical layout is the default layout for Blocks apps anyway, to be useful, Columns are usually nested within Rows. For example:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n text1 = gr.Textbox(label=\"t1\")\n slider2 = gr.Textbox(label=\"s2\")\n drop3 = gr.Dropdown([\"a\", \"b\", \"c\"], label=\"d3\")\n with gr.Row():\n with gr.Column(scale=1, min_width=600):\n text1 = gr.Textbox(label=\"prompt 1\")\n text2 = gr.Textbox(label=\"prompt 2\")\n inbtw = gr.Button(\"Between\")\n text4 = gr.Textbox(label=\"prompt 1\")\n text5 = gr.Textbox(label=\"prompt 2\")\n with gr.Column(scale=2, min_width=600):\n img1 = gr.Image(\"images/cheetah.jpg\")\n btn = gr.Button(\"Go\").style(full_width=True)\n\ndemo.launch()\n
See how the first column has two Textboxes arranged vertically. The second column has an Image and Button arranged vertically. Notice how the relative widths of the two columns is set by the scale
parameter. The column with twice the scale
value takes up twice the width.
Learn more about Columns in the docs.
\n\nYou can also create Tabs using the with gr.Tab('tab_name'):
clause. Any component created inside of a with gr.Tab('tab_name'):
context appears in that tab. Consecutive Tab clauses are grouped together so that a single tab can be selected at one time, and only the components within that Tab's context are shown.
For example:
\n\nimport numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
Also note the gr.Accordion('label')
in this example. The Accordion is a layout that can be toggled open or closed. Like Tabs
, it is a layout element that can selectively hide or show content. Any components that are defined inside of a with gr.Accordion('label'):
will be hidden or shown when the accordion's toggle icon is clicked.
Learn more about Tabs and Accordions in the docs.
\n\nBoth Components and Layout elements have a visible
argument that can set initially and also updated using gr.update()
. Setting gr.update(visible=...)
on a Column can be used to show or hide a set of Components.
import gradio as gr\n\nwith gr.Blocks() as demo:\n error_box = gr.Textbox(label=\"Error\", visible=False)\n\n name_box = gr.Textbox(label=\"Name\")\n age_box = gr.Number(label=\"Age\", minimum=0, maximum=100)\n symptoms_box = gr.CheckboxGroup([\"Cough\", \"Fever\", \"Runny Nose\"])\n submit_btn = gr.Button(\"Submit\")\n\n with gr.Column(visible=False) as output_col:\n diagnosis_box = gr.Textbox(label=\"Diagnosis\")\n patient_summary_box = gr.Textbox(label=\"Patient Summary\")\n\n def submit(name, age, symptoms):\n if len(name) == 0:\n return {error_box: gr.update(value=\"Enter name\", visible=True)}\n return {\n output_col: gr.update(visible=True),\n diagnosis_box: \"covid\" if \"Cough\" in symptoms else \"flu\",\n patient_summary_box: f\"{name}, {age} y/o\",\n }\n\n submit_btn.click(\n submit,\n [name_box, age_box, symptoms_box],\n [error_box, diagnosis_box, patient_summary_box, output_col],\n )\n\ndemo.launch()\n\n
By adjusting the visibility of components in a dynamic way, it is possible to create\ndemos with Gradio that support a variable numbers of outputs. Here's a very simple example\nwhere the number of output textboxes is controlled by an input slider:
\n\nimport gradio as gr\n\nmax_textboxes = 10\n\ndef variable_outputs(k):\n k = int(k)\n return [gr.Textbox.update(visible=True)]*k + [gr.Textbox.update(visible=False)]*(max_textboxes-k)\n\nwith gr.Blocks() as demo:\n s = gr.Slider(1, max_textboxes, value=max_textboxes, step=1, label=\"How many textboxes to show:\")\n textboxes = []\n for i in range(max_textboxes):\n t = gr.Textbox(f\"Textbox {i}\")\n textboxes.append(t)\n\n s.change(variable_outputs, s, textboxes)\n\nif __name__ == \"__main__\":\n demo.launch()\n\n
In some cases, you might want to define components before you actually render them in your UI. For instance, you might want to show an examples section using gr.Examples
above the corresponding gr.Textbox
input. Since gr.Examples
requires as a parameter the input component object, you will need to first define the input component, but then render it later, after you have defined the gr.Examples
object.
The solution to this is to define the gr.Textbox
outside of the gr.Blocks()
scope and use the component's .render()
method wherever you'd like it placed in the UI.
Here's a full code example:
\n\ninput_textbox = gr.Textbox()\n\nwith gr.Blocks() as demo:\n gr.Examples([\"hello\", \"bonjour\", \"merhaba\"], input_textbox)\n input_textbox.render()\n
We covered State in Interfaces, this guide takes a look at state in Blocks, which works mostly the same.
\n\nGlobal state in Blocks works the same as in Interface. Any variable created outside a function call is a reference shared between all users.
\n\nGradio supports session state, where data persists across multiple submits within a page session, in Blocks apps as well. To reiterate, session data is not shared between different users of your model. To store data in a session state, you need to do three things:
\n\ngr.State()
object. If there is a default value to this stateful object, pass that into the constructor.State
object as an input and output.Let's take a look at a game of hangman.
\n\nimport gradio as gr\n\nsecret_word = \"gradio\"\n\nwith gr.Blocks() as demo: \n used_letters_var = gr.State([])\n with gr.Row() as row:\n with gr.Column():\n input_letter = gr.Textbox(label=\"Enter letter\")\n btn = gr.Button(\"Guess Letter\")\n with gr.Column():\n hangman = gr.Textbox(\n label=\"Hangman\",\n value=\"_\"*len(secret_word)\n )\n used_letters_box = gr.Textbox(label=\"Used Letters\")\n\n def guess_letter(letter, used_letters):\n used_letters.append(letter)\n answer = \"\".join([\n (letter if letter in used_letters else \"_\")\n for letter in secret_word\n ])\n return {\n used_letters_var: used_letters,\n used_letters_box: \", \".join(used_letters),\n hangman: answer\n }\n btn.click(\n guess_letter, \n [input_letter, used_letters_var],\n [used_letters_var, used_letters_box, hangman]\n )\ndemo.launch()\n
Let's see how we do each of the 3 steps listed above in this game:
\n\nused_letters_var
. In the constructor of State
, we set the initial value of this to []
, an empty list. btn.click()
, we have a reference to used_letters_var
in both the inputs and outputs.guess_letter
, we pass the value of this State
to used_letters
, and then return an updated value of this State
in the return statement.With more complex apps, you will likely have many State variables storing session state in a single Blocks app.
\n\nLearn more about State
in the docs.
This guide covers how to style Blocks with more flexibility, as well as adding Javascript code to event listeners.
\n\nWarning: The use of query selectors in custom JS and CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using query selectors sparingly.
\n\nGradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the theme=
kwarg to the Blocks
constructor. For example:
with gr.Blocks(theme=gr.themes.Glass()):\n ...\n
Gradio comes with a set of prebuilt themes which you can load from gr.themes.*
. You can extend these themes or create your own themes from scratch - see the Theming guide for more details.
For additional styling ability, you can pass any CSS to your app using the css=
kwarg.
The base class for the Gradio app is gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Blocks(css=\".gradio-container {background-color: red}\") as demo:\n ...\n
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with \"file=\"
, for example:
with gr.Blocks(css=\".gradio-container {background: url('file=clouds.jpg')}\") as demo:\n ...\n
You can also pass the filepath to a CSS file to the css
argument.
elem_id
and elem_classes
ArgumentsYou can elem_id
to add an HTML element id
to any component, and elem_classes
to add a class or list of classes. This will allow you to select elements more easily with CSS. This approach is also more likely to be stable across Gradio versions as built-in class names or ids may change (however, as mentioned in the warning above, we cannot guarantee complete compatibility between Gradio versions if you use custom CSS as the DOM elements may themselves change).
css = \"\"\"\n#warning {background-color: #FFCCCB} \n.feedback textarea {font-size: 24px !important}\n\"\"\"\n\nwith gr.Blocks(css=css) as demo:\n box1 = gr.Textbox(value=\"Good Job\", elem_classes=\"feedback\")\n box2 = gr.Textbox(value=\"Failure\", elem_id=\"warning\", elem_classes=\"feedback\")\n
The CSS #warning
ruleset will only target the second Textbox, while the .feedback
ruleset will target both. Note that when targeting classes, you might need to put the !important
selector to override the default Gradio styles.
Event listeners have a _js
argument that can take a Javascript function as a string and treat it just like a Python event listener function. You can pass both a Javascript function and a Python function (in which case the Javascript function is run first) or only Javascript (and set the Python fn
to None
). Take a look at the code below:
import gradio as gr\n\nblocks = gr.Blocks()\n\nwith blocks as demo:\n subject = gr.Textbox(placeholder=\"subject\")\n verb = gr.Radio([\"ate\", \"loved\", \"hated\"])\n object = gr.Textbox(placeholder=\"object\")\n\n with gr.Row():\n btn = gr.Button(\"Create sentence.\")\n reverse_btn = gr.Button(\"Reverse sentence.\")\n foo_bar_btn = gr.Button(\"Append foo\")\n reverse_then_to_the_server_btn = gr.Button(\n \"Reverse sentence and send to server.\"\n )\n\n def sentence_maker(w1, w2, w3):\n return f\"{w1} {w2} {w3}\"\n\n output1 = gr.Textbox(label=\"output 1\")\n output2 = gr.Textbox(label=\"verb\")\n output3 = gr.Textbox(label=\"verb reversed\")\n output4 = gr.Textbox(label=\"front end process and then send to backend\")\n\n btn.click(sentence_maker, [subject, verb, object], output1)\n reverse_btn.click(\n None, [subject, verb, object], output2, _js=\"(s, v, o) => o + ' ' + v + ' ' + s\"\n )\n verb.change(lambda x: x, verb, output3, _js=\"(x) => [...x].reverse().join('')\")\n foo_bar_btn.click(None, [], subject, _js=\"(x) => x + ' foo'\")\n\n reverse_then_to_the_server_btn.click(\n sentence_maker,\n [subject, verb, object],\n output4,\n _js=\"(s, v, o) => [s, v, o].map(x => [...x].reverse().join(''))\",\n )\n\ndemo.launch()\n\n
Prerequisite: This Guide requires you to know about Blocks and the interpretation feature of Interfaces.\nMake sure to read the Guide to Blocks first as well as the\ninterpretation section of the Advanced Interface Features Guide.
\n\nIf you have experience working with the Interface class, then you know that interpreting the prediction of your machine learning model\nis as easy as setting the interpretation
parameter to either \"default\" or \"shap\".
You may be wondering if it is possible to add the same interpretation functionality to an app built with the Blocks API.\nNot only is it possible, but the flexibility of Blocks lets you display the interpretation output in ways that are\nimpossible to do with Interfaces!
\n\nThis guide will show how to:
\n\nLet's get started!
\n\nLet's build a sentiment classification app with the Blocks API.\nThis app will take text as input and output the probability that this text expresses either negative or positive sentiment.\nWe'll have a single input Textbox
and a single output Label
component.\nBelow is the code for the app as well as the app itself.
import gradio as gr \nfrom transformers import pipeline\n\nsentiment_classifier = pipeline(\"text-classification\", return_all_scores=True)\n\ndef classifier(text):\n pred = sentiment_classifier(text)\n return {p[\"label\"]: p[\"score\"] for p in pred[0]}\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n\n classify.click(classifier, input_text, label)\ndemo.launch()\n
Our goal is to present to our users how the words in the input contribute to the model's prediction.\nThis will help our users understand how the model works and also evaluate its effectiveness.\nFor example, we should expect our model to identify the words \"happy\" and \"love\" with positive sentiment - if not it's a sign we made a mistake in training it!
\n\nFor each word in the input, we will compute a score of how much the model's prediction of positive sentiment is changed by that word.\nOnce we have those (word, score)
pairs we can use gradio to visualize them for the user.
The shap library will help us compute the (word, score)
pairs and\ngradio will take care of displaying the output to the user.
The following code computes the (word, score)
pairs:
def interpretation_function(text):\n explainer = shap.Explainer(sentiment_classifier)\n shap_values = explainer([text])\n\n # Dimensions are (batch size, text size, number of classes)\n # Since we care about positive sentiment, use index 1\n scores = list(zip(shap_values.data[0], shap_values.values[0, :, 1]))\n # Scores contains (word, score) pairs\n\n\n # Format expected by gr.components.Interpretation\n return {\"original\": text, \"interpretation\": scores}\n
Now, all we have to do is add a button that runs this function when clicked.\nTo display the interpretation, we will use gr.components.Interpretation
.\nThis will color each word in the input either red or blue.\nRed if it contributes to positive sentiment and blue if it contributes to negative sentiment.\nThis is how Interface
displays the interpretation output for text.
with gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n interpret = gr.Button(\"Interpret\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n with gr.Column():\n interpretation = gr.components.Interpretation(input_text)\n classify.click(classifier, input_text, label)\n interpret.click(interpretation_function, input_text, interpretation)\n\ndemo.launch()\n
The gr.components.Interpretation
component does a good job of showing how individual words contribute to the sentiment prediction,\nbut what if we also wanted to display the score themselves along with the words?
One way to do this would be to generate a bar plot where the words are on the horizontal axis and the bar height corresponds\nto the shap score.
\n\nWe can do this by modifying our interpretation_function
to additionally return a matplotlib bar plot.\nWe will display it with the gr.Plot
component in a separate tab.
This is how the interpretation function will look:
\n\ndef interpretation_function(text):\n explainer = shap.Explainer(sentiment_classifier)\n shap_values = explainer([text])\n # Dimensions are (batch size, text size, number of classes)\n # Since we care about positive sentiment, use index 1\n scores = list(zip(shap_values.data[0], shap_values.values[0, :, 1]))\n\n scores_desc = sorted(scores, key=lambda t: t[1])[::-1]\n\n # Filter out empty string added by shap\n scores_desc = [t for t in scores_desc if t[0] != \"\"]\n\n fig_m = plt.figure()\n\n # Select top 5 words that contribute to positive sentiment\n plt.bar(x=[s[0] for s in scores_desc[:5]],\n height=[s[1] for s in scores_desc[:5]])\n plt.title(\"Top words contributing to positive sentiment\")\n plt.ylabel(\"Shap Value\")\n plt.xlabel(\"Word\")\n return {\"original\": text, \"interpretation\": scores}, fig_m\n
And this is how the app code will look:
\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n interpret = gr.Button(\"Interpret\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n with gr.Column():\n with gr.Tabs():\n with gr.TabItem(\"Display interpretation with built-in component\"):\n interpretation = gr.components.Interpretation(input_text)\n with gr.TabItem(\"Display interpretation with plot\"):\n interpretation_plot = gr.Plot()\n\n classify.click(classifier, input_text, label)\n interpret.click(interpretation_function, input_text, [interpretation, interpretation_plot])\n\ndemo.launch()\n
You can see the demo below!
\n\nAlthough we have focused on sentiment classification so far, you can add interpretations to almost any machine learning model.\nThe output must be an gr.Image
or gr.Label
but the input can be almost anything (gr.Number
, gr.Slider
, gr.Radio
, gr.Image
).
Here is a demo built with blocks of interpretations for an image classification model:
\n\nWe did a deep dive \ud83e\udd3f into how interpretations work and how you can add them to your Blocks app.
\n\nWe also showed how the Blocks API gives you the power to control how the interpretation is visualized in your app.
\n\nAdding interpretations is a helpful way to make your users understand and gain trust in your model.\nNow you have all the tools you need to add them to all of your apps!
\n", - "tags": ["INTERPRETATION", "SENTIMENT ANALYSIS"], - "spaces": [], - "url": "/guides/custom-interpretations-with-blocks/", - "contributor": null - }, - { - "name": "using-blocks-like-functions", - "category": "building-with-blocks", - "pretty_category": "Building With Blocks", - "guide_index": 5, - "absolute_index": 12, - "pretty_name": "Using Blocks Like Functions", - "content": "# Using Gradio Blocks Like Functions\n\n\n\n**Prerequisite**: This Guide builds on the Blocks Introduction. Make sure to [read that guide first](https://gradio.app/guides/quickstart/#blocks-more-flexibility-and-control).\n\n## Introduction\n\nDid you know that apart from being a full-stack machine learning demo, a Gradio Blocks app is also a regular-old python function!?\n\nThis means that if you have a gradio Blocks (or Interface) app called `demo`, you can use `demo` like you would any python function.\n\nSo doing something like `output = demo(\"Hello\", \"friend\")` will run the first event defined in `demo` on the inputs \"Hello\" and \"friend\" and store it\nin the variable `output`.\n\nIf I put you to sleep \ud83e\udd71, please bear with me! By using apps like functions, you can seamlessly compose Gradio apps.\nThe following section will show how.\n\n## Treating Blocks like functions\n\nLet's say we have the following demo that translates english text to german text. \n\n```python\nimport gradio as gr\n\nfrom transformers import pipeline\n\npipe = pipeline(\"translation\", model=\"t5-base\")\n\n\ndef translate(text):\n return pipe(text)[0][\"translation_text\"]\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n english = gr.Textbox(label=\"English text\")\n translate_btn = gr.Button(value=\"Translate\")\n with gr.Column():\n german = gr.Textbox(label=\"German Text\")\n\n translate_btn.click(translate, inputs=english, outputs=german, api_name=\"translate-to-german\")\n examples = gr.Examples(examples=[\"I went to the supermarket yesterday.\", \"Helen is a good swimmer.\"],\n inputs=[english])\n\ndemo.launch()\n```\n\nI already went ahead and hosted it in Hugging Face spaces at [gradio/english_translator](https://huggingface.co/spaces/gradio/english_translator).\n\nYou can see the demo below as well:\n\nPrerequisite: This Guide builds on the Blocks Introduction. Make sure to read that guide first.
\n\nDid you know that apart from being a full-stack machine learning demo, a Gradio Blocks app is also a regular-old python function!?
\n\nThis means that if you have a gradio Blocks (or Interface) app called demo
, you can use demo
like you would any python function.
So doing something like output = demo(\"Hello\", \"friend\")
will run the first event defined in demo
on the inputs \"Hello\" and \"friend\" and store it\nin the variable output
.
If I put you to sleep \ud83e\udd71, please bear with me! By using apps like functions, you can seamlessly compose Gradio apps.\nThe following section will show how.
\n\nLet's say we have the following demo that translates english text to german text.
\n\nimport gradio as gr\n\nfrom transformers import pipeline\n\npipe = pipeline(\"translation\", model=\"t5-base\")\n\n\ndef translate(text):\n return pipe(text)[0][\"translation_text\"]\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n english = gr.Textbox(label=\"English text\")\n translate_btn = gr.Button(value=\"Translate\")\n with gr.Column():\n german = gr.Textbox(label=\"German Text\")\n\n translate_btn.click(translate, inputs=english, outputs=german, api_name=\"translate-to-german\")\n examples = gr.Examples(examples=[\"I went to the supermarket yesterday.\", \"Helen is a good swimmer.\"],\n inputs=[english])\n\ndemo.launch()\n
I already went ahead and hosted it in Hugging Face spaces at gradio/english_translator.
\n\nYou can see the demo below as well:
\n\nNow, let's say you have an app that generates english text, but you wanted to additionally generate german text.
\n\nYou could either:
\n\nCopy the source code of my english-to-german translation and paste it in your app.
Load my english-to-german translation in your app and treat it like a normal python function.
Option 1 technically always works, but it often introduces unwanted complexity.
\n\nOption 2 lets you borrow the functionality you want without tightly coupling our apps.
\n\nAll you have to do is call the Blocks.load
class method in your source file.\nAfter that, you can use my translation app like a regular python function!
The following code snippet and demo shows how to use Blocks.load
.
Note that the variable english_translator
is my english to german app, but its used in generate_text
like a regular function.
import gradio as gr\n\nfrom transformers import pipeline\n\nenglish_translator = gr.Blocks.load(name=\"spaces/gradio/english_translator\")\nenglish_generator = pipeline(\"text-generation\", model=\"distilgpt2\")\n\n\ndef generate_text(text):\n english_text = english_generator(text)[0][\"generated_text\"]\n german_text = english_translator(english_text)\n return english_text, german_text\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n seed = gr.Text(label=\"Input Phrase\")\n with gr.Column():\n english = gr.Text(label=\"Generated English Text\")\n german = gr.Text(label=\"Generated German Text\")\n btn = gr.Button(\"Generate\")\n btn.click(generate_text, inputs=[seed], outputs=[english, german])\n gr.Examples([\"My name is Clara and I am\"], inputs=[seed])\n\ndemo.launch()\n
If the app you are loading defines more than one function, you can specify which function to use\nwith the fn_index
and api_name
parameters.
In the code for our english to german demo, you'll see the following line:
\n\ntranslate_btn.click(translate, inputs=english, outputs=german, api_name=\"translate-to-german\")\n
The api_name
gives this function a unique name in our app. You can use this name to tell gradio which\nfunction in the upstream space you want to use:
english_generator(text, api_name=\"translate-to-german\")[0][\"generated_text\"]\n
You can also use the fn_index
parameter.\nImagine my app also defined an english to spanish translation function.\nIn order to use it in our text generation app, we would use the following code:
english_generator(text, fn_index=1)[0][\"generated_text\"]\n
Functions in gradio spaces are zero-indexed, so since the spanish translator would be the second function in my space,\nyou would use index 1.
\n\nWe showed how treating a Blocks app like a regular python helps you compose functionality across different apps.\nAny Blocks app can be treated like a function, but a powerful pattern is to load
an app hosted on \nHugging Face Spaces prior to treating it like a function in your own app.\nYou can also load models hosted on the Hugging Face Model Hub - see the Using Hugging Face Integrations guide for an example.
By default, Components in Blocks are arranged vertically. Let's take a look at how we can rearrange Components. Under the hood, this layout structure uses the flexbox model of web development.
\n\nElements within a with gr.Row
clause will all be displayed horizontally. For example, to display two Buttons side by side:
with gr.Blocks() as demo:\n with gr.Row():\n btn1 = gr.Button(\"Button 1\")\n btn2 = gr.Button(\"Button 2\")\n
To make every element in a Row have the same height, use the equal_height
argument of the style
method.
with gr.Blocks() as demo:\n with gr.Row().style(equal_height=True):\n textbox = gr.Textbox()\n btn2 = gr.Button(\"Button 2\")\n
The widths of elements in a Row can be controlled via a combination of scale
and min_width
arguments that are present in every Component.
scale
is an integer that defines how an element will take up space in a Row. If scale is set to 0
, and element will not expand to take up space. If scale is set to 1
or greater, the element well expand. Multiple elements in a row will expand proportional to their scale. Below, btn1
will expand twice as much as btn2
, while btn0
will not expand at all:with gr.Blocks() as demo:\n with gr.Row():\n btn0 = gr.Button(\"Button 0\", scale=0)\n btn1 = gr.Button(\"Button 1\", scale=1)\n btn2 = gr.Button(\"Button 2\", scale=2)\n
min_width
will set the minimum width the element will take. The Row will wrap if there isn't sufficient space to satisfy all min_width
values.Learn more about Rows in the docs.
\n\nComponents within a Column will be placed vertically atop each other. Since the vertical layout is the default layout for Blocks apps anyway, to be useful, Columns are usually nested within Rows. For example:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n text1 = gr.Textbox(label=\"t1\")\n slider2 = gr.Textbox(label=\"s2\")\n drop3 = gr.Dropdown([\"a\", \"b\", \"c\"], label=\"d3\")\n with gr.Row():\n with gr.Column(scale=1, min_width=600):\n text1 = gr.Textbox(label=\"prompt 1\")\n text2 = gr.Textbox(label=\"prompt 2\")\n inbtw = gr.Button(\"Between\")\n text4 = gr.Textbox(label=\"prompt 1\")\n text5 = gr.Textbox(label=\"prompt 2\")\n with gr.Column(scale=2, min_width=600):\n img1 = gr.Image(\"images/cheetah.jpg\")\n btn = gr.Button(\"Go\").style(full_width=True)\n\ndemo.launch()\n
See how the first column has two Textboxes arranged vertically. The second column has an Image and Button arranged vertically. Notice how the relative widths of the two columns is set by the scale
parameter. The column with twice the scale
value takes up twice the width.
Learn more about Columns in the docs.
\n\nYou can also create Tabs using the with gr.Tab('tab_name'):
clause. Any component created inside of a with gr.Tab('tab_name'):
context appears in that tab. Consecutive Tab clauses are grouped together so that a single tab can be selected at one time, and only the components within that Tab's context are shown.
For example:
\n\nimport numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
Also note the gr.Accordion('label')
in this example. The Accordion is a layout that can be toggled open or closed. Like Tabs
, it is a layout element that can selectively hide or show content. Any components that are defined inside of a with gr.Accordion('label'):
will be hidden or shown when the accordion's toggle icon is clicked.
Learn more about Tabs and Accordions in the docs.
\n\nBoth Components and Layout elements have a visible
argument that can set initially and also updated using gr.update()
. Setting gr.update(visible=...)
on a Column can be used to show or hide a set of Components.
import gradio as gr\n\nwith gr.Blocks() as demo:\n error_box = gr.Textbox(label=\"Error\", visible=False)\n\n name_box = gr.Textbox(label=\"Name\")\n age_box = gr.Number(label=\"Age\", minimum=0, maximum=100)\n symptoms_box = gr.CheckboxGroup([\"Cough\", \"Fever\", \"Runny Nose\"])\n submit_btn = gr.Button(\"Submit\")\n\n with gr.Column(visible=False) as output_col:\n diagnosis_box = gr.Textbox(label=\"Diagnosis\")\n patient_summary_box = gr.Textbox(label=\"Patient Summary\")\n\n def submit(name, age, symptoms):\n if len(name) == 0:\n return {error_box: gr.update(value=\"Enter name\", visible=True)}\n return {\n output_col: gr.update(visible=True),\n diagnosis_box: \"covid\" if \"Cough\" in symptoms else \"flu\",\n patient_summary_box: f\"{name}, {age} y/o\",\n }\n\n submit_btn.click(\n submit,\n [name_box, age_box, symptoms_box],\n [error_box, diagnosis_box, patient_summary_box, output_col],\n )\n\ndemo.launch()\n\n
By adjusting the visibility of components in a dynamic way, it is possible to create\ndemos with Gradio that support a variable numbers of outputs. Here's a very simple example\nwhere the number of output textboxes is controlled by an input slider:
\n\nimport gradio as gr\n\nmax_textboxes = 10\n\ndef variable_outputs(k):\n k = int(k)\n return [gr.Textbox.update(visible=True)]*k + [gr.Textbox.update(visible=False)]*(max_textboxes-k)\n\nwith gr.Blocks() as demo:\n s = gr.Slider(1, max_textboxes, value=max_textboxes, step=1, label=\"How many textboxes to show:\")\n textboxes = []\n for i in range(max_textboxes):\n t = gr.Textbox(f\"Textbox {i}\")\n textboxes.append(t)\n\n s.change(variable_outputs, s, textboxes)\n\nif __name__ == \"__main__\":\n demo.launch()\n\n
In some cases, you might want to define components before you actually render them in your UI. For instance, you might want to show an examples section using gr.Examples
above the corresponding gr.Textbox
input. Since gr.Examples
requires as a parameter the input component object, you will need to first define the input component, but then render it later, after you have defined the gr.Examples
object.
The solution to this is to define the gr.Textbox
outside of the gr.Blocks()
scope and use the component's .render()
method wherever you'd like it placed in the UI.
Here's a full code example:
\n\ninput_textbox = gr.Textbox()\n\nwith gr.Blocks() as demo:\n gr.Examples([\"hello\", \"bonjour\", \"merhaba\"], input_textbox)\n input_textbox.render()\n
By default, Components in Blocks are arranged vertically. Let's take a look at how we can rearrange Components. Under the hood, this layout structure uses the flexbox model of web development.
\n\nElements within a with gr.Row
clause will all be displayed horizontally. For example, to display two Buttons side by side:
with gr.Blocks() as demo:\n with gr.Row():\n btn1 = gr.Button(\"Button 1\")\n btn2 = gr.Button(\"Button 2\")\n
To make every element in a Row have the same height, use the equal_height
argument of the style
method.
with gr.Blocks() as demo:\n with gr.Row().style(equal_height=True):\n textbox = gr.Textbox()\n btn2 = gr.Button(\"Button 2\")\n
The widths of elements in a Row can be controlled via a combination of scale
and min_width
arguments that are present in every Component.
scale
is an integer that defines how an element will take up space in a Row. If scale is set to 0
, and element will not expand to take up space. If scale is set to 1
or greater, the element well expand. Multiple elements in a row will expand proportional to their scale. Below, btn1
will expand twice as much as btn2
, while btn0
will not expand at all:with gr.Blocks() as demo:\n with gr.Row():\n btn0 = gr.Button(\"Button 0\", scale=0)\n btn1 = gr.Button(\"Button 1\", scale=1)\n btn2 = gr.Button(\"Button 2\", scale=2)\n
min_width
will set the minimum width the element will take. The Row will wrap if there isn't sufficient space to satisfy all min_width
values.Learn more about Rows in the docs.
\n\nComponents within a Column will be placed vertically atop each other. Since the vertical layout is the default layout for Blocks apps anyway, to be useful, Columns are usually nested within Rows. For example:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n text1 = gr.Textbox(label=\"t1\")\n slider2 = gr.Textbox(label=\"s2\")\n drop3 = gr.Dropdown([\"a\", \"b\", \"c\"], label=\"d3\")\n with gr.Row():\n with gr.Column(scale=1, min_width=600):\n text1 = gr.Textbox(label=\"prompt 1\")\n text2 = gr.Textbox(label=\"prompt 2\")\n inbtw = gr.Button(\"Between\")\n text4 = gr.Textbox(label=\"prompt 1\")\n text5 = gr.Textbox(label=\"prompt 2\")\n with gr.Column(scale=2, min_width=600):\n img1 = gr.Image(\"images/cheetah.jpg\")\n btn = gr.Button(\"Go\").style(full_width=True)\n\ndemo.launch()\n
See how the first column has two Textboxes arranged vertically. The second column has an Image and Button arranged vertically. Notice how the relative widths of the two columns is set by the scale
parameter. The column with twice the scale
value takes up twice the width.
Learn more about Columns in the docs.
\n\nYou can also create Tabs using the with gr.Tab('tab_name'):
clause. Any component created inside of a with gr.Tab('tab_name'):
context appears in that tab. Consecutive Tab clauses are grouped together so that a single tab can be selected at one time, and only the components within that Tab's context are shown.
For example:
\n\nimport numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
Also note the gr.Accordion('label')
in this example. The Accordion is a layout that can be toggled open or closed. Like Tabs
, it is a layout element that can selectively hide or show content. Any components that are defined inside of a with gr.Accordion('label'):
will be hidden or shown when the accordion's toggle icon is clicked.
Learn more about Tabs and Accordions in the docs.
\n\nBoth Components and Layout elements have a visible
argument that can set initially and also updated using gr.update()
. Setting gr.update(visible=...)
on a Column can be used to show or hide a set of Components.
import gradio as gr\n\nwith gr.Blocks() as demo:\n error_box = gr.Textbox(label=\"Error\", visible=False)\n\n name_box = gr.Textbox(label=\"Name\")\n age_box = gr.Number(label=\"Age\", minimum=0, maximum=100)\n symptoms_box = gr.CheckboxGroup([\"Cough\", \"Fever\", \"Runny Nose\"])\n submit_btn = gr.Button(\"Submit\")\n\n with gr.Column(visible=False) as output_col:\n diagnosis_box = gr.Textbox(label=\"Diagnosis\")\n patient_summary_box = gr.Textbox(label=\"Patient Summary\")\n\n def submit(name, age, symptoms):\n if len(name) == 0:\n return {error_box: gr.update(value=\"Enter name\", visible=True)}\n return {\n output_col: gr.update(visible=True),\n diagnosis_box: \"covid\" if \"Cough\" in symptoms else \"flu\",\n patient_summary_box: f\"{name}, {age} y/o\",\n }\n\n submit_btn.click(\n submit,\n [name_box, age_box, symptoms_box],\n [error_box, diagnosis_box, patient_summary_box, output_col],\n )\n\ndemo.launch()\n\n
By adjusting the visibility of components in a dynamic way, it is possible to create\ndemos with Gradio that support a variable numbers of outputs. Here's a very simple example\nwhere the number of output textboxes is controlled by an input slider:
\n\nimport gradio as gr\n\nmax_textboxes = 10\n\ndef variable_outputs(k):\n k = int(k)\n return [gr.Textbox.update(visible=True)]*k + [gr.Textbox.update(visible=False)]*(max_textboxes-k)\n\nwith gr.Blocks() as demo:\n s = gr.Slider(1, max_textboxes, value=max_textboxes, step=1, label=\"How many textboxes to show:\")\n textboxes = []\n for i in range(max_textboxes):\n t = gr.Textbox(f\"Textbox {i}\")\n textboxes.append(t)\n\n s.change(variable_outputs, s, textboxes)\n\nif __name__ == \"__main__\":\n demo.launch()\n\n
In some cases, you might want to define components before you actually render them in your UI. For instance, you might want to show an examples section using gr.Examples
above the corresponding gr.Textbox
input. Since gr.Examples
requires as a parameter the input component object, you will need to first define the input component, but then render it later, after you have defined the gr.Examples
object.
The solution to this is to define the gr.Textbox
outside of the gr.Blocks()
scope and use the component's .render()
method wherever you'd like it placed in the UI.
Here's a full code example:
\n\ninput_textbox = gr.Textbox()\n\nwith gr.Blocks() as demo:\n gr.Examples([\"hello\", \"bonjour\", \"merhaba\"], input_textbox)\n input_textbox.render()\n
By default, Components in Blocks are arranged vertically. Let's take a look at how we can rearrange Components. Under the hood, this layout structure uses the flexbox model of web development.
\n\nElements within a with gr.Row
clause will all be displayed horizontally. For example, to display two Buttons side by side:
with gr.Blocks() as demo:\n with gr.Row():\n btn1 = gr.Button(\"Button 1\")\n btn2 = gr.Button(\"Button 2\")\n
To make every element in a Row have the same height, use the equal_height
argument of the style
method.
with gr.Blocks() as demo:\n with gr.Row().style(equal_height=True):\n textbox = gr.Textbox()\n btn2 = gr.Button(\"Button 2\")\n
The widths of elements in a Row can be controlled via a combination of scale
and min_width
arguments that are present in every Component.
scale
is an integer that defines how an element will take up space in a Row. If scale is set to 0
, and element will not expand to take up space. If scale is set to 1
or greater, the element well expand. Multiple elements in a row will expand proportional to their scale. Below, btn1
will expand twice as much as btn2
, while btn0
will not expand at all:with gr.Blocks() as demo:\n with gr.Row():\n btn0 = gr.Button(\"Button 0\", scale=0)\n btn1 = gr.Button(\"Button 1\", scale=1)\n btn2 = gr.Button(\"Button 2\", scale=2)\n
min_width
will set the minimum width the element will take. The Row will wrap if there isn't sufficient space to satisfy all min_width
values.Learn more about Rows in the docs.
\n\nComponents within a Column will be placed vertically atop each other. Since the vertical layout is the default layout for Blocks apps anyway, to be useful, Columns are usually nested within Rows. For example:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n text1 = gr.Textbox(label=\"t1\")\n slider2 = gr.Textbox(label=\"s2\")\n drop3 = gr.Dropdown([\"a\", \"b\", \"c\"], label=\"d3\")\n with gr.Row():\n with gr.Column(scale=1, min_width=600):\n text1 = gr.Textbox(label=\"prompt 1\")\n text2 = gr.Textbox(label=\"prompt 2\")\n inbtw = gr.Button(\"Between\")\n text4 = gr.Textbox(label=\"prompt 1\")\n text5 = gr.Textbox(label=\"prompt 2\")\n with gr.Column(scale=2, min_width=600):\n img1 = gr.Image(\"images/cheetah.jpg\")\n btn = gr.Button(\"Go\").style(full_width=True)\n\ndemo.launch()\n
See how the first column has two Textboxes arranged vertically. The second column has an Image and Button arranged vertically. Notice how the relative widths of the two columns is set by the scale
parameter. The column with twice the scale
value takes up twice the width.
Learn more about Columns in the docs.
\n\nYou can also create Tabs using the with gr.Tab('tab_name'):
clause. Any component created inside of a with gr.Tab('tab_name'):
context appears in that tab. Consecutive Tab clauses are grouped together so that a single tab can be selected at one time, and only the components within that Tab's context are shown.
For example:
\n\nimport numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
Also note the gr.Accordion('label')
in this example. The Accordion is a layout that can be toggled open or closed. Like Tabs
, it is a layout element that can selectively hide or show content. Any components that are defined inside of a with gr.Accordion('label'):
will be hidden or shown when the accordion's toggle icon is clicked.
Learn more about Tabs and Accordions in the docs.
\n\nBoth Components and Layout elements have a visible
argument that can set initially and also updated using gr.update()
. Setting gr.update(visible=...)
on a Column can be used to show or hide a set of Components.
import gradio as gr\n\nwith gr.Blocks() as demo:\n error_box = gr.Textbox(label=\"Error\", visible=False)\n\n name_box = gr.Textbox(label=\"Name\")\n age_box = gr.Number(label=\"Age\", minimum=0, maximum=100)\n symptoms_box = gr.CheckboxGroup([\"Cough\", \"Fever\", \"Runny Nose\"])\n submit_btn = gr.Button(\"Submit\")\n\n with gr.Column(visible=False) as output_col:\n diagnosis_box = gr.Textbox(label=\"Diagnosis\")\n patient_summary_box = gr.Textbox(label=\"Patient Summary\")\n\n def submit(name, age, symptoms):\n if len(name) == 0:\n return {error_box: gr.update(value=\"Enter name\", visible=True)}\n return {\n output_col: gr.update(visible=True),\n diagnosis_box: \"covid\" if \"Cough\" in symptoms else \"flu\",\n patient_summary_box: f\"{name}, {age} y/o\",\n }\n\n submit_btn.click(\n submit,\n [name_box, age_box, symptoms_box],\n [error_box, diagnosis_box, patient_summary_box, output_col],\n )\n\ndemo.launch()\n\n
By adjusting the visibility of components in a dynamic way, it is possible to create\ndemos with Gradio that support a variable numbers of outputs. Here's a very simple example\nwhere the number of output textboxes is controlled by an input slider:
\n\nimport gradio as gr\n\nmax_textboxes = 10\n\ndef variable_outputs(k):\n k = int(k)\n return [gr.Textbox.update(visible=True)]*k + [gr.Textbox.update(visible=False)]*(max_textboxes-k)\n\nwith gr.Blocks() as demo:\n s = gr.Slider(1, max_textboxes, value=max_textboxes, step=1, label=\"How many textboxes to show:\")\n textboxes = []\n for i in range(max_textboxes):\n t = gr.Textbox(f\"Textbox {i}\")\n textboxes.append(t)\n\n s.change(variable_outputs, s, textboxes)\n\nif __name__ == \"__main__\":\n demo.launch()\n\n
In some cases, you might want to define components before you actually render them in your UI. For instance, you might want to show an examples section using gr.Examples
above the corresponding gr.Textbox
input. Since gr.Examples
requires as a parameter the input component object, you will need to first define the input component, but then render it later, after you have defined the gr.Examples
object.
The solution to this is to define the gr.Textbox
outside of the gr.Blocks()
scope and use the component's .render()
method wherever you'd like it placed in the UI.
Here's a full code example:
\n\ninput_textbox = gr.Textbox()\n\nwith gr.Blocks() as demo:\n gr.Examples([\"hello\", \"bonjour\", \"merhaba\"], input_textbox)\n input_textbox.render()\n
Chatbots are a popular application of large language models. Using gradio
, you can easily build a demo of your chatbot model and share that with your users, or try it yourself using an intuitive chatbot UI.
This tutorial uses gr.ChatInterface()
, which is a high-level abstraction that allows you to create your chatbot UI fast, often with a single line of code. The chatbot interface that we create will look something like this:
We'll start with a couple of simple examples, and then show how to use gr.ChatInterface()
with real language models from several popular APIs and libraries, including langchain
, openai
, and Hugging Face.
Prerequisites: please make sure you are using the latest version version of Gradio:
\n\n$ pip install --upgrade gradio\n
When working with gr.ChatInterface()
, the first thing you should do is define your chat function. Your chat function should take two arguments: message
and then history
(the arguments can be named anything, but must be in this order).
message
: a str
representing the user's input.history
: a list
of list
representing the conversations up until that point. Each inner list consists of two str
representing a pair: [user input, bot response]
. Your function should return a single string response, which is the bot's response to the particular user input message
. Your function can take into account the history
of messages, as well as the current message.
Let's take a look at a few examples.
\n\nLet's write a chat function that responds Yes
or No
randomly.
Here's our chat function:
\n\nimport random\n\ndef random_response(message, history):\n return random.choice([\"Yes\", \"No\"])\n
Now, we can plug this into gr.ChatInterface()
and call the .launch()
method to create the web interface:
import gradio as gr\n\ngr.ChatInterface(random_response).launch()\n
That's it! Here's our running demo, try it out:
\n\nOf course, the previous example was very simplistic, it didn't even take user input or the previous history into account! Here's another simple example showing how to incorporate a user's input as well as the history.
\n\nimport random\nimport gradio as gr\n\ndef alternatingly_agree(message, history):\n if len(history) % 2 == 0:\n return f\"Yes, I do think that '{message}'\"\n else:\n return \"I don't think so\"\n\ngr.ChatInterface(alternatingly_agree).launch()\n
If in your chat function, you use yield
to generate a sequence of responses, you'll end up with a streaming chatbot. It's that simple!
import time\nimport gradio as gr\n\ndef slow_echo(message, history):\n for i in range(len(message)):\n time.sleep(0.3)\n yield \"You typed: \" + message[: i+1]\n\ngr.ChatInterface(slow_echo).queue().launch()\n
Notice that we've enabled queuing, which is required to use generator functions. While the response is streaming, the \"Submit\" button turns into a \"Stop\" button that can be used to stop the generator function. You can customize the appearance and behavior of the \"Stop\" button using the stop_btn
parameter.
If you're familiar with Gradio's Interface
class, the gr.ChatInterface
includes many of the same arguments that you can use to customize the look and feel of your Chatbot. For example, you can:
title
and description
arguments.theme
and css
arguments respectively.examples
and even enable cache_examples
, which make it easier for users to try it out .submit_btn
, retry_btn
, undo_btn
, clear_btn
.If you want to customize the gr.Chatbot
or gr.Textbox
that compose the ChatInterface
, then you can pass in your own chatbot or textbox as well. Here's an example of how we can use these parameters:
import gradio as gr\n\ndef yes_man(message, history):\n if message.endswith(\"?\"):\n return \"Yes\"\n else:\n return \"Ask me anything!\"\n\ngr.ChatInterface(\n yes_man,\n chatbot=gr.Chatbot(height=300),\n textbox=gr.Textbox(placeholder=\"Ask me a yes or no question\", container=False, scale=7),\n title=\"Yes Man\",\n description=\"Ask Yes Man any question\",\n theme=\"soft\",\n examples=[\"Hello\", \"Am I cool?\", \"Are tomatoes vegetables?\"],\n cache_examples=True,\n retry_btn=None,\n undo_btn=\"Delete Previous\",\n clear_btn=\"Clear\",\n).launch()\n
You may want to add additional parameters to your chatbot and expose them to your users through the Chatbot UI. For example, suppose you want to add a textbox for a system prompt, or a slider that sets the number of tokens in the chatbot's response. The ChatInterface
class supports an additional_inputs
parameter which can be used to add additional input components.
The additional_inputs
parameters accepts a component or a list of components. You can pass the component instances directly, or use their string shortcuts (e.g. \"textbox\"
instead of gr.Textbox()
). If you pass in component instances, and they have not already been rendered, then the components will appear underneath the chatbot (and any examples) within a gr.Accordion()
. You can set the label of this accordion using the additional_inputs_accordion_name
parameter.
Here's a complete example:
\n\nimport gradio as gr\nimport time\n\ndef echo(message, history, system_prompt, tokens):\n response = f\"System prompt: {system_prompt}\\n Message: {message}.\"\n for i in range(min(len(response), int(tokens))):\n time.sleep(0.05)\n yield response[: i+1]\n\ndemo = gr.ChatInterface(echo, \n additional_inputs=[\n gr.Textbox(\"You are helpful AI.\", label=\"System Prompt\"), \n gr.Slider(10, 100)\n ]\n )\n\nif __name__ == \"__main__\":\n demo.queue().launch()\n
If the components you pass into the additional_inputs
have already been rendered in a parent gr.Blocks()
, then they will not be re-rendered in the accordion. This provides flexibility in deciding where to lay out the input components. In the example below, we position the gr.Textbox()
on top of the Chatbot UI, while keeping the slider underneath.
import gradio as gr\nimport time\n\ndef echo(message, history, system_prompt, tokens):\n response = f\"System prompt: {system_prompt}\\n Message: {message}.\"\n for i in range(min(len(response), int(tokens))):\n time.sleep(0.05)\n yield response[: i+1]\n\nwith gr.Blocks() as demo:\n system_prompt = gr.Textbox(\"You are helpful AI.\", label=\"System Prompt\")\n slider = gr.Slider(10, 100, render=False)\n\n gr.ChatInterface(\n echo, additional_inputs=[system_prompt, slider]\n )\n\ndemo.queue().launch()\n
If you need to create something even more custom, then its best to construct the chatbot UI using the low-level gr.Blocks()
API. We have a dedicated guide for that here.
Once you've built your Gradio chatbot and are hosting it on Hugging Face Spaces or somewhere else, then you can query it with a simple API at the /chat
endpoint. The endpoint just expects the user's message (and potentially additional inputs if you have set any using the additional_inputs
parameter), and will return the response, internally keeping track of the messages sent so far.
To use the endpoint, you should use either the Gradio Python Client or the Gradio JS client.
\n\nlangchain
exampleNow, let's actually use the gr.ChatInterface
with some real large language models. We'll start by using langchain
on top of openai
to build a general-purpose streaming chatbot application in 19 lines of code. You'll need to have an OpenAI key for this example (keep reading for the free, open-source equivalent!)
from langchain.chat_models import ChatOpenAI\nfrom langchain.schema import AIMessage, HumanMessage\nimport openai\nimport gradio as gr\n\nos.envrion[\"OPENAI_API_KEY\"] = \"sk-...\" # Replace with your key\n\nllm = ChatOpenAI(temperature=1.0, model='gpt-3.5-turbo-0613')\n\ndef predict(message, history):\n history_langchain_format = []\n for human, ai in history:\n history_langchain_format.append(HumanMessage(content=human))\n history_langchain_format.append(AIMessage(content=ai))\n history_langchain_format.append(HumanMessage(content=message))\n gpt_response = llm(history_langchain_format)\n return gpt_response.content\n\ngr.ChatInterface(predict).launch() \n
openai
Of course, we could also use the openai
library directy. Here a similar example, but this time with streaming results as well:
import openai\nimport gradio as gr\n\nopenai.api_key = \"sk-...\" # Replace with your key\n\ndef predict(message, history):\n history_openai_format = []\n for human, assistant in history:\n history_openai_format.append({\"role\": \"user\", \"content\": human })\n history_openai_format.append({\"role\": \"assistant\", \"content\":assistant})\n history_openai_format.append({\"role\": \"user\", \"content\": message})\n\n response = openai.ChatCompletion.create(\n model='gpt-3.5-turbo',\n messages= history_openai_format, \n temperature=1.0,\n stream=True\n )\n\n partial_message = \"\"\n for chunk in response:\n if len(chunk['choices'][0]['delta']) != 0:\n partial_message = partial_message + chunk['choices'][0]['delta']['content']\n yield partial_message \n\ngr.ChatInterface(predict).queue().launch() \n
Of course, in many cases you want to run a chatbot locally. Here's the equivalent example using Together's RedePajama model, from Hugging Face (this requires you to have a GPU with CUDA).
\n\nimport gradio as gr\nimport torch\nfrom transformers import AutoModelForCausalLM, AutoTokenizer, StoppingCriteria, StoppingCriteriaList, TextIteratorStreamer\nfrom threading import Thread\n\ntokenizer = AutoTokenizer.from_pretrained(\"togethercomputer/RedPajama-INCITE-Chat-3B-v1\")\nmodel = AutoModelForCausalLM.from_pretrained(\"togethercomputer/RedPajama-INCITE-Chat-3B-v1\", torch_dtype=torch.float16)\nmodel = model.to('cuda:0')\n\nclass StopOnTokens(StoppingCriteria):\n def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool:\n stop_ids = [29, 0]\n for stop_id in stop_ids:\n if input_ids[0][-1] == stop_id:\n return True\n return False\n\ndef predict(message, history): \n\n history_transformer_format = history + [[message, \"\"]]\n stop = StopOnTokens()\n\n messages = \"\".join([\"\".join([\"\\n:\"+item[0], \"\\n:\"+item[1]]) #curr_system_message + \n for item in history_transformer_format])\n\n model_inputs = tokenizer([messages], return_tensors=\"pt\").to(\"cuda\")\n streamer = TextIteratorStreamer(tokenizer, timeout=10., skip_prompt=True, skip_special_tokens=True)\n generate_kwargs = dict(\n model_inputs,\n streamer=streamer,\n max_new_tokens=1024,\n do_sample=True,\n top_p=0.95,\n top_k=1000,\n temperature=1.0,\n num_beams=1,\n stopping_criteria=StoppingCriteriaList([stop])\n )\n t = Thread(target=model.generate, kwargs=generate_kwargs)\n t.start()\n\n partial_message = \"\"\n for new_token in streamer:\n if new_token != '<':\n partial_message += new_token\n yield partial_message \n\n\ngr.ChatInterface(predict).queue().launch()\n
With those examples, you should be all set to create your own Gradio Chatbot demos soon! For building even more custom Chatbot applications, check out a dedicated guide using the low-level gr.Blocks()
API.
How to share your Gradio app:
\n\nGradio demos can be easily shared publicly by setting share=True
in the launch()
method. Like this:
demo.launch(share=True)\n
This generates a public, shareable link that you can send to anybody! When you send this link, the user on the other side can try out the model in their browser. Because the processing happens on your device (as long as your device stays on!), you don't have to worry about any packaging any dependencies. A share link usually looks something like this: XXXXX.gradio.app. Although the link is served through a Gradio URL, we are only a proxy for your local server, and do not store any data sent through your app.
\n\nKeep in mind, however, that these links are publicly accessible, meaning that anyone can use your model for prediction! Therefore, make sure not to expose any sensitive information through the functions you write, or allow any critical changes to occur on your device. If you set share=False
(the default, except in colab notebooks), only a local link is created, which can be shared by port-forwarding with specific users.
Share links expire after 72 hours.
\n\nIf you'd like to have a permanent link to your Gradio demo on the internet, use Hugging Face Spaces. Hugging Face Spaces provides the infrastructure to permanently host your machine learning model for free!
\n\nAfter you have created a free Hugging Face account, you have three methods to deploy your Gradio app to Hugging Face Spaces:
\n\nFrom terminal: run gradio deploy
in your app directory. The CLI will gather some basic metadata and then launch your app. To update your space, you can re-run this command or enable the Github Actions option to automatically update the Spaces on git push
.
From your browser: Drag and drop a folder containing your Gradio model and all related files here.
Connect Spaces with your Git repository and Spaces will pull the Gradio app from there. See this guide how to host on Hugging Face Spaces for more information.
Note: Some components, like gr.Image
, will display a \"Share\" button only on Spaces, so that users can share the generated output to the Discussions page of the Space easily. You can disable this with show_share_button
, such as gr.Image(show_share_button=False)
.
sharebutton=True\" />
\n\nOnce you have hosted your app on Hugging Face Spaces (or on your own server), you may want to embed the demo on a different website, such as your blog or your portfolio. Embedding an interactive demo allows people to try out the machine learning model that you have built, without needing to download or install anything \u2014 right in their browser! The best part is that you can embed interactive demos even in static websites, such as GitHub pages.
\n\nThere are two ways to embed your Gradio demos. You can find quick links to both options directly on the Hugging Face Space page, in the \"Embed this Space\" dropdown option:
\n\n\n\nWeb components typically offer a better experience to users than IFrames. Web components load lazily, meaning that they won't slow down the loading time of your website, and they automatically adjust their height based on the size of the Gradio app.
\n\nTo embed with Web Components:
\n\n\n
\n
element where you want to place the app. Set the src=
attribute to your Space's embed URL, which you can find in the \"Embed this Space\" button. For example:
\n
You can see examples of how web components look on the Gradio landing page.
\n\nYou can also customize the appearance and behavior of your web component with attributes that you pass into the <gradio-app>
tag:
src
: as we've seen, the src
attributes links to the URL of the hosted Gradio demo that you would like to embedspace
: an optional shorthand if your Gradio demo is hosted on Hugging Face Space. Accepts a username/space_name
instead of a full URL. Example: gradio/Echocardiogram-Segmentation
. If this attribute attribute is provided, then src
does not need to be provided.control_page_title
: a boolean designating whether the html title of the page should be set to the title of the Gradio app (by default \"false\"
)initial_height
: the initial height of the web component while it is loading the Gradio app, (by default \"300px\"
). Note that the final height is set based on the size of the Gradio app.container
: whether to show the border frame and information about where the Space is hosted (by default \"true\"
)info
: whether to show just the information about where the Space is hosted underneath the embedded app (by default \"true\"
)autoscroll
: whether to autoscroll to the output when prediction has finished (by default \"false\"
)eager
: whether to load the Gradio app as soon as the page loads (by default \"false\"
)theme_mode
: whether to use the dark
, light
, or default system
theme mode (by default \"system\"
)Here's an example of how to use these attributes to create a Gradio app that does not lazy load and has an initial height of 0px.
\n\n \n
Note: While Gradio's CSS will never impact the embedding page, the embedding page can affect the style of the embedded Gradio app. Make sure that any CSS in the parent page isn't so general that it could also apply to the embedded Gradio app and cause the styling to break. Element selectors such as header { ... }
and footer { ... }
will be the most likely to cause issues.
To embed with IFrames instead (if you cannot add javascript to your website, for example), add this element:
\n\n\n
Again, you can find the src=
attribute to your Space's embed URL, which you can find in the \"Embed this Space\" button.
Note: if you use IFrames, you'll probably want to add a fixed height
attribute and set style=\"border:0;\"
to remove the boreder. In addition, if your app requires permissions such as access to the webcam or the microphone, you'll need to provide that as well using the allow
attribute.
You can use almost any Gradio app as an API! In the footer of a Gradio app like this one, you'll see a \"Use via API\" link.
\n\n\n\nThis is a page that lists the endpoints that can be used to query the Gradio app, via our supported clients: either the Python client, or the JavaScript client. For each endpoint, Gradio automatically generates the parameters and their types, as well as example inputs.
\n\nThe endpoints are automatically created when you launch a Gradio Interface
. If you are using Gradio Blocks
, you can also set up a Gradio API page, though we recommend that you explicitly name each event listener, such as
btn.click(add, [num1, num2], output, api_name=\"addition\")\n
This will add and document the endpoint /api/addition/
to the automatically generated API page. Otherwise, your API endpoints will appear as \"unnamed\" endpoints.
Note: For Gradio apps in which queueing is enabled, users can bypass the queue if they make a POST request to your API endpoint. To disable this behavior, set api_open=False
in the queue()
method. To disable the API page altogether, set show_api=False
in .launch()
.
You may wish to put an authentication page in front of your app to limit who can open your app. With the auth=
keyword argument in the launch()
method, you can provide a tuple with a username and password, or a list of acceptable username/password tuples; Here's an example that provides password-based authentication for a single user named \"admin\":
demo.launch(auth=(\"admin\", \"pass1234\"))\n
For more complex authentication handling, you can even pass a function that takes a username and password as arguments, and returns True to allow authentication, False otherwise. This can be used for, among other things, making requests to 3rd-party authentication services.
\n\nHere's an example of a function that accepts any login where the username and password are the same:
\n\ndef same_auth(username, password):\n return username == password\ndemo.launch(auth=same_auth)\n
For authentication to work properly, third party cookies must be enabled in your browser.\nThis is not the case by default for Safari, Chrome Incognito Mode.
\n\nWhen a user makes a prediction to your app, you may need the underlying network request, in order to get the request headers (e.g. for advanced authentication), log the client's IP address, or for other reasons. Gradio supports this in a similar manner to FastAPI: simply add a function parameter whose type hint is gr.Request
and Gradio will pass in the network request as that parameter. Here is an example:
import gradio as gr\n\ndef echo(name, request: gr.Request):\n if request:\n print(\"Request headers dictionary:\", request.headers)\n print(\"IP address:\", request.client.host)\n return name\n\nio = gr.Interface(echo, \"textbox\", \"textbox\").launch()\n
Note: if your function is called directly instead of through the UI (this happens, for \nexample, when examples are cached), then request
will be None
. You should handle\nthis case explicitly to ensure that your app does not throw any errors. That is why\nwe have the explicit check if request
.
In some cases, you might have an existing FastAPI app, and you'd like to add a path for a Gradio demo.\nYou can easily do this with gradio.mount_gradio_app()
.
Here's a complete example:
\n\nfrom fastapi import FastAPI\nimport gradio as gr\n\nCUSTOM_PATH = \"/gradio\"\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_main():\n return {\"message\": \"This is your main app\"}\n\n\nio = gr.Interface(lambda x: \"Hello, \" + x + \"!\", \"textbox\", \"textbox\")\napp = gr.mount_gradio_app(app, io, path=CUSTOM_PATH)\n\n\n# Run this from the terminal as you would normally start a FastAPI app: `uvicorn run:app`\n# and navigate to http://localhost:8000/gradio in your browser.\n\n
Note that this approach also allows you run your Gradio apps on custom paths (http://localhost:8000/gradio
in the example above).
Sharing your Gradio app with others (by hosting it on Spaces, on your own server, or through temporary share links) exposes certain files on the host machine to users of your Gradio app.
\n\nIn particular, Gradio apps ALLOW users to access to three kinds of files:
\n\nFiles in the same directory (or a subdirectory) of where the Gradio script is launched from. For example, if the path to your gradio scripts is /home/usr/scripts/project/app.py
and you launch it from /home/usr/scripts/project/
, then users of your shared Gradio app will be able to access any files inside /home/usr/scripts/project/
. This is done so that you can easily reference these files in your Gradio app (e.g. for your app's examples
).
Temporary files created by Gradio. These are files that are created by Gradio as part of running your prediction function. For example, if your prediction function returns a video file, then Gradio will save that video to a temporary file and then send the path to the temporary file to the front end. You can customize the location of temporary files created by Gradio by setting the environment variable GRADIO_TEMP_DIR
to an absolute path, such as /home/usr/scripts/project/temp/
.
Files that you explicitly allow via the allowed_paths
parameter in launch()
. This parameter allows you to pass in a list of additional directories or exact filepaths you'd like to allow users to have access to. (By default, this parameter is an empty list).
Gradio DOES NOT ALLOW access to:
\n\nDotfiles (any files whose name begins with '.'
) or any files that are contained in any directory whose name begins with '.'
Files that you explicitly allow via the blocked_paths
parameter in launch()
. You can pass in a list of additional directories or exact filepaths to the blocked_paths
parameter in launch()
. This parameter takes precedence over the files that Gradio exposes by default or by the allowed_paths
.
Any other paths on the host machine. Users should NOT be able to access other arbitrary paths on the host.
Please make sure you are running the latest version of gradio
for these security settings to apply.
Prerequisite: Gradio requires Python 3.8 or higher, that's all!
\n\nOne of the best ways to share your machine learning model, API, or data science workflow with others is to create an interactive app that allows your users or colleagues to try out the demo in their browsers.
\n\nGradio allows you to build demos and share them, all in Python. And usually in just a few lines of code! So let's get started.
\n\nTo get Gradio running with a simple \"Hello, World\" example, follow these three steps:
\n\n1. Install Gradio using pip:
\n\npip install gradio\n
2. Run the code below as a Python script or in a Jupyter Notebook (or Google Colab):
\n\nimport gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\ndemo = gr.Interface(fn=greet, inputs=\"text\", outputs=\"text\")\n\ndemo.launch() \n
We shorten the imported name to gr
for better readability of code using Gradio. This is a widely adopted convention that you should follow so that anyone working with your code can easily understand it.
3. The demo below will appear automatically within the Jupyter Notebook, or pop in a browser on http://localhost:7860 if running from a script:
\n\nWhen developing locally, if you want to run the code as a Python script, you can use the Gradio CLI to launch the application in reload mode, which will provide seamless and fast development. Learn more about reloading in the Auto-Reloading Guide.
\n\ngradio app.py\n
Note: you can also do python app.py
, but it won't provide the automatic reload mechanism.
Interface
ClassYou'll notice that in order to make the demo, we created a gr.Interface
. This Interface
class can wrap any Python function with a user interface. In the example above, we saw a simple text-based function, but the function could be anything from music generator to a tax calculator to the prediction function of a pretrained machine learning model.
The core Interface
class is initialized with three required parameters:
fn
: the function to wrap a UI aroundinputs
: which component(s) to use for the input (e.g. \"text\"
, \"image\"
or \"audio\"
)outputs
: which component(s) to use for the output (e.g. \"text\"
, \"image\"
or \"label\"
)Let's take a closer look at these components used to provide input and output.
\n\nWe saw some simple Textbox
components in the previous examples, but what if you want to change how the UI components look or behave?
Let's say you want to customize the input text field \u2014 for example, you wanted it to be larger and have a text placeholder. If we use the actual class for Textbox
instead of using the string shortcut, you have access to much more customizability through component attributes.
import gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\ndemo = gr.Interface(\n fn=greet,\n inputs=gr.Textbox(lines=2, placeholder=\"Name Here...\"),\n outputs=\"text\",\n)\ndemo.launch()\n\n
Suppose you had a more complex function, with multiple inputs and outputs. In the example below, we define a function that takes a string, boolean, and number, and returns a string and number. Take a look how you pass a list of input and output components.
\n\nimport gradio as gr\n\ndef greet(name, is_morning, temperature):\n salutation = \"Good morning\" if is_morning else \"Good evening\"\n greeting = f\"{salutation} {name}. It is {temperature} degrees today\"\n celsius = (temperature - 32) * 5 / 9\n return greeting, round(celsius, 2)\n\ndemo = gr.Interface(\n fn=greet,\n inputs=[\"text\", \"checkbox\", gr.Slider(0, 100)],\n outputs=[\"text\", \"number\"],\n)\ndemo.launch()\n\n
You simply wrap the components in a list. Each component in the inputs
list corresponds to one of the parameters of the function, in order. Each component in the outputs
list corresponds to one of the values returned by the function, again in order.
Gradio supports many types of components, such as Image
, DataFrame
, Video
, or Label
. Let's try an image-to-image function to get a feel for these!
import numpy as np\nimport gradio as gr\n\ndef sepia(input_img):\n sepia_filter = np.array([\n [0.393, 0.769, 0.189], \n [0.349, 0.686, 0.168], \n [0.272, 0.534, 0.131]\n ])\n sepia_img = input_img.dot(sepia_filter.T)\n sepia_img /= sepia_img.max()\n return sepia_img\n\ndemo = gr.Interface(sepia, gr.Image(shape=(200, 200)), \"image\")\ndemo.launch()\n\n
When using the Image
component as input, your function will receive a NumPy array with the shape (height, width, 3)
, where the last dimension represents the RGB values. We'll return an image as well in the form of a NumPy array.
You can also set the datatype used by the component with the type=
keyword argument. For example, if you wanted your function to take a file path to an image instead of a NumPy array, the input Image
component could be written as:
gr.Image(type=\"filepath\", shape=...)\n
Also note that our input Image
component comes with an edit button \ud83d\udd89, which allows for cropping and zooming into images. Manipulating images in this way can help reveal biases or hidden flaws in a machine learning model!
You can read more about the many components and how to use them in the Gradio docs.
\n\nGradio includes a high-level class, gr.ChatInterface
, which is similar to gr.Interface
, but is specifically designed for chatbot UIs. The gr.ChatInterface
class also wraps a function but this function must have a specific signature. The function should take two arguments: message
and then history
(the arguments can be named anything, but must be in this order)
message
: a str
representing the user's inputhistory
: a list
of list
representing the conversations up until that point. Each inner list consists of two str
representing a pair: [user input, bot response]
. Your function should return a single string response, which is the bot's response to the particular user input message
.
Other than that, gr.ChatInterface
has no required parameters (though several are available for customization of the UI).
Here's a toy example:
\n\nimport random\nimport gradio as gr\n\ndef random_response(message, history):\n return random.choice([\"Yes\", \"No\"])\n\ndemo = gr.ChatInterface(random_response)\n\ndemo.launch()\n\n
You can read more about gr.ChatInterface
here.
Gradio offers two approaches to build apps:
\n\n1. Interface and ChatInterface, which provide a high-level abstraction for creating demos that we've been discussing so far.
\n\n2. Blocks, a low-level API for designing web apps with more flexible layouts and data flows. Blocks allows you to do things like feature multiple data flows and demos, control where components appear on the page, handle complex data flows (e.g. outputs can serve as inputs to other functions), and update properties/visibility of components based on user interaction \u2014 still all in Python. If this customizability is what you need, try Blocks
instead!
Let's take a look at a simple example. Note how the API here differs from Interface
.
import gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\nwith gr.Blocks() as demo:\n name = gr.Textbox(label=\"Name\")\n output = gr.Textbox(label=\"Output Box\")\n greet_btn = gr.Button(\"Greet\")\n greet_btn.click(fn=greet, inputs=name, outputs=output, api_name=\"greet\")\n\n\ndemo.launch()\n
Things to note:
\n\nBlocks
are made with a with
clause, and any component created inside this clause is automatically added to the app.Button
was created, and then a click
event-listener was added to this button. The API for this should look familiar! Like an Interface
, the click
method takes a Python function, input components, and output components.Here's an app to give you a taste of what's possible with Blocks
:
import numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
A lot more going on here! We'll cover how to create complex Blocks
apps like this in the building with blocks section for you.
Congrats, you're now familiar with the basics of Gradio! \ud83e\udd73 Go to our next guide to learn more about the key features of Gradio.
\n", - "tags": [], - "spaces": [], - "url": "/guides/quickstart/", - "contributor": null - }, - { - "name": "key-features", - "category": "getting-started", - "pretty_category": "Getting Started", - "guide_index": 2, - "absolute_index": 1, - "pretty_name": "Key Features", - "content": "# Key Features\n\nLet's go through some of the most popular features of Gradio! Here are Gradio's key features:\n\n1. [Adding example inputs](#example-inputs)\n2. [Passing custom error messages](#alerts)\n3. [Adding descriptive content](#descriptive-content)\n4. [Setting up flagging](#flagging)\n5. [Preprocessing and postprocessing](#preprocessing-and-postprocessing)\n6. [Styling demos](#styling)\n7. [Queuing users](#queuing)\n8. [Iterative outputs](#iterative-outputs)\n9. [Progress bars](#progress-bars)\n10. [Batch functions](#batch-functions)\n11. [Running on collaborative notebooks](#colab-notebooks)\n\n## Example Inputs\n\nYou can provide example data that a user can easily load into `Interface`. This can be helpful to demonstrate the types of inputs the model expects, as well as to provide a way to explore your dataset in conjunction with your model. To load example data, you can provide a **nested list** to the `examples=` keyword argument of the Interface constructor. Each sublist within the outer list represents a data sample, and each element within the sublist represents an input for each input component. The format of example data for each component is specified in the [Docs](https://gradio.app/docs#components).\n\n```python\nimport gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n if num2 == 0:\n raise gr.Error(\"Cannot divide by zero!\")\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\", \n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n examples=[\n [5, \"add\", 3],\n [4, \"divide\", 2],\n [-4, \"multiply\", 2.5],\n [0, \"subtract\", 1.2],\n ],\n title=\"Toy Calculator\",\n description=\"Here's a sample toy calculator. Allows you to calculate things like $2+2=4$\",\n)\ndemo.launch()\n\n```\nLet's go through some of the most popular features of Gradio! Here are Gradio's key features:
\n\nYou can provide example data that a user can easily load into Interface
. This can be helpful to demonstrate the types of inputs the model expects, as well as to provide a way to explore your dataset in conjunction with your model. To load example data, you can provide a nested list to the examples=
keyword argument of the Interface constructor. Each sublist within the outer list represents a data sample, and each element within the sublist represents an input for each input component. The format of example data for each component is specified in the Docs.
import gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n if num2 == 0:\n raise gr.Error(\"Cannot divide by zero!\")\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\", \n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n examples=[\n [5, \"add\", 3],\n [4, \"divide\", 2],\n [-4, \"multiply\", 2.5],\n [0, \"subtract\", 1.2],\n ],\n title=\"Toy Calculator\",\n description=\"Here's a sample toy calculator. Allows you to calculate things like $2+2=4$\",\n)\ndemo.launch()\n\n
You can load a large dataset into the examples to browse and interact with the dataset through Gradio. The examples will be automatically paginated (you can configure this through the examples_per_page
argument of Interface
).
Continue learning about examples in the More On Examples guide.
\n\nYou wish to pass custom error messages to the user. To do so, raise a gr.Error(\"custom message\")
to display an error message. If you try to divide by zero in the calculator demo above, a popup modal will display the custom error message. Learn more about Error in the docs.
You can also issue gr.Warning(\"message\")
and gr.Info(\"message\")
by having them as standalone lines in your function, which will immediately display modals while continuing the execution of your function. Queueing needs to be enabled for this to work.
Note below how the gr.Error
has to be raised, while the gr.Warning
and gr.Info
are single lines.
def start_process(name):\n gr.Info(\"Starting process\")\n if name is None:\n gr.Warning(\"Name is empty\")\n ...\n if success == False:\n raise gr.Error(\"Process failed\")\n
In the previous example, you may have noticed the title=
and description=
keyword arguments in the Interface
constructor that helps users understand your app.
There are three arguments in the Interface
constructor to specify where this content should go:
title
: which accepts text and can display it at the very top of interface, and also becomes the page title.description
: which accepts text, markdown or HTML and places it right under the title.article
: which also accepts text, markdown or HTML and places it below the interface.If you're using the Blocks
API instead, you can insert text, markdown, or HTML anywhere using the gr.Markdown(...)
or gr.HTML(...)
components, with descriptive content inside the Component
constructor.
Another useful keyword argument is label=
, which is present in every Component
. This modifies the label text at the top of each Component
. You can also add the info=
keyword argument to form elements like Textbox
or Radio
to provide further information on their usage.
gr.Number(label='Age', info='In years, must be greater than 0')\n
By default, an Interface
will have \"Flag\" button. When a user testing your Interface
sees input with interesting output, such as erroneous or unexpected model behaviour, they can flag the input for you to review. Within the directory provided by the flagging_dir=
argument to the Interface
constructor, a CSV file will log the flagged inputs. If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well.
For example, with the calculator interface shown above, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- calculator.py\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output\n5,add,7,12\n6,subtract,1.5,4.5\n
With the sepia interface shown earlier, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- sepia.py\n+-- flagged/\n| +-- logs.csv\n| +-- im/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output\nim/0.png,Output/0.png\nim/1.png,Output/1.png\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of the strings when flagging, which will be saved as an additional column to the CSV.
As you've seen, Gradio includes components that can handle a variety of different data types, such as images, audio, and video. Most components can be used both as inputs or outputs.
\n\nWhen a component is used as an input, Gradio automatically handles the preprocessing needed to convert the data from a type sent by the user's browser (such as a base64 representation of a webcam snapshot) to a form that can be accepted by your function (such as a numpy
array).
Similarly, when a component is used as an output, Gradio automatically handles the postprocessing needed to convert the data from what is returned by your function (such as a list of image paths) to a form that can be displayed in the user's browser (such as a Gallery
of images in base64 format).
You can control the preprocessing using the parameters when constructing the image component. For example, here if you instantiate the Image
component with the following parameters, it will convert the image to the PIL
type and reshape it to be (100, 100)
no matter the original size that it was submitted as:
img = gr.Image(shape=(100, 100), type=\"pil\")\n
In contrast, here we keep the original size of the image, but invert the colors before converting it to a numpy array:
\n\nimg = gr.Image(invert_colors=True, type=\"numpy\")\n
Postprocessing is a lot easier! Gradio automatically recognizes the format of the returned data (e.g. is the Image
a numpy
array or a str
filepath?) and postprocesses it into a format that can be displayed by the browser.
Take a look at the Docs to see all the preprocessing-related parameters for each Component.
\n\nGradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the theme=
kwarg to the Interface
constructor. For example:
demo = gr.Interface(..., theme=gr.themes.Monochrome())\n
Gradio comes with a set of prebuilt themes which you can load from gr.themes.*
. You can extend these themes or create your own themes from scratch - see the Theming guide for more details.
For additional styling ability, you can pass any CSS to your app using the css=
kwarg.\nThe base class for the Gradio app is gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Interface(css=\".gradio-container {background-color: red}\") as demo:\n ...\n
Some components can be additionally styled through the style()
method. For example:
img = gr.Image(\"lion.jpg\").style(height='24', rounded=False)\n
Take a look at the Docs to see all the styling options for each Component.
\n\nIf your app expects heavy traffic, use the queue()
method to control processing rate. This will queue up calls so only a certain number of requests are processed at a single time. Queueing uses websockets, which also prevent network timeouts, so you should use queueing if the inference time of your function is long (> 1min).
With Interface
:
demo = gr.Interface(...).queue()\ndemo.launch()\n
With Blocks
:
with gr.Blocks() as demo:\n #...\ndemo.queue()\ndemo.launch()\n
You can control the number of requests processed at a single time as such:
\n\ndemo.queue(concurrency_count=3)\n
See the Docs on queueing on configuring other queuing parameters.
\n\nTo specify only certain functions for queueing in Blocks:
\n\nwith gr.Blocks() as demo2:\n num1 = gr.Number()\n num2 = gr.Number()\n output = gr.Number()\n gr.Button(\"Add\").click(\n lambda a, b: a + b, [num1, num2], output)\n gr.Button(\"Multiply\").click(\n lambda a, b: a * b, [num1, num2], output, queue=True)\ndemo2.launch()\n
In some cases, you may want to stream a sequence of outputs rather than show a single output at once. For example, you might have an image generation model and you want to show the image that is generated at each step, leading up to the final image. Or you might have a chatbot which streams its response one word at a time instead of returning it all at once.
\n\nIn such cases, you can supply a generator function into Gradio instead of a regular function. Creating generators in Python is very simple: instead of a single return
value, a function should yield
a series of values instead. Usually the yield
statement is put in some kind of loop. Here's an example of an generator that simply counts up to a given number:
def my_generator(x):\n for i in range(x):\n yield i\n
You supply a generator into Gradio the same way as you would a regular function. For example, here's a a (fake) image generation model that generates noise for several steps before outputting an image:
\n\nimport gradio as gr\nimport numpy as np\nimport time\n\n# define core fn, which returns a generator {steps} times before returning the image\ndef fake_diffusion(steps):\n for _ in range(steps):\n time.sleep(1)\n image = np.random.random((600, 600, 3))\n yield image\n image = \"https://gradio-builds.s3.amazonaws.com/diffusion_image/cute_dog.jpg\"\n yield image\n\n\ndemo = gr.Interface(fake_diffusion, inputs=gr.Slider(1, 10, 3), outputs=\"image\")\n\n# define queue - required for generators\ndemo.queue()\n\ndemo.launch()\n\n
Note that we've added a time.sleep(1)
in the iterator to create an artificial pause between steps so that you are able to observe the steps of the iterator (in a real image generation model, this probably wouldn't be necessary).
Supplying a generator into Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio supports the ability to create a custom Progress Bars so that you have customizability and control over the progress update that you show to the user. In order to enable this, simply add an argument to your method that has a default value of a gr.Progress
instance. Then you can update the progress levels by calling this instance directly with a float between 0 and 1, or using the tqdm()
method of the Progress
instance to track progress over an iterable, as shown below. Queueing must be enabled for progress updates.
import gradio as gr\nimport time\n\ndef slowly_reverse(word, progress=gr.Progress()):\n progress(0, desc=\"Starting\")\n time.sleep(1)\n progress(0.05)\n new_string = \"\"\n for letter in progress.tqdm(word, desc=\"Reversing\"):\n time.sleep(0.25)\n new_string = letter + new_string\n return new_string\n\ndemo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())\n\nif __name__ == \"__main__\":\n demo.queue(concurrency_count=10).launch()\n\n
If you use the tqdm
library, you can even report progress updates automatically from any tqdm.tqdm
that already exists within your function by setting the default argument as gr.Progress(track_tqdm=True)
!
Gradio supports the ability to pass batch functions. Batch functions are just\nfunctions which take in a list of inputs and return a list of predictions.
\n\nFor example, here is a batched function that takes in two lists of inputs (a list of\nwords and a list of ints), and returns a list of trimmed words as output:
\n\nimport time\n\ndef trim_words(words, lens):\n trimmed_words = []\n time.sleep(5)\n for w, l in zip(words, lens):\n trimmed_words.append(w[:int(l)]) \n return [trimmed_words]\n
The advantage of using batched functions is that if you enable queuing, the Gradio\nserver can automatically batch incoming requests and process them in parallel,\npotentially speeding up your demo. Here's what the Gradio code looks like (notice\nthe batch=True
and max_batch_size=16
-- both of these parameters can be passed\ninto event triggers or into the Interface
class)
With Interface
:
demo = gr.Interface(trim_words, [\"textbox\", \"number\"], [\"output\"], \n batch=True, max_batch_size=16)\ndemo.queue()\ndemo.launch()\n
With Blocks
:
import gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n word = gr.Textbox(label=\"word\")\n leng = gr.Number(label=\"leng\")\n output = gr.Textbox(label=\"Output\")\n with gr.Row():\n run = gr.Button()\n\n event = run.click(trim_words, [word, leng], output, batch=True, max_batch_size=16)\n\ndemo.queue()\ndemo.launch()\n
In the example above, 16 requests could be processed in parallel (for a total inference\ntime of 5 seconds), instead of each request being processed separately (for a total\ninference time of 80 seconds). Many Hugging Face transformers
and diffusers
models\nwork very naturally with Gradio's batch mode: here's an example demo using diffusers to\ngenerate images in batches
Note: using batch functions with Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio is able to run anywhere you run Python, including local jupyter notebooks as well as collaborative notebooks, such as Google Colab. In the case of local jupyter notebooks and Google Colab notbooks, Gradio runs on a local server which you can interact with in your browser. (Note: for Google Colab, this is accomplished by service worker tunneling, which requires cookies to be enabled in your browser.) For other remote notebooks, Gradio will also run on a server, but you will need to use SSH tunneling to view the app in your local browser. Often a simpler options is to use Gradio's built-in public links, discussed in the next Guide.
\n", - "tags": [], - "spaces": [], - "url": "/guides/key-features/", - "contributor": null - }, - { - "name": "sharing-your-app", - "category": "getting-started", - "pretty_category": "Getting Started", - "guide_index": 3, - "absolute_index": 2, - "pretty_name": "Sharing Your App", - "content": "# Sharing Your App\n\nHow to share your Gradio app: \n\n1. [Sharing demos with the share parameter](#sharing-demos)\n2. [Hosting on HF Spaces](#hosting-on-hf-spaces)\n3. [Embedding hosted spaces](#embedding-hosted-spaces)\n4. [Embedding with web components](#embedding-with-web-components)\n5. [Using the API page](#api-page)\n6. [Adding authentication to the page](#authentication)\n7. [Accessing Network Requests](#accessing-the-network-request-directly)\n8. [Mounting within FastAPI](#mounting-within-another-fast-api-app)\n9. [Security](#security-and-file-access)\n\n## Sharing Demos\n\nGradio demos can be easily shared publicly by setting `share=True` in the `launch()` method. Like this:\n\n```python\ndemo.launch(share=True)\n```\n\nThis generates a public, shareable link that you can send to anybody! When you send this link, the user on the other side can try out the model in their browser. Because the processing happens on your device (as long as your device stays on!), you don't have to worry about any packaging any dependencies. A share link usually looks something like this: **XXXXX.gradio.app**. Although the link is served through a Gradio URL, we are only a proxy for your local server, and do not store any data sent through your app.\n\nKeep in mind, however, that these links are publicly accessible, meaning that anyone can use your model for prediction! Therefore, make sure not to expose any sensitive information through the functions you write, or allow any critical changes to occur on your device. If you set `share=False` (the default, except in colab notebooks), only a local link is created, which can be shared by [port-forwarding](https://www.ssh.com/ssh/tunneling/example) with specific users. \n\n![sharing](https://github.com/gradio-app/gradio/blob/main/guides/assets/sharing.svg?raw=true)\n\nShare links expire after 72 hours.\n\n## Hosting on HF Spaces\n\nIf you'd like to have a permanent link to your Gradio demo on the internet, use Hugging Face Spaces. [Hugging Face Spaces](http://huggingface.co/spaces/) provides the infrastructure to permanently host your machine learning model for free! \n\nAfter you have [created a free Hugging Face account](https://huggingface.co/join), you have three methods to deploy your Gradio app to Hugging Face Spaces:\n\n1. From terminal: run `gradio deploy` in your app directory. The CLI will gather some basic metadata and then launch your app. To update your space, you can re-run this command or enable the Github Actions option to automatically update the Spaces on `git push`.\n\n2. From your browser: Drag and drop a folder containing your Gradio model and all related files [here](https://huggingface.co/new-space).\n\n3. Connect Spaces with your Git repository and Spaces will pull the Gradio app from there. See [this guide how to host on Hugging Face Spaces](https://huggingface.co/blog/gradio-spaces) for more information. \n\n\n\nNote: Some components, like `gr.Image`, will display a \"Share\" button only on Spaces, so that users can share the generated output to the Discussions page of the Space easily. You can disable this with `show_share_button`, such as `gr.Image(show_share_button=False)`. \n\n![Image with show_share_button=True](https://github.com/gradio-app/gradio/blob/main/guides/assets/share_icon.png?raw=true)\n\n## Embedding Hosted Spaces\n\nOnce you have hosted your app on Hugging Face Spaces (or on your own server), you may want to embed the demo on a different website, such as your blog or your portfolio. Embedding an interactive demo allows people to try out the machine learning model that you have built, without needing to download or install anything \u2014 right in their browser! The best part is that you can embed interactive demos even in static websites, such as GitHub pages.\n\nThere are two ways to embed your Gradio demos. You can find quick links to both options directly on the Hugging Face Space page, in the \"Embed this Space\" dropdown option:\n\n![Embed this Space dropdown option](https://github.com/gradio-app/gradio/blob/main/guides/assets/embed_this_space.png?raw=true)\n\n### Embedding with Web Components\n\nWeb components typically offer a better experience to users than IFrames. Web components load lazily, meaning that they won't slow down the loading time of your website, and they automatically adjust their height based on the size of the Gradio app. \n\nTo embed with Web Components:\n\n1. Import the gradio JS library into into your site by adding the script below in your site (replace {GRADIO_VERSION} in the URL with the library version of Gradio you are using). \n\n```html\n\n```\n\n2. Add \n```html\nHow to share your Gradio app:
\n\nGradio demos can be easily shared publicly by setting share=True
in the launch()
method. Like this:
demo.launch(share=True)\n
This generates a public, shareable link that you can send to anybody! When you send this link, the user on the other side can try out the model in their browser. Because the processing happens on your device (as long as your device stays on!), you don't have to worry about any packaging any dependencies. A share link usually looks something like this: XXXXX.gradio.app. Although the link is served through a Gradio URL, we are only a proxy for your local server, and do not store any data sent through your app.
\n\nKeep in mind, however, that these links are publicly accessible, meaning that anyone can use your model for prediction! Therefore, make sure not to expose any sensitive information through the functions you write, or allow any critical changes to occur on your device. If you set share=False
(the default, except in colab notebooks), only a local link is created, which can be shared by port-forwarding with specific users.
Share links expire after 72 hours.
\n\nIf you'd like to have a permanent link to your Gradio demo on the internet, use Hugging Face Spaces. Hugging Face Spaces provides the infrastructure to permanently host your machine learning model for free!
\n\nAfter you have created a free Hugging Face account, you have three methods to deploy your Gradio app to Hugging Face Spaces:
\n\nFrom terminal: run gradio deploy
in your app directory. The CLI will gather some basic metadata and then launch your app. To update your space, you can re-run this command or enable the Github Actions option to automatically update the Spaces on git push
.
From your browser: Drag and drop a folder containing your Gradio model and all related files here.
Connect Spaces with your Git repository and Spaces will pull the Gradio app from there. See this guide how to host on Hugging Face Spaces for more information.
Note: Some components, like gr.Image
, will display a \"Share\" button only on Spaces, so that users can share the generated output to the Discussions page of the Space easily. You can disable this with show_share_button
, such as gr.Image(show_share_button=False)
.
sharebutton=True\" />
\n\nOnce you have hosted your app on Hugging Face Spaces (or on your own server), you may want to embed the demo on a different website, such as your blog or your portfolio. Embedding an interactive demo allows people to try out the machine learning model that you have built, without needing to download or install anything \u2014 right in their browser! The best part is that you can embed interactive demos even in static websites, such as GitHub pages.
\n\nThere are two ways to embed your Gradio demos. You can find quick links to both options directly on the Hugging Face Space page, in the \"Embed this Space\" dropdown option:
\n\n\n\nWeb components typically offer a better experience to users than IFrames. Web components load lazily, meaning that they won't slow down the loading time of your website, and they automatically adjust their height based on the size of the Gradio app.
\n\nTo embed with Web Components:
\n\n\n
\n
element where you want to place the app. Set the src=
attribute to your Space's embed URL, which you can find in the \"Embed this Space\" button. For example:
\n
You can see examples of how web components look on the Gradio landing page.
\n\nYou can also customize the appearance and behavior of your web component with attributes that you pass into the <gradio-app>
tag:
src
: as we've seen, the src
attributes links to the URL of the hosted Gradio demo that you would like to embedspace
: an optional shorthand if your Gradio demo is hosted on Hugging Face Space. Accepts a username/space_name
instead of a full URL. Example: gradio/Echocardiogram-Segmentation
. If this attribute attribute is provided, then src
does not need to be provided.control_page_title
: a boolean designating whether the html title of the page should be set to the title of the Gradio app (by default \"false\"
)initial_height
: the initial height of the web component while it is loading the Gradio app, (by default \"300px\"
). Note that the final height is set based on the size of the Gradio app.container
: whether to show the border frame and information about where the Space is hosted (by default \"true\"
)info
: whether to show just the information about where the Space is hosted underneath the embedded app (by default \"true\"
)autoscroll
: whether to autoscroll to the output when prediction has finished (by default \"false\"
)eager
: whether to load the Gradio app as soon as the page loads (by default \"false\"
)theme_mode
: whether to use the dark
, light
, or default system
theme mode (by default \"system\"
)Here's an example of how to use these attributes to create a Gradio app that does not lazy load and has an initial height of 0px.
\n\n \n
Note: While Gradio's CSS will never impact the embedding page, the embedding page can affect the style of the embedded Gradio app. Make sure that any CSS in the parent page isn't so general that it could also apply to the embedded Gradio app and cause the styling to break. Element selectors such as header { ... }
and footer { ... }
will be the most likely to cause issues.
To embed with IFrames instead (if you cannot add javascript to your website, for example), add this element:
\n\n\n
Again, you can find the src=
attribute to your Space's embed URL, which you can find in the \"Embed this Space\" button.
Note: if you use IFrames, you'll probably want to add a fixed height
attribute and set style=\"border:0;\"
to remove the boreder. In addition, if your app requires permissions such as access to the webcam or the microphone, you'll need to provide that as well using the allow
attribute.
You can use almost any Gradio app as an API! In the footer of a Gradio app like this one, you'll see a \"Use via API\" link.
\n\n\n\nThis is a page that lists the endpoints that can be used to query the Gradio app, via our supported clients: either the Python client, or the JavaScript client. For each endpoint, Gradio automatically generates the parameters and their types, as well as example inputs.
\n\nThe endpoints are automatically created when you launch a Gradio Interface
. If you are using Gradio Blocks
, you can also set up a Gradio API page, though we recommend that you explicitly name each event listener, such as
btn.click(add, [num1, num2], output, api_name=\"addition\")\n
This will add and document the endpoint /api/addition/
to the automatically generated API page. Otherwise, your API endpoints will appear as \"unnamed\" endpoints.
Note: For Gradio apps in which queueing is enabled, users can bypass the queue if they make a POST request to your API endpoint. To disable this behavior, set api_open=False
in the queue()
method. To disable the API page altogether, set show_api=False
in .launch()
.
You may wish to put an authentication page in front of your app to limit who can open your app. With the auth=
keyword argument in the launch()
method, you can provide a tuple with a username and password, or a list of acceptable username/password tuples; Here's an example that provides password-based authentication for a single user named \"admin\":
demo.launch(auth=(\"admin\", \"pass1234\"))\n
For more complex authentication handling, you can even pass a function that takes a username and password as arguments, and returns True to allow authentication, False otherwise. This can be used for, among other things, making requests to 3rd-party authentication services.
\n\nHere's an example of a function that accepts any login where the username and password are the same:
\n\ndef same_auth(username, password):\n return username == password\ndemo.launch(auth=same_auth)\n
For authentication to work properly, third party cookies must be enabled in your browser.\nThis is not the case by default for Safari, Chrome Incognito Mode.
\n\nWhen a user makes a prediction to your app, you may need the underlying network request, in order to get the request headers (e.g. for advanced authentication), log the client's IP address, or for other reasons. Gradio supports this in a similar manner to FastAPI: simply add a function parameter whose type hint is gr.Request
and Gradio will pass in the network request as that parameter. Here is an example:
import gradio as gr\n\ndef echo(name, request: gr.Request):\n if request:\n print(\"Request headers dictionary:\", request.headers)\n print(\"IP address:\", request.client.host)\n return name\n\nio = gr.Interface(echo, \"textbox\", \"textbox\").launch()\n
Note: if your function is called directly instead of through the UI (this happens, for \nexample, when examples are cached), then request
will be None
. You should handle\nthis case explicitly to ensure that your app does not throw any errors. That is why\nwe have the explicit check if request
.
In some cases, you might have an existing FastAPI app, and you'd like to add a path for a Gradio demo.\nYou can easily do this with gradio.mount_gradio_app()
.
Here's a complete example:
\n\nfrom fastapi import FastAPI\nimport gradio as gr\n\nCUSTOM_PATH = \"/gradio\"\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_main():\n return {\"message\": \"This is your main app\"}\n\n\nio = gr.Interface(lambda x: \"Hello, \" + x + \"!\", \"textbox\", \"textbox\")\napp = gr.mount_gradio_app(app, io, path=CUSTOM_PATH)\n\n\n# Run this from the terminal as you would normally start a FastAPI app: `uvicorn run:app`\n# and navigate to http://localhost:8000/gradio in your browser.\n\n
Note that this approach also allows you run your Gradio apps on custom paths (http://localhost:8000/gradio
in the example above).
Sharing your Gradio app with others (by hosting it on Spaces, on your own server, or through temporary share links) exposes certain files on the host machine to users of your Gradio app.
\n\nIn particular, Gradio apps ALLOW users to access to three kinds of files:
\n\nFiles in the same directory (or a subdirectory) of where the Gradio script is launched from. For example, if the path to your gradio scripts is /home/usr/scripts/project/app.py
and you launch it from /home/usr/scripts/project/
, then users of your shared Gradio app will be able to access any files inside /home/usr/scripts/project/
. This is done so that you can easily reference these files in your Gradio app (e.g. for your app's examples
).
Temporary files created by Gradio. These are files that are created by Gradio as part of running your prediction function. For example, if your prediction function returns a video file, then Gradio will save that video to a temporary file and then send the path to the temporary file to the front end. You can customize the location of temporary files created by Gradio by setting the environment variable GRADIO_TEMP_DIR
to an absolute path, such as /home/usr/scripts/project/temp/
.
Files that you explicitly allow via the allowed_paths
parameter in launch()
. This parameter allows you to pass in a list of additional directories or exact filepaths you'd like to allow users to have access to. (By default, this parameter is an empty list).
Gradio DOES NOT ALLOW access to:
\n\nDotfiles (any files whose name begins with '.'
) or any files that are contained in any directory whose name begins with '.'
Files that you explicitly allow via the blocked_paths
parameter in launch()
. You can pass in a list of additional directories or exact filepaths to the blocked_paths
parameter in launch()
. This parameter takes precedence over the files that Gradio exposes by default or by the allowed_paths
.
Any other paths on the host machine. Users should NOT be able to access other arbitrary paths on the host.
Please make sure you are running the latest version of gradio
for these security settings to apply.
This guide covers how State is handled in Gradio. Learn the difference between Global and Session states, and how to use both.
\n\nYour function may use data that persists beyond a single function call. If the data is something accessible to all function calls and all users, you can create a variable outside the function call and access it inside the function. For example, you may load a large model outside the function and use it inside the function so that every function call does not need to reload the model.
\n\nimport gradio as gr\n\nscores = []\n\ndef track_score(score):\n scores.append(score)\n top_scores = sorted(scores, reverse=True)[:3]\n return top_scores\n\ndemo = gr.Interface(\n track_score, \n gr.Number(label=\"Score\"), \n gr.JSON(label=\"Top Scores\")\n)\ndemo.launch()\n
In the code above, the scores
array is shared between all users. If multiple users are accessing this demo, their scores will all be added to the same list, and the returned top 3 scores will be collected from this shared reference.
Another type of data persistence Gradio supports is session state, where data persists across multiple submits within a page session. However, data is not shared between different users of your model. To store data in a session state, you need to do three things:
\n\n'state'
input and 'state'
output components when creating your Interface
A chatbot is an example where you would need session state - you want access to a users previous submissions, but you cannot store chat history in a global variable, because then chat history would get jumbled between different users.
\n\nimport gradio as gr\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\nimport torch\n\ntokenizer = AutoTokenizer.from_pretrained(\"microsoft/DialoGPT-medium\")\nmodel = AutoModelForCausalLM.from_pretrained(\"microsoft/DialoGPT-medium\")\n\n\ndef user(message, history):\n return \"\", history + [[message, None]]\n\n\ndef bot(history):\n user_message = history[-1][0]\n new_user_input_ids = tokenizer.encode(\n user_message + tokenizer.eos_token, return_tensors=\"pt\"\n )\n\n # append the new user input tokens to the chat history\n bot_input_ids = torch.cat([torch.LongTensor([]), new_user_input_ids], dim=-1)\n\n # generate a response\n response = model.generate(\n bot_input_ids, max_length=1000, pad_token_id=tokenizer.eos_token_id\n ).tolist()\n\n # convert the tokens to text, and then split the responses into lines\n response = tokenizer.decode(response[0]).split(\"<|endoftext|>\")\n response = [\n (response[i], response[i + 1]) for i in range(0, len(response) - 1, 2)\n ] # convert to tuples of list\n history[-1] = response[0]\n return history\n\n\nwith gr.Blocks() as demo:\n chatbot = gr.Chatbot()\n msg = gr.Textbox()\n clear = gr.Button(\"Clear\")\n\n msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(\n bot, chatbot, chatbot\n )\n clear.click(lambda: None, None, chatbot, queue=False)\n\ndemo.launch()\n\n
Notice how the state persists across submits within each page, but if you load this demo in another tab (or refresh the page), the demos will not share chat history.
\n\nThe default value of state
is None. If you pass a default value to the state parameter of the function, it is used as the default value of the state instead. The Interface
class only supports a single input and outputs state variable, though it can be a list with multiple elements. For more complex use cases, you can use Blocks, which supports multiple State
variables.
This guide covers how to get Gradio interfaces to refresh automatically or continuously stream data.
\n\nYou can make interfaces automatically refresh by setting live=True
in the interface. Now the interface will recalculate as soon as the user input changes.
import gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\",\n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n live=True,\n)\ndemo.launch()\n\n
Note there is no submit button, because the interface resubmits automatically on change.
\n\nSome components have a \"streaming\" mode, such as Audio
component in microphone mode, or the Image
component in webcam mode. Streaming means data is sent continuously to the backend and the Interface
function is continuously being rerun.
The difference between gr.Audio(source='microphone')
and gr.Audio(source='microphone', streaming=True)
, when both are used in gr.Interface(live=True)
, is that the first Component
will automatically submit data and run the Interface
function when the user stops recording, whereas the second Component
will continuously send data and run the Interface
function during recording.
Here is example code of streaming images from the webcam.
\n\nimport gradio as gr\nimport numpy as np\n\ndef flip(im):\n return np.flipud(im)\n\ndemo = gr.Interface(\n flip, \n gr.Image(source=\"webcam\", streaming=True), \n \"image\",\n live=True\n)\ndemo.launch()\n\n
There's more to cover on the Interface class. This guide covers all the advanced features: Using Interpretation, custom styling, loading from the Hugging Face Hub, and using Parallel and Series.
\n\nMost models are black boxes such that the internal logic of the function is hidden from the end user. To encourage transparency, we've made it very easy to add interpretation to your model by simply setting the interpretation
keyword in the Interface
class to default
. This allows your users to understand what parts of the input are responsible for the output. Take a look at the simple interface below which shows an image classifier that also includes interpretation:
import requests\nimport tensorflow as tf\n\nimport gradio as gr\n\ninception_net = tf.keras.applications.MobileNetV2() # load the model\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n return {labels[i]: float(prediction[i]) for i in range(1000)}\n\n\nimage = gr.Image(shape=(224, 224))\nlabel = gr.Label(num_top_classes=3)\n\ndemo = gr.Interface(\n fn=classify_image, inputs=image, outputs=label, interpretation=\"default\"\n)\n\ndemo.launch()\n\n
In addition to default
, Gradio also includes Shapley-based interpretation, which provides more accurate interpretations, albeit usually with a slower runtime. To use this, simply set the interpretation
parameter to \"shap\"
(note: also make sure the python package shap
is installed). Optionally, you can modify the num_shap
parameter, which controls the tradeoff between accuracy and runtime (increasing this value generally increases accuracy). Here is an example:
gr.Interface(fn=classify_image,\n inputs=image, \n outputs=label, \n interpretation=\"shap\", \n num_shap=5).launch()\n
This will work for any function, even if internally, the model is a complex neural network or some other black box. If you use Gradio's default
or shap
interpretation, the output component must be a Label
. All common input components are supported. Here is an example with text input.
import gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=\"default\",\n)\n\ndemo.launch()\n\n
So what is happening under the hood? With these interpretation methods, Gradio runs the prediction multiple times with modified versions of the input. Based on the results, you'll see that the interface automatically highlights the parts of the text (or image, etc.) that contributed increased the likelihood of the class as red. The intensity of color corresponds to the importance of that part of the input. The parts that decrease the class confidence are highlighted blue.
\n\nYou can also write your own interpretation function. The demo below adds custom interpretation to the previous demo. This function will take the same inputs as the main wrapped function. The output of this interpretation function will be used to highlight the input of each input component - therefore the function must return a list where the number of elements corresponds to the number of input components. To see the format for interpretation for each input component, check the Docs.
\n\nimport re\n\nimport gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\n# Number of arguments to interpretation function must\n# match number of inputs to prediction function\ndef interpret_gender(sentence):\n result = gender_of_sentence(sentence)\n is_male = result[\"male\"] > result[\"female\"]\n interpretation = []\n for word in re.split(\"( )\", sentence):\n score = 0\n token = word.lower()\n if (is_male and token in male_words) or (not is_male and token in female_words):\n score = 1\n elif (is_male and token in female_words) or (\n not is_male and token in male_words\n ):\n score = -1\n interpretation.append((word, score))\n # Output must be a list of lists containing the same number of elements as inputs\n # Each element corresponds to the interpretation scores for the given input\n return [interpretation]\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=interpret_gender,\n)\n\ndemo.launch()\n\n
Learn more about Interpretation in the docs.
\n\nIf you'd like to have more fine-grained control over any aspect of your demo, you can also write your own css or pass in a filepath to a css file, with the css
parameter of the Interface
class.
gr.Interface(..., css=\"body {background-color: red}\")\n
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with \"file=\"
, for example:
gr.Interface(..., css=\"body {background-image: url('file=clouds.jpg')}\")\n
Warning: Custom CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using custom CSS sparingly and instead using Themes whenever possible.
\n\nGradio integrates nicely with the Hugging Face Hub, allowing you to load models and Spaces with just one line of code. To use this, simply use the load()
method in the Interface
class. So:
\"model/\"
or \"huggingface/\"
followed by the model name, like these examples:gr.Interface.load(\"huggingface/gpt2\").launch();\n
gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\", \n inputs=gr.Textbox(lines=5, label=\"Input Text\") # customizes the input component\n).launch()\n
\"spaces/\"
followed by the model name:gr.Interface.load(\"spaces/eugenesiow/remove-bg\", \n inputs=\"webcam\", \n title=\"Remove your webcam background!\").launch()\n
One of the great things about loading Hugging Face models or spaces using Gradio is that you can then immediately use the resulting Interface
object just like function in your Python code (this works for every type of model/space: text, images, audio, video, and even multimodal models):
io = gr.Interface.load(\"models/EleutherAI/gpt-neo-2.7B\")\nio(\"It was the best of times\") # outputs model completion\n
Gradio also lets you mix interfaces very easily using the gradio.Parallel
and gradio.Series
classes. Parallel
lets you put two similar models (if they have the same input type) in parallel to compare model predictions:
generator1 = gr.Interface.load(\"huggingface/gpt2\")\ngenerator2 = gr.Interface.load(\"huggingface/EleutherAI/gpt-neo-2.7B\")\ngenerator3 = gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\")\n\ngr.Parallel(generator1, generator2, generator3).launch()\n
Series
lets you put models and spaces in series, piping the output of one model into the input of the next model.
generator = gr.Interface.load(\"huggingface/gpt2\")\ntranslator = gr.Interface.load(\"huggingface/t5-small\")\n\ngr.Series(generator, translator).launch() \n# this demo generates text, then translates it to German, and outputs the final result.\n
And of course, you can also mix Parallel
and Series
together whenever that makes sense!
Learn more about Parallel and Series in the docs.
\n", - "tags": [], - "spaces": [], - "url": "/guides/advanced-interface-features/", - "contributor": null - } - ], - "parent": "gradio" - }, - "tabbedinterface": { - "class": null, - "name": "TabbedInterface", - "description": "A TabbedInterface is created by providing a list of Interfaces, each of which gets rendered in a separate tab.", - "tags": { "demos": "stt_or_tts" }, - "parameters": [ - { - "name": "self", - "annotation": "There's more to cover on the Interface class. This guide covers all the advanced features: Using Interpretation, custom styling, loading from the Hugging Face Hub, and using Parallel and Series.
\n\nMost models are black boxes such that the internal logic of the function is hidden from the end user. To encourage transparency, we've made it very easy to add interpretation to your model by simply setting the interpretation
keyword in the Interface
class to default
. This allows your users to understand what parts of the input are responsible for the output. Take a look at the simple interface below which shows an image classifier that also includes interpretation:
import requests\nimport tensorflow as tf\n\nimport gradio as gr\n\ninception_net = tf.keras.applications.MobileNetV2() # load the model\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n return {labels[i]: float(prediction[i]) for i in range(1000)}\n\n\nimage = gr.Image(shape=(224, 224))\nlabel = gr.Label(num_top_classes=3)\n\ndemo = gr.Interface(\n fn=classify_image, inputs=image, outputs=label, interpretation=\"default\"\n)\n\ndemo.launch()\n\n
In addition to default
, Gradio also includes Shapley-based interpretation, which provides more accurate interpretations, albeit usually with a slower runtime. To use this, simply set the interpretation
parameter to \"shap\"
(note: also make sure the python package shap
is installed). Optionally, you can modify the num_shap
parameter, which controls the tradeoff between accuracy and runtime (increasing this value generally increases accuracy). Here is an example:
gr.Interface(fn=classify_image,\n inputs=image, \n outputs=label, \n interpretation=\"shap\", \n num_shap=5).launch()\n
This will work for any function, even if internally, the model is a complex neural network or some other black box. If you use Gradio's default
or shap
interpretation, the output component must be a Label
. All common input components are supported. Here is an example with text input.
import gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=\"default\",\n)\n\ndemo.launch()\n\n
So what is happening under the hood? With these interpretation methods, Gradio runs the prediction multiple times with modified versions of the input. Based on the results, you'll see that the interface automatically highlights the parts of the text (or image, etc.) that contributed increased the likelihood of the class as red. The intensity of color corresponds to the importance of that part of the input. The parts that decrease the class confidence are highlighted blue.
\n\nYou can also write your own interpretation function. The demo below adds custom interpretation to the previous demo. This function will take the same inputs as the main wrapped function. The output of this interpretation function will be used to highlight the input of each input component - therefore the function must return a list where the number of elements corresponds to the number of input components. To see the format for interpretation for each input component, check the Docs.
\n\nimport re\n\nimport gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\n# Number of arguments to interpretation function must\n# match number of inputs to prediction function\ndef interpret_gender(sentence):\n result = gender_of_sentence(sentence)\n is_male = result[\"male\"] > result[\"female\"]\n interpretation = []\n for word in re.split(\"( )\", sentence):\n score = 0\n token = word.lower()\n if (is_male and token in male_words) or (not is_male and token in female_words):\n score = 1\n elif (is_male and token in female_words) or (\n not is_male and token in male_words\n ):\n score = -1\n interpretation.append((word, score))\n # Output must be a list of lists containing the same number of elements as inputs\n # Each element corresponds to the interpretation scores for the given input\n return [interpretation]\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=interpret_gender,\n)\n\ndemo.launch()\n\n
Learn more about Interpretation in the docs.
\n\nIf you'd like to have more fine-grained control over any aspect of your demo, you can also write your own css or pass in a filepath to a css file, with the css
parameter of the Interface
class.
gr.Interface(..., css=\"body {background-color: red}\")\n
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with \"file=\"
, for example:
gr.Interface(..., css=\"body {background-image: url('file=clouds.jpg')}\")\n
Warning: Custom CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using custom CSS sparingly and instead using Themes whenever possible.
\n\nGradio integrates nicely with the Hugging Face Hub, allowing you to load models and Spaces with just one line of code. To use this, simply use the load()
method in the Interface
class. So:
\"model/\"
or \"huggingface/\"
followed by the model name, like these examples:gr.Interface.load(\"huggingface/gpt2\").launch();\n
gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\", \n inputs=gr.Textbox(lines=5, label=\"Input Text\") # customizes the input component\n).launch()\n
\"spaces/\"
followed by the model name:gr.Interface.load(\"spaces/eugenesiow/remove-bg\", \n inputs=\"webcam\", \n title=\"Remove your webcam background!\").launch()\n
One of the great things about loading Hugging Face models or spaces using Gradio is that you can then immediately use the resulting Interface
object just like function in your Python code (this works for every type of model/space: text, images, audio, video, and even multimodal models):
io = gr.Interface.load(\"models/EleutherAI/gpt-neo-2.7B\")\nio(\"It was the best of times\") # outputs model completion\n
Gradio also lets you mix interfaces very easily using the gradio.Parallel
and gradio.Series
classes. Parallel
lets you put two similar models (if they have the same input type) in parallel to compare model predictions:
generator1 = gr.Interface.load(\"huggingface/gpt2\")\ngenerator2 = gr.Interface.load(\"huggingface/EleutherAI/gpt-neo-2.7B\")\ngenerator3 = gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\")\n\ngr.Parallel(generator1, generator2, generator3).launch()\n
Series
lets you put models and spaces in series, piping the output of one model into the input of the next model.
generator = gr.Interface.load(\"huggingface/gpt2\")\ntranslator = gr.Interface.load(\"huggingface/t5-small\")\n\ngr.Series(generator, translator).launch() \n# this demo generates text, then translates it to German, and outputs the final result.\n
And of course, you can also mix Parallel
and Series
together whenever that makes sense!
Learn more about Parallel and Series in the docs.
\n", - "tags": [], - "spaces": [], - "url": "/guides/advanced-interface-features/", - "contributor": null - } - ], - "parent": "gradio" - }, - "series": { - "class": null, - "name": "Series", - "description": "Creates a new Interface from multiple Interfaces in series (the output of one is fed as the input to the next, and so the input and output components must agree between the interfaces).There's more to cover on the Interface class. This guide covers all the advanced features: Using Interpretation, custom styling, loading from the Hugging Face Hub, and using Parallel and Series.
\n\nMost models are black boxes such that the internal logic of the function is hidden from the end user. To encourage transparency, we've made it very easy to add interpretation to your model by simply setting the interpretation
keyword in the Interface
class to default
. This allows your users to understand what parts of the input are responsible for the output. Take a look at the simple interface below which shows an image classifier that also includes interpretation:
import requests\nimport tensorflow as tf\n\nimport gradio as gr\n\ninception_net = tf.keras.applications.MobileNetV2() # load the model\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n return {labels[i]: float(prediction[i]) for i in range(1000)}\n\n\nimage = gr.Image(shape=(224, 224))\nlabel = gr.Label(num_top_classes=3)\n\ndemo = gr.Interface(\n fn=classify_image, inputs=image, outputs=label, interpretation=\"default\"\n)\n\ndemo.launch()\n\n
In addition to default
, Gradio also includes Shapley-based interpretation, which provides more accurate interpretations, albeit usually with a slower runtime. To use this, simply set the interpretation
parameter to \"shap\"
(note: also make sure the python package shap
is installed). Optionally, you can modify the num_shap
parameter, which controls the tradeoff between accuracy and runtime (increasing this value generally increases accuracy). Here is an example:
gr.Interface(fn=classify_image,\n inputs=image, \n outputs=label, \n interpretation=\"shap\", \n num_shap=5).launch()\n
This will work for any function, even if internally, the model is a complex neural network or some other black box. If you use Gradio's default
or shap
interpretation, the output component must be a Label
. All common input components are supported. Here is an example with text input.
import gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=\"default\",\n)\n\ndemo.launch()\n\n
So what is happening under the hood? With these interpretation methods, Gradio runs the prediction multiple times with modified versions of the input. Based on the results, you'll see that the interface automatically highlights the parts of the text (or image, etc.) that contributed increased the likelihood of the class as red. The intensity of color corresponds to the importance of that part of the input. The parts that decrease the class confidence are highlighted blue.
\n\nYou can also write your own interpretation function. The demo below adds custom interpretation to the previous demo. This function will take the same inputs as the main wrapped function. The output of this interpretation function will be used to highlight the input of each input component - therefore the function must return a list where the number of elements corresponds to the number of input components. To see the format for interpretation for each input component, check the Docs.
\n\nimport re\n\nimport gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\n# Number of arguments to interpretation function must\n# match number of inputs to prediction function\ndef interpret_gender(sentence):\n result = gender_of_sentence(sentence)\n is_male = result[\"male\"] > result[\"female\"]\n interpretation = []\n for word in re.split(\"( )\", sentence):\n score = 0\n token = word.lower()\n if (is_male and token in male_words) or (not is_male and token in female_words):\n score = 1\n elif (is_male and token in female_words) or (\n not is_male and token in male_words\n ):\n score = -1\n interpretation.append((word, score))\n # Output must be a list of lists containing the same number of elements as inputs\n # Each element corresponds to the interpretation scores for the given input\n return [interpretation]\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=interpret_gender,\n)\n\ndemo.launch()\n\n
Learn more about Interpretation in the docs.
\n\nIf you'd like to have more fine-grained control over any aspect of your demo, you can also write your own css or pass in a filepath to a css file, with the css
parameter of the Interface
class.
gr.Interface(..., css=\"body {background-color: red}\")\n
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with \"file=\"
, for example:
gr.Interface(..., css=\"body {background-image: url('file=clouds.jpg')}\")\n
Warning: Custom CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using custom CSS sparingly and instead using Themes whenever possible.
\n\nGradio integrates nicely with the Hugging Face Hub, allowing you to load models and Spaces with just one line of code. To use this, simply use the load()
method in the Interface
class. So:
\"model/\"
or \"huggingface/\"
followed by the model name, like these examples:gr.Interface.load(\"huggingface/gpt2\").launch();\n
gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\", \n inputs=gr.Textbox(lines=5, label=\"Input Text\") # customizes the input component\n).launch()\n
\"spaces/\"
followed by the model name:gr.Interface.load(\"spaces/eugenesiow/remove-bg\", \n inputs=\"webcam\", \n title=\"Remove your webcam background!\").launch()\n
One of the great things about loading Hugging Face models or spaces using Gradio is that you can then immediately use the resulting Interface
object just like function in your Python code (this works for every type of model/space: text, images, audio, video, and even multimodal models):
io = gr.Interface.load(\"models/EleutherAI/gpt-neo-2.7B\")\nio(\"It was the best of times\") # outputs model completion\n
Gradio also lets you mix interfaces very easily using the gradio.Parallel
and gradio.Series
classes. Parallel
lets you put two similar models (if they have the same input type) in parallel to compare model predictions:
generator1 = gr.Interface.load(\"huggingface/gpt2\")\ngenerator2 = gr.Interface.load(\"huggingface/EleutherAI/gpt-neo-2.7B\")\ngenerator3 = gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\")\n\ngr.Parallel(generator1, generator2, generator3).launch()\n
Series
lets you put models and spaces in series, piping the output of one model into the input of the next model.
generator = gr.Interface.load(\"huggingface/gpt2\")\ntranslator = gr.Interface.load(\"huggingface/t5-small\")\n\ngr.Series(generator, translator).launch() \n# this demo generates text, then translates it to German, and outputs the final result.\n
And of course, you can also mix Parallel
and Series
together whenever that makes sense!
Learn more about Parallel and Series in the docs.
\n", - "tags": [], - "spaces": [], - "url": "/guides/advanced-interface-features/", - "contributor": null - } - ], - "parent": "gradio" - } - }, - "components": { - "annotatedimage": { - "class": null, - "name": "AnnotatedImage", - "description": "Displays a base image and colored subsections on top of that image. Subsections can take the from of rectangles (e.g. object detection) or masks (e.g. image segmentation).Automatic speech recognition (ASR), the conversion of spoken speech to text, is a very important and thriving area of machine learning. ASR algorithms run on practically every smartphone, and are becoming increasingly embedded in professional workflows, such as digital assistants for nurses and doctors. Because ASR algorithms are designed to be used directly by customers and end users, it is important to validate that they are behaving as expected when confronted with a wide variety of speech patterns (different accents, pitches, and background audio conditions).
\n\nUsing gradio
, you can easily build a demo of your ASR model and share that with a testing team, or test it yourself by speaking through the microphone on your device.
This tutorial will show how to take a pretrained speech-to-text model and deploy it with a Gradio interface. We will start with a full-context model, in which the user speaks the entire audio before the prediction runs. Then we will adapt the demo to make it streaming, meaning that the audio model will convert speech as you speak. The streaming demo that we create will look something like this (try it below or in a new tab!):
\n\n\n\nReal-time ASR is inherently stateful, meaning that the model's predictions change depending on what words the user previously spoke. So, in this tutorial, we will also cover how to use state with Gradio demos.
\n\nMake sure you have the gradio
Python package already installed. You will also need a pretrained speech recognition model. In this tutorial, we will build demos from 2 ASR libraries:
pip install transformers
and pip install torch
) pip install deepspeech==0.8.2
)Make sure you have at least one of these installed so that you can follow along the tutorial. You will also need ffmpeg
installed on your system, if you do not already have it, to process files from the microphone.
Here's how to build a real time speech recognition (ASR) app:
\n\nFirst, you will need to have an ASR model that you have either trained yourself or you will need to download a pretrained model. In this tutorial, we will start by using a pretrained ASR model from the Hugging Face model, Wav2Vec2
.
Here is the code to load Wav2Vec2
from Hugging Face transformers
.
from transformers import pipeline\n\np = pipeline(\"automatic-speech-recognition\")\n
That's it! By default, the automatic speech recognition model pipeline loads Facebook's facebook/wav2vec2-base-960h
model.
We will start by creating a full-context ASR demo, in which the user speaks the full audio before using the ASR model to run inference. This is very easy with Gradio -- we simply create a function around the pipeline
object above.
We will use gradio
's built in Audio
component, configured to take input from the user's microphone and return a filepath for the recorded audio. The output component will be a plain Textbox
.
import gradio as gr\n\ndef transcribe(audio):\n text = p(audio)[\"text\"]\n return text\n\ngr.Interface(\n fn=transcribe, \n inputs=gr.Audio(source=\"microphone\", type=\"filepath\"), \n outputs=\"text\").launch()\n
So what's happening here? The transcribe
function takes a single parameter, audio
, which is a filepath to the audio file that the user has recorded. The pipeline
object expects a filepath and converts it to text, which is returned to the frontend and displayed in a textbox.
Let's see it in action! (Record a short audio clip and then click submit, or open in a new tab):
\n\n\n\nOk great! We've built an ASR model that works well for short audio clips. However, if you are recording longer audio clips, you probably want a streaming interface, one that transcribes audio as the user speaks instead of just all-at-once at the end.
\n\nThe good news is that it's not too difficult to adapt the demo we just made to make it streaming, using the same Wav2Vec2
model.
The biggest change is that we must now introduce a state
parameter, which holds the audio that has been transcribed so far. This allows us to only the latest chunk of audio and simply append it to the audio we previously transcribed.
When adding state to a Gradio demo, you need to do a total of 3 things:
\n\nstate
parameter to the functionstate
at the end of the function\"state\"
components to the inputs
and outputs
in Interface
Here's what the code looks like:
\n\ndef transcribe(audio, state=\"\"):\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\n# Set the starting state to an empty string\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\" \n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Notice that we've also made one other change, which is that we've set live=True
. This keeps the Gradio interface running constantly, so it automatically transcribes audio without the user having to repeatedly hit the submit button.
Let's see how it does (try below or in a new tab)!
\n\n\n\nOne thing that you may notice is that the transcription quality has dropped since the chunks of audio are so small, they lack the context to properly be transcribed. A \"hacky\" fix to this is to simply increase the runtime of the transcribe()
function so that longer audio chunks are processed. We can do this by adding a time.sleep()
inside the function, as shown below (we'll see a proper fix next)
from transformers import pipeline\nimport gradio as gr\nimport time\n\np = pipeline(\"automatic-speech-recognition\")\n\ndef transcribe(audio, state=\"\"):\n time.sleep(2)\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\"\n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Try the demo below to see the difference (or open in a new tab)!
\n\n\n\nYou're not restricted to ASR models from the transformers
library -- you can use your own models or models from other libraries. The DeepSpeech
library contains models that are specifically designed to handle streaming audio data. These models perform really well with streaming data as they are able to account for previous chunks of audio data when making predictions.
Going through the DeepSpeech library is beyond the scope of this Guide (check out their excellent documentation here), but you can use Gradio very similarly with a DeepSpeech ASR model as with a Transformers ASR model.
\n\nHere's a complete example (on Linux):
\n\nFirst install the DeepSpeech library and download the pretrained models from the terminal:
\n\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.pbmm\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer\napt install libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 ffmpeg\npip install deepspeech==0.8.2\n
Then, create a similar transcribe()
function as before:
from deepspeech import Model\nimport numpy as np\n\nmodel_file_path = \"deepspeech-0.8.2-models.pbmm\"\nlm_file_path = \"deepspeech-0.8.2-models.scorer\"\nbeam_width = 100\nlm_alpha = 0.93\nlm_beta = 1.18\n\nmodel = Model(model_file_path)\nmodel.enableExternalScorer(lm_file_path)\nmodel.setScorerAlphaBeta(lm_alpha, lm_beta)\nmodel.setBeamWidth(beam_width)\n\n\ndef reformat_freq(sr, y):\n if sr not in (\n 48000,\n 16000,\n ): # Deepspeech only supports 16k, (we convert 48k -> 16k)\n raise ValueError(\"Unsupported rate\", sr)\n if sr == 48000:\n y = (\n ((y / max(np.max(y), 1)) * 32767)\n .reshape((-1, 3))\n .mean(axis=1)\n .astype(\"int16\")\n )\n sr = 16000\n return sr, y\n\n\ndef transcribe(speech, stream):\n _, y = reformat_freq(*speech)\n if stream is None:\n stream = model.createStream()\n stream.feedAudioContent(y)\n text = stream.intermediateDecode()\n return text, stream\n\n
Then, create a Gradio Interface as before (the only difference being that the return type should be numpy
instead of a filepath
to be compatible with the DeepSpeech models)
import gradio as gr\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"numpy\"), \n \"state\" \n ], \n outputs= [\n \"text\", \n \"state\"\n ], \n live=True).launch()\n
Running all of this should allow you to deploy your realtime ASR model with a nice GUI. Try it out and see how well it works for you.
\n\nAnd you're done! That's all the code you need to build a web-based GUI for your ASR model.
\n\nFun tip: you can share your ASR model instantly with others simply by setting share=True
in launch()
.
Let's go through some of the most popular features of Gradio! Here are Gradio's key features:
\n\nYou can provide example data that a user can easily load into Interface
. This can be helpful to demonstrate the types of inputs the model expects, as well as to provide a way to explore your dataset in conjunction with your model. To load example data, you can provide a nested list to the examples=
keyword argument of the Interface constructor. Each sublist within the outer list represents a data sample, and each element within the sublist represents an input for each input component. The format of example data for each component is specified in the Docs.
import gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n if num2 == 0:\n raise gr.Error(\"Cannot divide by zero!\")\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\", \n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n examples=[\n [5, \"add\", 3],\n [4, \"divide\", 2],\n [-4, \"multiply\", 2.5],\n [0, \"subtract\", 1.2],\n ],\n title=\"Toy Calculator\",\n description=\"Here's a sample toy calculator. Allows you to calculate things like $2+2=4$\",\n)\ndemo.launch()\n\n
You can load a large dataset into the examples to browse and interact with the dataset through Gradio. The examples will be automatically paginated (you can configure this through the examples_per_page
argument of Interface
).
Continue learning about examples in the More On Examples guide.
\n\nYou wish to pass custom error messages to the user. To do so, raise a gr.Error(\"custom message\")
to display an error message. If you try to divide by zero in the calculator demo above, a popup modal will display the custom error message. Learn more about Error in the docs.
You can also issue gr.Warning(\"message\")
and gr.Info(\"message\")
by having them as standalone lines in your function, which will immediately display modals while continuing the execution of your function. Queueing needs to be enabled for this to work.
Note below how the gr.Error
has to be raised, while the gr.Warning
and gr.Info
are single lines.
def start_process(name):\n gr.Info(\"Starting process\")\n if name is None:\n gr.Warning(\"Name is empty\")\n ...\n if success == False:\n raise gr.Error(\"Process failed\")\n
In the previous example, you may have noticed the title=
and description=
keyword arguments in the Interface
constructor that helps users understand your app.
There are three arguments in the Interface
constructor to specify where this content should go:
title
: which accepts text and can display it at the very top of interface, and also becomes the page title.description
: which accepts text, markdown or HTML and places it right under the title.article
: which also accepts text, markdown or HTML and places it below the interface.If you're using the Blocks
API instead, you can insert text, markdown, or HTML anywhere using the gr.Markdown(...)
or gr.HTML(...)
components, with descriptive content inside the Component
constructor.
Another useful keyword argument is label=
, which is present in every Component
. This modifies the label text at the top of each Component
. You can also add the info=
keyword argument to form elements like Textbox
or Radio
to provide further information on their usage.
gr.Number(label='Age', info='In years, must be greater than 0')\n
By default, an Interface
will have \"Flag\" button. When a user testing your Interface
sees input with interesting output, such as erroneous or unexpected model behaviour, they can flag the input for you to review. Within the directory provided by the flagging_dir=
argument to the Interface
constructor, a CSV file will log the flagged inputs. If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well.
For example, with the calculator interface shown above, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- calculator.py\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output\n5,add,7,12\n6,subtract,1.5,4.5\n
With the sepia interface shown earlier, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- sepia.py\n+-- flagged/\n| +-- logs.csv\n| +-- im/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output\nim/0.png,Output/0.png\nim/1.png,Output/1.png\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of the strings when flagging, which will be saved as an additional column to the CSV.
As you've seen, Gradio includes components that can handle a variety of different data types, such as images, audio, and video. Most components can be used both as inputs or outputs.
\n\nWhen a component is used as an input, Gradio automatically handles the preprocessing needed to convert the data from a type sent by the user's browser (such as a base64 representation of a webcam snapshot) to a form that can be accepted by your function (such as a numpy
array).
Similarly, when a component is used as an output, Gradio automatically handles the postprocessing needed to convert the data from what is returned by your function (such as a list of image paths) to a form that can be displayed in the user's browser (such as a Gallery
of images in base64 format).
You can control the preprocessing using the parameters when constructing the image component. For example, here if you instantiate the Image
component with the following parameters, it will convert the image to the PIL
type and reshape it to be (100, 100)
no matter the original size that it was submitted as:
img = gr.Image(shape=(100, 100), type=\"pil\")\n
In contrast, here we keep the original size of the image, but invert the colors before converting it to a numpy array:
\n\nimg = gr.Image(invert_colors=True, type=\"numpy\")\n
Postprocessing is a lot easier! Gradio automatically recognizes the format of the returned data (e.g. is the Image
a numpy
array or a str
filepath?) and postprocesses it into a format that can be displayed by the browser.
Take a look at the Docs to see all the preprocessing-related parameters for each Component.
\n\nGradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the theme=
kwarg to the Interface
constructor. For example:
demo = gr.Interface(..., theme=gr.themes.Monochrome())\n
Gradio comes with a set of prebuilt themes which you can load from gr.themes.*
. You can extend these themes or create your own themes from scratch - see the Theming guide for more details.
For additional styling ability, you can pass any CSS to your app using the css=
kwarg.\nThe base class for the Gradio app is gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Interface(css=\".gradio-container {background-color: red}\") as demo:\n ...\n
Some components can be additionally styled through the style()
method. For example:
img = gr.Image(\"lion.jpg\").style(height='24', rounded=False)\n
Take a look at the Docs to see all the styling options for each Component.
\n\nIf your app expects heavy traffic, use the queue()
method to control processing rate. This will queue up calls so only a certain number of requests are processed at a single time. Queueing uses websockets, which also prevent network timeouts, so you should use queueing if the inference time of your function is long (> 1min).
With Interface
:
demo = gr.Interface(...).queue()\ndemo.launch()\n
With Blocks
:
with gr.Blocks() as demo:\n #...\ndemo.queue()\ndemo.launch()\n
You can control the number of requests processed at a single time as such:
\n\ndemo.queue(concurrency_count=3)\n
See the Docs on queueing on configuring other queuing parameters.
\n\nTo specify only certain functions for queueing in Blocks:
\n\nwith gr.Blocks() as demo2:\n num1 = gr.Number()\n num2 = gr.Number()\n output = gr.Number()\n gr.Button(\"Add\").click(\n lambda a, b: a + b, [num1, num2], output)\n gr.Button(\"Multiply\").click(\n lambda a, b: a * b, [num1, num2], output, queue=True)\ndemo2.launch()\n
In some cases, you may want to stream a sequence of outputs rather than show a single output at once. For example, you might have an image generation model and you want to show the image that is generated at each step, leading up to the final image. Or you might have a chatbot which streams its response one word at a time instead of returning it all at once.
\n\nIn such cases, you can supply a generator function into Gradio instead of a regular function. Creating generators in Python is very simple: instead of a single return
value, a function should yield
a series of values instead. Usually the yield
statement is put in some kind of loop. Here's an example of an generator that simply counts up to a given number:
def my_generator(x):\n for i in range(x):\n yield i\n
You supply a generator into Gradio the same way as you would a regular function. For example, here's a a (fake) image generation model that generates noise for several steps before outputting an image:
\n\nimport gradio as gr\nimport numpy as np\nimport time\n\n# define core fn, which returns a generator {steps} times before returning the image\ndef fake_diffusion(steps):\n for _ in range(steps):\n time.sleep(1)\n image = np.random.random((600, 600, 3))\n yield image\n image = \"https://gradio-builds.s3.amazonaws.com/diffusion_image/cute_dog.jpg\"\n yield image\n\n\ndemo = gr.Interface(fake_diffusion, inputs=gr.Slider(1, 10, 3), outputs=\"image\")\n\n# define queue - required for generators\ndemo.queue()\n\ndemo.launch()\n\n
Note that we've added a time.sleep(1)
in the iterator to create an artificial pause between steps so that you are able to observe the steps of the iterator (in a real image generation model, this probably wouldn't be necessary).
Supplying a generator into Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio supports the ability to create a custom Progress Bars so that you have customizability and control over the progress update that you show to the user. In order to enable this, simply add an argument to your method that has a default value of a gr.Progress
instance. Then you can update the progress levels by calling this instance directly with a float between 0 and 1, or using the tqdm()
method of the Progress
instance to track progress over an iterable, as shown below. Queueing must be enabled for progress updates.
import gradio as gr\nimport time\n\ndef slowly_reverse(word, progress=gr.Progress()):\n progress(0, desc=\"Starting\")\n time.sleep(1)\n progress(0.05)\n new_string = \"\"\n for letter in progress.tqdm(word, desc=\"Reversing\"):\n time.sleep(0.25)\n new_string = letter + new_string\n return new_string\n\ndemo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())\n\nif __name__ == \"__main__\":\n demo.queue(concurrency_count=10).launch()\n\n
If you use the tqdm
library, you can even report progress updates automatically from any tqdm.tqdm
that already exists within your function by setting the default argument as gr.Progress(track_tqdm=True)
!
Gradio supports the ability to pass batch functions. Batch functions are just\nfunctions which take in a list of inputs and return a list of predictions.
\n\nFor example, here is a batched function that takes in two lists of inputs (a list of\nwords and a list of ints), and returns a list of trimmed words as output:
\n\nimport time\n\ndef trim_words(words, lens):\n trimmed_words = []\n time.sleep(5)\n for w, l in zip(words, lens):\n trimmed_words.append(w[:int(l)]) \n return [trimmed_words]\n
The advantage of using batched functions is that if you enable queuing, the Gradio\nserver can automatically batch incoming requests and process them in parallel,\npotentially speeding up your demo. Here's what the Gradio code looks like (notice\nthe batch=True
and max_batch_size=16
-- both of these parameters can be passed\ninto event triggers or into the Interface
class)
With Interface
:
demo = gr.Interface(trim_words, [\"textbox\", \"number\"], [\"output\"], \n batch=True, max_batch_size=16)\ndemo.queue()\ndemo.launch()\n
With Blocks
:
import gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n word = gr.Textbox(label=\"word\")\n leng = gr.Number(label=\"leng\")\n output = gr.Textbox(label=\"Output\")\n with gr.Row():\n run = gr.Button()\n\n event = run.click(trim_words, [word, leng], output, batch=True, max_batch_size=16)\n\ndemo.queue()\ndemo.launch()\n
In the example above, 16 requests could be processed in parallel (for a total inference\ntime of 5 seconds), instead of each request being processed separately (for a total\ninference time of 80 seconds). Many Hugging Face transformers
and diffusers
models\nwork very naturally with Gradio's batch mode: here's an example demo using diffusers to\ngenerate images in batches
Note: using batch functions with Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio is able to run anywhere you run Python, including local jupyter notebooks as well as collaborative notebooks, such as Google Colab. In the case of local jupyter notebooks and Google Colab notbooks, Gradio runs on a local server which you can interact with in your browser. (Note: for Google Colab, this is accomplished by service worker tunneling, which requires cookies to be enabled in your browser.) For other remote notebooks, Gradio will also run on a server, but you will need to use SSH tunneling to view the app in your local browser. Often a simpler options is to use Gradio's built-in public links, discussed in the next Guide.
\n", - "tags": [], - "spaces": [], - "url": "/guides/key-features/", - "contributor": null - } - ], - "preprocessing": "this component does *not* accept input.", - "postprocessing": "expects a valid HTML str.", - "parent": "gradio", - "prev_obj": "Gallery", - "next_obj": "HighlightedText" - }, - "highlightedtext": { - "class": null, - "name": "HighlightedText", - "description": "Displays text that contains spans that are highlighted by category or numerical value.Named-entity recognition (NER), also known as token classification or text tagging, is the task of taking a sentence and classifying every word (or \"token\") into different categories, such as names of people or names of locations, or different parts of speech.
\n\nFor example, given the sentence:
\n\n\n\n\nDoes Chicago have any Pakistani restaurants?
\n
A named-entity recognition algorithm may identify:
\n\nand so on.
\n\nUsing gradio
(specifically the HighlightedText
component), you can easily build a web demo of your NER model and share that with the rest of your team.
Here is an example of a demo that you'll be able to build:
\n\nThis tutorial will show how to take a pretrained NER model and deploy it with a Gradio interface. We will show two different ways to use the HighlightedText
component -- depending on your NER model, either of these two ways may be easier to learn!
Make sure you have the gradio
Python package already installed. You will also need a pretrained named-entity recognition model. You can use your own, while in this tutorial, we will use one from the transformers
library.
Many named-entity recognition models output a list of dictionaries. Each dictionary consists of an entity, a \"start\" index, and an \"end\" index. This is, for example, how NER models in the transformers
library operate:
from transformers import pipeline \nner_pipeline = pipeline(\"ner\")\nner_pipeline(\"Does Chicago have any Pakistani restaurants\")\n
Output:
\n\n[{'entity': 'I-LOC',\n 'score': 0.9988978,\n 'index': 2,\n 'word': 'Chicago',\n 'start': 5,\n 'end': 12},\n {'entity': 'I-MISC',\n 'score': 0.9958592,\n 'index': 5,\n 'word': 'Pakistani',\n 'start': 22,\n 'end': 31}]\n
If you have such a model, it is very easy to hook it up to Gradio's HighlightedText
component. All you need to do is pass in this list of entities, along with the original text to the model, together as dictionary, with the keys being \"entities\"
and \"text\"
respectively.
Here is a complete example:
\n\nfrom transformers import pipeline\n\nimport gradio as gr\n\nner_pipeline = pipeline(\"ner\")\n\nexamples = [\n \"Does Chicago have any stores and does Joe live here?\",\n]\n\ndef ner(text):\n output = ner_pipeline(text)\n return {\"text\": text, \"entities\": output} \n\ndemo = gr.Interface(ner,\n gr.Textbox(placeholder=\"Enter sentence here...\"), \n gr.HighlightedText(),\n examples=examples)\n\ndemo.launch()\n\n
An alternative way to pass data into the HighlightedText
component is a list of tuples. The first element of each tuple should be the word or words that are being classified into a particular entity. The second element should be the entity label (or None
if they should be unlabeled). The HighlightedText
component automatically strings together the words and labels to display the entities.
In some cases, this can be easier than the first approach. Here is a demo showing this approach using Spacy's parts-of-speech tagger:
\n\nimport gradio as gr\nimport os\nos.system('python -m spacy download en_core_web_sm')\nimport spacy\nfrom spacy import displacy\n\nnlp = spacy.load(\"en_core_web_sm\")\n\ndef text_analysis(text):\n doc = nlp(text)\n html = displacy.render(doc, style=\"dep\", page=True)\n html = (\n \"\"\n + html\n + \"\"\n )\n pos_count = {\n \"char_count\": len(text),\n \"token_count\": 0,\n }\n pos_tokens = []\n\n for token in doc:\n pos_tokens.extend([(token.text, token.pos_), (\" \", None)])\n\n return pos_tokens, pos_count, html\n\ndemo = gr.Interface(\n text_analysis,\n gr.Textbox(placeholder=\"Enter sentence here...\"),\n [\"highlight\", \"json\", \"html\"],\n examples=[\n [\"What a beautiful morning for a walk!\"],\n [\"It was the best of times, it was the worst of times.\"],\n ],\n)\n\ndemo.launch()\n\n
And you're done! That's all you need to know to build a web-based GUI for your NER model.
\n\nFun tip: you can share your NER demo instantly with others simply by setting share=True
in launch()
.
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from autonomous vehicles to medical imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained image classification model, so you should also have torch
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Resnet-18 model, as it is easily downloadable from PyTorch Hub. You can use a different pretrained model or train your own.
\n\nimport torch\n\nmodel = torch.hub.load('pytorch/vision:v0.6.0', 'resnet18', pretrained=True).eval()\n
Because we will be using the model for inference, we have called the .eval()
method.
predict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\nfrom PIL import Image\nfrom torchvision import transforms\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef predict(inp):\n inp = transforms.ToTensor()(inp).unsqueeze(0)\n with torch.no_grad():\n prediction = torch.nn.functional.softmax(model(inp)[0], dim=0)\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)} \n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a PIL
imageThen, the function converts the image to a PIL Image and then eventually a PyTorch tensor
, passes it through the model, and returns:
confidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we use Image(type=\"pil\")
which creates the component and handles the preprocessing to convert that to a PIL
image.
The output component will be a Label
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images by constructing it as Label(num_top_classes=3)
.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=predict, \n inputs=gr.Image(type=\"pil\"),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"lion.jpg\", \"cheetah.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from traffic control systems to satellite imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained Keras image classification model, so you should also have tensorflow
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Mobile Net model, as it is easily downloadable from Keras. You can use a different pretrained model or train your own.
\n\nimport tensorflow as tf\n\ninception_net = tf.keras.applications.MobileNetV2()\n
This line automatically downloads the MobileNet model and weights using the Keras library.
\n\npredict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)}\n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a numpy
arrayThen, the function adds a batch dimension, passes it through the model, and returns:
\n\nconfidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we can use the \"gradio.inputs.Image\"
class, which creates the component and handles the preprocessing to convert that to a numpy array. We will instantiate the class with a parameter that automatically preprocesses the input image to be 224 pixels by 224 pixels, which is the size that MobileNet expects.
The output component will be a \"label\"
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=classify_image, \n inputs=gr.Image(shape=(224, 224)),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"banana.jpg\", \"car.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from facial recognition to manufacturing quality control.
\n\nState-of-the-art image classifiers are based on the transformers architectures, originally popularized for NLP tasks. Such architectures are typically called vision transformers (ViT). Such models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in a single line of Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed.
First, we will need an image classification model. For this tutorial, we will use a model from the Hugging Face Model Hub. The Hub contains thousands of models covering dozens of different machine learning tasks.
\n\nExpand the Tasks category on the left sidebar and select \"Image Classification\" as our task of interest. You will then see all of the models on the Hub that are designed to classify images.
\n\nAt the time of writing, the most popular one is google/vit-base-patch16-224
, which has been trained on ImageNet images at a resolution of 224x224 pixels. We will use this model for our demo.
When using a model from the Hugging Face Hub, we do not need to define the input or output components for the demo. Similarly, we do not need to be concerned with the details of preprocessing or postprocessing. \nAll of these are automatically inferred from the model tags.
\n\nBesides the import statement, it only takes a single line of Python to load and launch the demo.
\n\nWe use the gr.Interface.load()
method and pass in the path to the model including the huggingface/
to designate that it is from the Hugging Face Hub.
import gradio as gr\n\ngr.Interface.load(\n \"huggingface/google/vit-base-patch16-224\",\n examples=[\"alligator.jpg\", \"laptop.jpg\"]).launch()\n
Notice that we have added one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples.
This produces the following interface, which you can try right here in your browser. When you input an image, it is automatically preprocessed and sent to the Hugging Face Hub API, where it is passed through the model and returned as a human-interpretable prediction. Try uploading your own image!
\n\n\n\nAnd you're done! In one line of code, you have built a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
It seems that cryptocurrencies, NFTs, and the web3 movement are all the rage these days! Digital assets are being listed on marketplaces for astounding amounts of money, and just about every celebrity is debuting their own NFT collection. While your crypto assets may be taxable, such as in Canada, today we'll explore some fun and tax-free ways to generate your own assortment of procedurally generated CryptoPunks.
\n\nGenerative Adversarial Networks, often known just as GANs, are a specific class of deep-learning models that are designed to learn from an input dataset to create (generate!) new material that is convincingly similar to elements of the original training set. Famously, the website thispersondoesnotexist.com went viral with lifelike, yet synthetic, images of people generated with a model called StyleGAN2. GANs have gained traction in the machine learning world, and are now being used to generate all sorts of images, text, and even music!
\n\nToday we'll briefly look at the high-level intuition behind GANs, and then we'll build a small demo around a pre-trained GAN to see what all the fuss is about. Here's a peek at what we're going to be putting together:
\n\n\n\nMake sure you have the gradio
Python package already installed. To use the pretrained model, also install torch
and torchvision
.
Originally proposed in Goodfellow et al. 2014, GANs are made up of neural networks which compete with the intention of outsmarting each other. One network, known as the generator, is responsible for generating images. The other network, the discriminator, receives an image at a time from the generator along with a real image from the training data set. The discriminator then has to guess: which image is the fake?
\n\nThe generator is constantly training to create images which are trickier for the discriminator to identify, while the discriminator raises the bar for the generator every time it correctly detects a fake. As the networks engage in this competitive (adversarial!) relationship, the images that get generated improve to the point where they become indistinguishable to human eyes!
\n\nFor a more in-depth look at GANs, you can take a look at this excellent post on Analytics Vidhya or this PyTorch tutorial. For now, though, we'll dive into a demo!
\n\nTo generate new images with a GAN, you only need the generator model. There are many different architectures that the generator could use, but for this demo we'll use a pretrained GAN generator model with the following architecture:
\n\nfrom torch import nn\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n
We're taking the generator from this repo by @teddykoker, where you can also see the original discriminator model structure.
\n\nAfter instantiating the model, we'll load in the weights from the Hugging Face Hub, stored at nateraw/cryptopunks-gan:
\n\nfrom huggingface_hub import hf_hub_download\nimport torch\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n
predict
functionThe predict
function is the key to making Gradio work! Whatever inputs we choose through the Gradio interface will get passed through our predict
function, which should operate on the inputs and generate outputs that we can display with Gradio output components. For GANs it's common to pass random noise into our model as the input, so we'll generate a tensor of random numbers and pass that through the model. We can then use torchvision
's save_image
function to save the output of the model as a png
file, and return the file name:
from torchvision.utils import save_image\n\ndef predict(seed):\n num_punks = 4\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
We're giving our predict
function a seed
parameter, so that we can fix the random tensor generation with a seed. We'll then be able to reproduce punks if we want to see them again by passing in the same seed.
Note! Our model needs an input tensor of dimensions 100x1x1 to do a single inference, or (BatchSize)x100x1x1 for generating a batch of images. In this demo we'll start by generating 4 punks at a time.
\n\nAt this point you can even run the code you have with predict(<SOME_NUMBER>)
, and you'll find your freshly generated punks in your file system at ./punks.png
. To make a truly interactive demo, though, we'll build out a simple interface with Gradio. Our goals here are to:
predict()
to take the seed and generate the imagesWith gr.Interface()
, we can define all of that with a single function call:
import gradio as gr\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n ],\n outputs=\"image\",\n).launch()\n
Launching the interface should present you with something like this:
\n\n\n\nGenerating 4 punks at a time is a good start, but maybe we'd like to control how many we want to make each time. Adding more inputs to our Gradio interface is as simple as adding another item to the inputs
list that we pass to gr.Interface
:
gr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10), # Adding another slider!\n ],\n outputs=\"image\",\n).launch()\n
The new input will be passed to our predict()
function, so we have to make some changes to that function to accept a new parameter:
def predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
When you relaunch your interface, you should see a second slider that'll let you control the number of punks!
\n\nYour Gradio app is pretty much good to go, but you can add a few extra things to really make it ready for the spotlight \u2728
\n\nWe can add some examples that users can easily try out by adding this to the gr.Interface
:
gr.Interface(\n # ...\n # keep everything as it is, and then add\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True) # cache_examples is optional\n
The examples
parameter takes a list of lists, where each item in the sublists is ordered in the same order that we've listed the inputs
. So in our case, [seed, num_punks]
. Give it a try!
You can also try adding a title
, description
, and article
to the gr.Interface
. Each of those parameters accepts a string, so try it out and see what happens \ud83d\udc40 article
will also accept HTML, as explored in a previous guide!
When you're all done, you may end up with something like this:
\n\n\n\nFor reference, here is our full code:
\n\nimport torch\nfrom torch import nn\nfrom huggingface_hub import hf_hub_download\nfrom torchvision.utils import save_image\nimport gradio as gr\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n\ndef predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10),\n ],\n outputs=\"image\",\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True)\n
Congratulations! You've built out your very own GAN-powered CryptoPunks generator, with a fancy Gradio interface that makes it easy for anyone to use. Now you can scour the Hub for more GANs (or train your own) and continue making even more awesome demos \ud83e\udd17
\n", - "tags": ["GAN", "IMAGE", "HUB"], - "spaces": [ - "https://huggingface.co/spaces/NimaBoscarino/cryptopunks", - "https://huggingface.co/spaces/nateraw/cryptopunks-generator" - ], - "url": "/guides/create-your-own-friends-with-a-gan/", - "contributor": "Nima Boscarino and Nate Raw" - } - ], - "preprocessing": "passes the uploaded image as a numpy.array, PIL.Image or str filepath depending on `type` -- unless `tool` is `sketch` AND source is one of `upload` or `webcam`. In these cases, a dict with keys `image` and `mask` is passed, and the format of the corresponding values depends on `type`.", - "postprocessing": "expects a numpy.array, PIL.Image or str or pathlib.Path filepath to an image and displays the image.", - "examples-format": "a str filepath to a local file that contains the image.", - "parent": "gradio", - "prev_obj": "HighlightedText", - "next_obj": "Interpretation" - }, - "interpretation": { - "class": null, - "name": "Interpretation", - "description": "Used to create an interpretation widget for a component.Prerequisite: This Guide requires you to know about Blocks and the interpretation feature of Interfaces.\nMake sure to read the Guide to Blocks first as well as the\ninterpretation section of the Advanced Interface Features Guide.
\n\nIf you have experience working with the Interface class, then you know that interpreting the prediction of your machine learning model\nis as easy as setting the interpretation
parameter to either \"default\" or \"shap\".
You may be wondering if it is possible to add the same interpretation functionality to an app built with the Blocks API.\nNot only is it possible, but the flexibility of Blocks lets you display the interpretation output in ways that are\nimpossible to do with Interfaces!
\n\nThis guide will show how to:
\n\nLet's get started!
\n\nLet's build a sentiment classification app with the Blocks API.\nThis app will take text as input and output the probability that this text expresses either negative or positive sentiment.\nWe'll have a single input Textbox
and a single output Label
component.\nBelow is the code for the app as well as the app itself.
import gradio as gr \nfrom transformers import pipeline\n\nsentiment_classifier = pipeline(\"text-classification\", return_all_scores=True)\n\ndef classifier(text):\n pred = sentiment_classifier(text)\n return {p[\"label\"]: p[\"score\"] for p in pred[0]}\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n\n classify.click(classifier, input_text, label)\ndemo.launch()\n
Our goal is to present to our users how the words in the input contribute to the model's prediction.\nThis will help our users understand how the model works and also evaluate its effectiveness.\nFor example, we should expect our model to identify the words \"happy\" and \"love\" with positive sentiment - if not it's a sign we made a mistake in training it!
\n\nFor each word in the input, we will compute a score of how much the model's prediction of positive sentiment is changed by that word.\nOnce we have those (word, score)
pairs we can use gradio to visualize them for the user.
The shap library will help us compute the (word, score)
pairs and\ngradio will take care of displaying the output to the user.
The following code computes the (word, score)
pairs:
def interpretation_function(text):\n explainer = shap.Explainer(sentiment_classifier)\n shap_values = explainer([text])\n\n # Dimensions are (batch size, text size, number of classes)\n # Since we care about positive sentiment, use index 1\n scores = list(zip(shap_values.data[0], shap_values.values[0, :, 1]))\n # Scores contains (word, score) pairs\n\n\n # Format expected by gr.components.Interpretation\n return {\"original\": text, \"interpretation\": scores}\n
Now, all we have to do is add a button that runs this function when clicked.\nTo display the interpretation, we will use gr.components.Interpretation
.\nThis will color each word in the input either red or blue.\nRed if it contributes to positive sentiment and blue if it contributes to negative sentiment.\nThis is how Interface
displays the interpretation output for text.
with gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n interpret = gr.Button(\"Interpret\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n with gr.Column():\n interpretation = gr.components.Interpretation(input_text)\n classify.click(classifier, input_text, label)\n interpret.click(interpretation_function, input_text, interpretation)\n\ndemo.launch()\n
The gr.components.Interpretation
component does a good job of showing how individual words contribute to the sentiment prediction,\nbut what if we also wanted to display the score themselves along with the words?
One way to do this would be to generate a bar plot where the words are on the horizontal axis and the bar height corresponds\nto the shap score.
\n\nWe can do this by modifying our interpretation_function
to additionally return a matplotlib bar plot.\nWe will display it with the gr.Plot
component in a separate tab.
This is how the interpretation function will look:
\n\ndef interpretation_function(text):\n explainer = shap.Explainer(sentiment_classifier)\n shap_values = explainer([text])\n # Dimensions are (batch size, text size, number of classes)\n # Since we care about positive sentiment, use index 1\n scores = list(zip(shap_values.data[0], shap_values.values[0, :, 1]))\n\n scores_desc = sorted(scores, key=lambda t: t[1])[::-1]\n\n # Filter out empty string added by shap\n scores_desc = [t for t in scores_desc if t[0] != \"\"]\n\n fig_m = plt.figure()\n\n # Select top 5 words that contribute to positive sentiment\n plt.bar(x=[s[0] for s in scores_desc[:5]],\n height=[s[1] for s in scores_desc[:5]])\n plt.title(\"Top words contributing to positive sentiment\")\n plt.ylabel(\"Shap Value\")\n plt.xlabel(\"Word\")\n return {\"original\": text, \"interpretation\": scores}, fig_m\n
And this is how the app code will look:
\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n interpret = gr.Button(\"Interpret\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n with gr.Column():\n with gr.Tabs():\n with gr.TabItem(\"Display interpretation with built-in component\"):\n interpretation = gr.components.Interpretation(input_text)\n with gr.TabItem(\"Display interpretation with plot\"):\n interpretation_plot = gr.Plot()\n\n classify.click(classifier, input_text, label)\n interpret.click(interpretation_function, input_text, [interpretation, interpretation_plot])\n\ndemo.launch()\n
You can see the demo below!
\n\nAlthough we have focused on sentiment classification so far, you can add interpretations to almost any machine learning model.\nThe output must be an gr.Image
or gr.Label
but the input can be almost anything (gr.Number
, gr.Slider
, gr.Radio
, gr.Image
).
Here is a demo built with blocks of interpretations for an image classification model:
\n\nWe did a deep dive \ud83e\udd3f into how interpretations work and how you can add them to your Blocks app.
\n\nWe also showed how the Blocks API gives you the power to control how the interpretation is visualized in your app.
\n\nAdding interpretations is a helpful way to make your users understand and gain trust in your model.\nNow you have all the tools you need to add them to all of your apps!
\n", - "tags": ["INTERPRETATION", "SENTIMENT ANALYSIS"], - "spaces": [], - "url": "/guides/custom-interpretations-with-blocks/", - "contributor": null - } - ], - "preprocessing": "this component does *not* accept input.", - "postprocessing": "expects a dict with keys \"original\" and \"interpretation\".", - "parent": "gradio", - "prev_obj": "Image", - "next_obj": "JSON" - }, - "json": { - "class": null, - "name": "JSON", - "description": "Used to display arbitrary JSON output prettily.Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from autonomous vehicles to medical imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained image classification model, so you should also have torch
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Resnet-18 model, as it is easily downloadable from PyTorch Hub. You can use a different pretrained model or train your own.
\n\nimport torch\n\nmodel = torch.hub.load('pytorch/vision:v0.6.0', 'resnet18', pretrained=True).eval()\n
Because we will be using the model for inference, we have called the .eval()
method.
predict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\nfrom PIL import Image\nfrom torchvision import transforms\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef predict(inp):\n inp = transforms.ToTensor()(inp).unsqueeze(0)\n with torch.no_grad():\n prediction = torch.nn.functional.softmax(model(inp)[0], dim=0)\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)} \n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a PIL
imageThen, the function converts the image to a PIL Image and then eventually a PyTorch tensor
, passes it through the model, and returns:
confidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we use Image(type=\"pil\")
which creates the component and handles the preprocessing to convert that to a PIL
image.
The output component will be a Label
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images by constructing it as Label(num_top_classes=3)
.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=predict, \n inputs=gr.Image(type=\"pil\"),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"lion.jpg\", \"cheetah.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from traffic control systems to satellite imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained Keras image classification model, so you should also have tensorflow
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Mobile Net model, as it is easily downloadable from Keras. You can use a different pretrained model or train your own.
\n\nimport tensorflow as tf\n\ninception_net = tf.keras.applications.MobileNetV2()\n
This line automatically downloads the MobileNet model and weights using the Keras library.
\n\npredict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)}\n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a numpy
arrayThen, the function adds a batch dimension, passes it through the model, and returns:
\n\nconfidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we can use the \"gradio.inputs.Image\"
class, which creates the component and handles the preprocessing to convert that to a numpy array. We will instantiate the class with a parameter that automatically preprocesses the input image to be 224 pixels by 224 pixels, which is the size that MobileNet expects.
The output component will be a \"label\"
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=classify_image, \n inputs=gr.Image(shape=(224, 224)),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"banana.jpg\", \"car.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from facial recognition to manufacturing quality control.
\n\nState-of-the-art image classifiers are based on the transformers architectures, originally popularized for NLP tasks. Such architectures are typically called vision transformers (ViT). Such models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in a single line of Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed.
First, we will need an image classification model. For this tutorial, we will use a model from the Hugging Face Model Hub. The Hub contains thousands of models covering dozens of different machine learning tasks.
\n\nExpand the Tasks category on the left sidebar and select \"Image Classification\" as our task of interest. You will then see all of the models on the Hub that are designed to classify images.
\n\nAt the time of writing, the most popular one is google/vit-base-patch16-224
, which has been trained on ImageNet images at a resolution of 224x224 pixels. We will use this model for our demo.
When using a model from the Hugging Face Hub, we do not need to define the input or output components for the demo. Similarly, we do not need to be concerned with the details of preprocessing or postprocessing. \nAll of these are automatically inferred from the model tags.
\n\nBesides the import statement, it only takes a single line of Python to load and launch the demo.
\n\nWe use the gr.Interface.load()
method and pass in the path to the model including the huggingface/
to designate that it is from the Hugging Face Hub.
import gradio as gr\n\ngr.Interface.load(\n \"huggingface/google/vit-base-patch16-224\",\n examples=[\"alligator.jpg\", \"laptop.jpg\"]).launch()\n
Notice that we have added one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples.
This produces the following interface, which you can try right here in your browser. When you input an image, it is automatically preprocessed and sent to the Hugging Face Hub API, where it is passed through the model and returned as a human-interpretable prediction. Try uploading your own image!
\n\n\n\nAnd you're done! In one line of code, you have built a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
How well can an algorithm guess what you're drawing? A few years ago, Google released the Quick Draw dataset, which contains drawings made by humans of a variety of every objects. Researchers have used this dataset to train models to guess Pictionary-style drawings.
\n\nSuch models are perfect to use with Gradio's sketchpad input, so in this tutorial we will build a Pictionary web application using Gradio. We will be able to build the whole web application in Python, and will look like this (try drawing something!):
\n\n\n\nLet's get started! This guide covers how to build a pictionary app (step-by-step):
\n\n\n\nMake sure you have the gradio
Python package already installed. To use the pretrained sketchpad model, also install torch
.
First, you will need a sketch recognition model. Since many researchers have already trained their own models on the Quick Draw dataset, we will use a pretrained model in this tutorial. Our model is a light 1.5 MB model trained by Nate Raw, that you can download here.
\n\nIf you are interested, here is the code that was used to train the model. We will simply load the pretrained model in PyTorch, as follows:
\n\nimport torch\nfrom torch import nn\n\nmodel = nn.Sequential(\n nn.Conv2d(1, 32, 3, padding='same'),\n nn.ReLU(),\n nn.MaxPool2d(2),\n nn.Conv2d(32, 64, 3, padding='same'),\n nn.ReLU(),\n nn.MaxPool2d(2),\n nn.Conv2d(64, 128, 3, padding='same'),\n nn.ReLU(),\n nn.MaxPool2d(2),\n nn.Flatten(),\n nn.Linear(1152, 256),\n nn.ReLU(),\n nn.Linear(256, len(LABELS)),\n)\nstate_dict = torch.load('pytorch_model.bin', map_location='cpu')\nmodel.load_state_dict(state_dict, strict=False)\nmodel.eval()\n
predict
functionNext, you will need to define a function that takes in the user input, which in this case is a sketched image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nfrom pathlib import Path\n\nLABELS = Path('class_names.txt').read_text().splitlines()\n\ndef predict(img):\n x = torch.tensor(img, dtype=torch.float32).unsqueeze(0).unsqueeze(0) / 255.\n with torch.no_grad():\n out = model(x)\n probabilities = torch.nn.functional.softmax(out[0], dim=0)\n values, indices = torch.topk(probabilities, 5)\n confidences = {LABELS[i]: v.item() for i, v in zip(indices, values)}\n return confidences\n
Let's break this down. The function takes one parameters:
\n\nimg
: the input image as a numpy
arrayThen, the function converts the image to a PyTorch tensor
, passes it through the model, and returns:
confidences
: the top five predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a sketchpad. To create a sketchpad input, we can use the convenient string shortcut, \"sketchpad\"
which creates a canvas for a user to draw on and handles the preprocessing to convert that to a numpy array.
The output component will be a \"label\"
, which displays the top labels in a nice form.
Finally, we'll add one more parameter, setting live=True
, which allows our interface to run in real time, adjusting its predictions every time a user draws on the sketchpad. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=predict, \n inputs=\"sketchpad\",\n outputs=\"label\",\n live=True).launch()\n
This produces the following interface, which you can try right here in your browser (try drawing something, like a \"snake\" or a \"laptop\"):
\n\n\n\nAnd you're done! That's all the code you need to build a Pictionary-style guessing app. Have fun and try to find some edge cases \ud83e\uddd0
\n", - "tags": ["SKETCHPAD", "LABELS", "LIVE"], - "spaces": ["https://huggingface.co/spaces/nateraw/quickdraw"], - "url": "/guides/building-a-pictionary-app/", - "contributor": null - } - ], - "preprocessing": "this component does *not* accept input.", - "postprocessing": "expects a Dict[str, float] of classes and confidences, or str with just the class or an int/float for regression outputs, or a str path to a .json file containing a json dictionary in the structure produced by Label.postprocess().", - "parent": "gradio", - "prev_obj": "JSON", - "next_obj": "LinePlot" - }, - "lineplot": { - "class": null, - "name": "LinePlot", - "description": "Create a line plot.Let's go through some of the most popular features of Gradio! Here are Gradio's key features:
\n\nYou can provide example data that a user can easily load into Interface
. This can be helpful to demonstrate the types of inputs the model expects, as well as to provide a way to explore your dataset in conjunction with your model. To load example data, you can provide a nested list to the examples=
keyword argument of the Interface constructor. Each sublist within the outer list represents a data sample, and each element within the sublist represents an input for each input component. The format of example data for each component is specified in the Docs.
import gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n if num2 == 0:\n raise gr.Error(\"Cannot divide by zero!\")\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\", \n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n examples=[\n [5, \"add\", 3],\n [4, \"divide\", 2],\n [-4, \"multiply\", 2.5],\n [0, \"subtract\", 1.2],\n ],\n title=\"Toy Calculator\",\n description=\"Here's a sample toy calculator. Allows you to calculate things like $2+2=4$\",\n)\ndemo.launch()\n\n
You can load a large dataset into the examples to browse and interact with the dataset through Gradio. The examples will be automatically paginated (you can configure this through the examples_per_page
argument of Interface
).
Continue learning about examples in the More On Examples guide.
\n\nYou wish to pass custom error messages to the user. To do so, raise a gr.Error(\"custom message\")
to display an error message. If you try to divide by zero in the calculator demo above, a popup modal will display the custom error message. Learn more about Error in the docs.
You can also issue gr.Warning(\"message\")
and gr.Info(\"message\")
by having them as standalone lines in your function, which will immediately display modals while continuing the execution of your function. Queueing needs to be enabled for this to work.
Note below how the gr.Error
has to be raised, while the gr.Warning
and gr.Info
are single lines.
def start_process(name):\n gr.Info(\"Starting process\")\n if name is None:\n gr.Warning(\"Name is empty\")\n ...\n if success == False:\n raise gr.Error(\"Process failed\")\n
In the previous example, you may have noticed the title=
and description=
keyword arguments in the Interface
constructor that helps users understand your app.
There are three arguments in the Interface
constructor to specify where this content should go:
title
: which accepts text and can display it at the very top of interface, and also becomes the page title.description
: which accepts text, markdown or HTML and places it right under the title.article
: which also accepts text, markdown or HTML and places it below the interface.If you're using the Blocks
API instead, you can insert text, markdown, or HTML anywhere using the gr.Markdown(...)
or gr.HTML(...)
components, with descriptive content inside the Component
constructor.
Another useful keyword argument is label=
, which is present in every Component
. This modifies the label text at the top of each Component
. You can also add the info=
keyword argument to form elements like Textbox
or Radio
to provide further information on their usage.
gr.Number(label='Age', info='In years, must be greater than 0')\n
By default, an Interface
will have \"Flag\" button. When a user testing your Interface
sees input with interesting output, such as erroneous or unexpected model behaviour, they can flag the input for you to review. Within the directory provided by the flagging_dir=
argument to the Interface
constructor, a CSV file will log the flagged inputs. If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well.
For example, with the calculator interface shown above, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- calculator.py\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output\n5,add,7,12\n6,subtract,1.5,4.5\n
With the sepia interface shown earlier, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- sepia.py\n+-- flagged/\n| +-- logs.csv\n| +-- im/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output\nim/0.png,Output/0.png\nim/1.png,Output/1.png\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of the strings when flagging, which will be saved as an additional column to the CSV.
As you've seen, Gradio includes components that can handle a variety of different data types, such as images, audio, and video. Most components can be used both as inputs or outputs.
\n\nWhen a component is used as an input, Gradio automatically handles the preprocessing needed to convert the data from a type sent by the user's browser (such as a base64 representation of a webcam snapshot) to a form that can be accepted by your function (such as a numpy
array).
Similarly, when a component is used as an output, Gradio automatically handles the postprocessing needed to convert the data from what is returned by your function (such as a list of image paths) to a form that can be displayed in the user's browser (such as a Gallery
of images in base64 format).
You can control the preprocessing using the parameters when constructing the image component. For example, here if you instantiate the Image
component with the following parameters, it will convert the image to the PIL
type and reshape it to be (100, 100)
no matter the original size that it was submitted as:
img = gr.Image(shape=(100, 100), type=\"pil\")\n
In contrast, here we keep the original size of the image, but invert the colors before converting it to a numpy array:
\n\nimg = gr.Image(invert_colors=True, type=\"numpy\")\n
Postprocessing is a lot easier! Gradio automatically recognizes the format of the returned data (e.g. is the Image
a numpy
array or a str
filepath?) and postprocesses it into a format that can be displayed by the browser.
Take a look at the Docs to see all the preprocessing-related parameters for each Component.
\n\nGradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the theme=
kwarg to the Interface
constructor. For example:
demo = gr.Interface(..., theme=gr.themes.Monochrome())\n
Gradio comes with a set of prebuilt themes which you can load from gr.themes.*
. You can extend these themes or create your own themes from scratch - see the Theming guide for more details.
For additional styling ability, you can pass any CSS to your app using the css=
kwarg.\nThe base class for the Gradio app is gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Interface(css=\".gradio-container {background-color: red}\") as demo:\n ...\n
Some components can be additionally styled through the style()
method. For example:
img = gr.Image(\"lion.jpg\").style(height='24', rounded=False)\n
Take a look at the Docs to see all the styling options for each Component.
\n\nIf your app expects heavy traffic, use the queue()
method to control processing rate. This will queue up calls so only a certain number of requests are processed at a single time. Queueing uses websockets, which also prevent network timeouts, so you should use queueing if the inference time of your function is long (> 1min).
With Interface
:
demo = gr.Interface(...).queue()\ndemo.launch()\n
With Blocks
:
with gr.Blocks() as demo:\n #...\ndemo.queue()\ndemo.launch()\n
You can control the number of requests processed at a single time as such:
\n\ndemo.queue(concurrency_count=3)\n
See the Docs on queueing on configuring other queuing parameters.
\n\nTo specify only certain functions for queueing in Blocks:
\n\nwith gr.Blocks() as demo2:\n num1 = gr.Number()\n num2 = gr.Number()\n output = gr.Number()\n gr.Button(\"Add\").click(\n lambda a, b: a + b, [num1, num2], output)\n gr.Button(\"Multiply\").click(\n lambda a, b: a * b, [num1, num2], output, queue=True)\ndemo2.launch()\n
In some cases, you may want to stream a sequence of outputs rather than show a single output at once. For example, you might have an image generation model and you want to show the image that is generated at each step, leading up to the final image. Or you might have a chatbot which streams its response one word at a time instead of returning it all at once.
\n\nIn such cases, you can supply a generator function into Gradio instead of a regular function. Creating generators in Python is very simple: instead of a single return
value, a function should yield
a series of values instead. Usually the yield
statement is put in some kind of loop. Here's an example of an generator that simply counts up to a given number:
def my_generator(x):\n for i in range(x):\n yield i\n
You supply a generator into Gradio the same way as you would a regular function. For example, here's a a (fake) image generation model that generates noise for several steps before outputting an image:
\n\nimport gradio as gr\nimport numpy as np\nimport time\n\n# define core fn, which returns a generator {steps} times before returning the image\ndef fake_diffusion(steps):\n for _ in range(steps):\n time.sleep(1)\n image = np.random.random((600, 600, 3))\n yield image\n image = \"https://gradio-builds.s3.amazonaws.com/diffusion_image/cute_dog.jpg\"\n yield image\n\n\ndemo = gr.Interface(fake_diffusion, inputs=gr.Slider(1, 10, 3), outputs=\"image\")\n\n# define queue - required for generators\ndemo.queue()\n\ndemo.launch()\n\n
Note that we've added a time.sleep(1)
in the iterator to create an artificial pause between steps so that you are able to observe the steps of the iterator (in a real image generation model, this probably wouldn't be necessary).
Supplying a generator into Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio supports the ability to create a custom Progress Bars so that you have customizability and control over the progress update that you show to the user. In order to enable this, simply add an argument to your method that has a default value of a gr.Progress
instance. Then you can update the progress levels by calling this instance directly with a float between 0 and 1, or using the tqdm()
method of the Progress
instance to track progress over an iterable, as shown below. Queueing must be enabled for progress updates.
import gradio as gr\nimport time\n\ndef slowly_reverse(word, progress=gr.Progress()):\n progress(0, desc=\"Starting\")\n time.sleep(1)\n progress(0.05)\n new_string = \"\"\n for letter in progress.tqdm(word, desc=\"Reversing\"):\n time.sleep(0.25)\n new_string = letter + new_string\n return new_string\n\ndemo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())\n\nif __name__ == \"__main__\":\n demo.queue(concurrency_count=10).launch()\n\n
If you use the tqdm
library, you can even report progress updates automatically from any tqdm.tqdm
that already exists within your function by setting the default argument as gr.Progress(track_tqdm=True)
!
Gradio supports the ability to pass batch functions. Batch functions are just\nfunctions which take in a list of inputs and return a list of predictions.
\n\nFor example, here is a batched function that takes in two lists of inputs (a list of\nwords and a list of ints), and returns a list of trimmed words as output:
\n\nimport time\n\ndef trim_words(words, lens):\n trimmed_words = []\n time.sleep(5)\n for w, l in zip(words, lens):\n trimmed_words.append(w[:int(l)]) \n return [trimmed_words]\n
The advantage of using batched functions is that if you enable queuing, the Gradio\nserver can automatically batch incoming requests and process them in parallel,\npotentially speeding up your demo. Here's what the Gradio code looks like (notice\nthe batch=True
and max_batch_size=16
-- both of these parameters can be passed\ninto event triggers or into the Interface
class)
With Interface
:
demo = gr.Interface(trim_words, [\"textbox\", \"number\"], [\"output\"], \n batch=True, max_batch_size=16)\ndemo.queue()\ndemo.launch()\n
With Blocks
:
import gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n word = gr.Textbox(label=\"word\")\n leng = gr.Number(label=\"leng\")\n output = gr.Textbox(label=\"Output\")\n with gr.Row():\n run = gr.Button()\n\n event = run.click(trim_words, [word, leng], output, batch=True, max_batch_size=16)\n\ndemo.queue()\ndemo.launch()\n
In the example above, 16 requests could be processed in parallel (for a total inference\ntime of 5 seconds), instead of each request being processed separately (for a total\ninference time of 80 seconds). Many Hugging Face transformers
and diffusers
models\nwork very naturally with Gradio's batch mode: here's an example demo using diffusers to\ngenerate images in batches
Note: using batch functions with Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio is able to run anywhere you run Python, including local jupyter notebooks as well as collaborative notebooks, such as Google Colab. In the case of local jupyter notebooks and Google Colab notbooks, Gradio runs on a local server which you can interact with in your browser. (Note: for Google Colab, this is accomplished by service worker tunneling, which requires cookies to be enabled in your browser.) For other remote notebooks, Gradio will also run on a server, but you will need to use SSH tunneling to view the app in your local browser. Often a simpler options is to use Gradio's built-in public links, discussed in the next Guide.
\n", - "tags": [], - "spaces": [], - "url": "/guides/key-features/", - "contributor": null - } - ], - "preprocessing": "this component does *not* accept input.", - "postprocessing": "expects a valid str that can be rendered as Markdown.", - "parent": "gradio", - "prev_obj": "LinePlot", - "next_obj": "Model3D" - }, - "model3d": { - "class": null, - "name": "Model3D", - "description": "Component allows users to upload or view 3D Model files (.obj, .glb, or .gltf).3D models are becoming more popular in machine learning and make for some of the most fun demos to experiment with. Using gradio
, you can easily build a demo of your 3D image model and share it with anyone. The Gradio 3D Model component accepts 3 file types including: .obj, .glb, & .gltf.
This guide will show you how to build a demo for your 3D image model in a few lines of code; like the one below. Play around with 3D object by clicking around, dragging and zooming:
\n\nMake sure you have the gradio
Python package already installed.
Let's take a look at how to create the minimal interface above. The prediction function in this case will just return the original 3D model mesh, but you can change this function to run inference on your machine learning model. We'll take a look at more complex examples below.
\n\nimport gradio as gr\n\ndef load_mesh(mesh_file_name):\n return mesh_file_name\n\ndemo = gr.Interface(\n fn=load_mesh,\n inputs=gr.Model3D(),\n outputs=gr.Model3D(clear_color=[0.0, 0.0, 0.0, 0.0], label=\"3D Model\"),\n examples=[\n [\"files/Bunny.obj\"],\n [\"files/Duck.glb\"],\n [\"files/Fox.gltf\"],\n [\"files/face.obj\"],\n ],\n cache_examples=True,\n)\n\ndemo.launch()\n
Let's break down the code above:
\n\nload_mesh
: This is our 'prediction' function and for simplicity, this function will take in the 3D model mesh and return it.
Creating the Interface:
\n\nfn
: the prediction function that is used when the user clicks submit. In our case this is the load_mesh
function.inputs
: create a model3D input component. The input expects an uploaded file as a {str} filepath.outputs
: create a model3D output component. The output component also expects a file as a {str} filepath.\nclear_color
: this is the background color of the 3D model canvas. Expects RGBa values.label
: the label that appears on the top left of the component.examples
: list of 3D model files. The 3D model component can accept .obj, .glb, & .gltf file types.cache_examples
: saves the predicted output for the examples, to save time on inference.Below is a demo that uses the DPT model to predict the depth of an image and then uses 3D Point Cloud to create a 3D object. Take a look at the app.py file for a peek into the code and the model prediction function.\n
Below is a demo that uses the PIFu model to convert an image of a clothed human into a 3D digitized model. Take a look at the spaces.py file for a peek into the code and the model prediction function.
\n\nAnd you're done! That's all the code you need to build an interface for your Model3D model. Here are some references that you may find useful:
\n\nThis guide explains how you can use Gradio to plot geographical data on a map using the gradio.Plot
component. The Gradio Plot
component works with Matplotlib, Bokeh and Plotly. Plotly is what we will be working with in this guide. Plotly allows developers to easily create all sorts of maps with their geographical data. Take a look here for some examples.
We will be using the New York City Airbnb dataset, which is hosted on kaggle here. I've uploaded it to the Hugging Face Hub as a dataset here for easier use and download. Using this data we will plot Airbnb locations on a map output and allow filtering based on price and location. Below is the demo that we will be building. \u26a1\ufe0f
\n\nLet's start by loading the Airbnb NYC data from the Hugging Face Hub.
\n\nfrom datasets import load_dataset\n\ndataset = load_dataset(\"gradio/NYC-Airbnb-Open-Data\", split=\"train\")\ndf = dataset.to_pandas()\n\ndef filter_map(min_price, max_price, boroughs):\n new_df = df[(df['neighbourhood_group'].isin(boroughs)) & \n (df['price'] > min_price) & (df['price'] < max_price)]\n names = new_df[\"name\"].tolist()\n prices = new_df[\"price\"].tolist()\n text_list = [(names[i], prices[i]) for i in range(0, len(names))]\n
In the code above, we first load the csv data into a pandas dataframe. Let's begin by defining a function that we will use as the prediction function for the gradio app. This function will accept the minimum price and maximum price range as well as the list of boroughs to filter the resulting map. We can use the passed in values (min_price
, max_price
, and list of boroughs
) to filter the dataframe and create new_df
. Next we will create text_list
of the names and prices of each Airbnb to use as labels on the map.
Plotly makes it easy to work with maps. Let's take a look below how we can create a map figure.
\n\nimport plotly.graph_objects as go\n\nfig = go.Figure(go.Scattermapbox(\n customdata=text_list,\n lat=new_df['latitude'].tolist(),\n lon=new_df['longitude'].tolist(),\n mode='markers',\n marker=go.scattermapbox.Marker(\n size=6\n ),\n hoverinfo=\"text\",\n hovertemplate='Name: %{customdata[0]}
Price: $%{customdata[1]}'\n ))\n\nfig.update_layout(\n mapbox_style=\"open-street-map\",\n hovermode='closest',\n mapbox=dict(\n bearing=0,\n center=go.layout.mapbox.Center(\n lat=40.67,\n lon=-73.90\n ),\n pitch=0,\n zoom=9\n ),\n)\n
Above, we create a scatter plot on mapbox by passing it our list of latitudes and longitudes to plot markers. We also pass in our custom data of names and prices for additional info to appear on every marker we hover over. Next we use update_layout
to specify other map settings such as zoom, and centering.
More info here on scatter plots using Mapbox and Plotly.
\n\nWe will use two gr.Number
components and a gr.CheckboxGroup
to allow users of our app to specify price ranges and borough locations. We will then use the gr.Plot
component as an output for our Plotly + Mapbox map we created earlier.
with gr.Blocks() as demo:\n with gr.Column():\n with gr.Row():\n min_price = gr.Number(value=250, label=\"Minimum Price\")\n max_price = gr.Number(value=1000, label=\"Maximum Price\")\n boroughs = gr.CheckboxGroup(choices=[\"Queens\", \"Brooklyn\", \"Manhattan\", \"Bronx\", \"Staten Island\"], value=[\"Queens\", \"Brooklyn\"], label=\"Select Boroughs:\")\n btn = gr.Button(value=\"Update Filter\")\n map = gr.Plot()\n demo.load(filter_map, [min_price, max_price, boroughs], map)\n btn.click(filter_map, [min_price, max_price, boroughs], map)\n
We layout these components using the gr.Column
and gr.Row
and we'll also add event triggers for when the demo first loads and when our \"Update Filter\" button is clicked in order to trigger the map to update with our new filters.
This is what the full demo code looks like:
\n\nimport gradio as gr\nimport plotly.graph_objects as go\nfrom datasets import load_dataset\n\ndataset = load_dataset(\"gradio/NYC-Airbnb-Open-Data\", split=\"train\")\ndf = dataset.to_pandas()\n\ndef filter_map(min_price, max_price, boroughs):\n\n filtered_df = df[(df['neighbourhood_group'].isin(boroughs)) & \n (df['price'] > min_price) & (df['price'] < max_price)]\n names = filtered_df[\"name\"].tolist()\n prices = filtered_df[\"price\"].tolist()\n text_list = [(names[i], prices[i]) for i in range(0, len(names))]\n fig = go.Figure(go.Scattermapbox(\n customdata=text_list,\n lat=filtered_df['latitude'].tolist(),\n lon=filtered_df['longitude'].tolist(),\n mode='markers',\n marker=go.scattermapbox.Marker(\n size=6\n ),\n hoverinfo=\"text\",\n hovertemplate='Name: %{customdata[0]}
Price: $%{customdata[1]}'\n ))\n\n fig.update_layout(\n mapbox_style=\"open-street-map\",\n hovermode='closest',\n mapbox=dict(\n bearing=0,\n center=go.layout.mapbox.Center(\n lat=40.67,\n lon=-73.90\n ),\n pitch=0,\n zoom=9\n ),\n )\n\n return fig\n\nwith gr.Blocks() as demo:\n with gr.Column():\n with gr.Row():\n min_price = gr.Number(value=250, label=\"Minimum Price\")\n max_price = gr.Number(value=1000, label=\"Maximum Price\")\n boroughs = gr.CheckboxGroup(choices=[\"Queens\", \"Brooklyn\", \"Manhattan\", \"Bronx\", \"Staten Island\"], value=[\"Queens\", \"Brooklyn\"], label=\"Select Boroughs:\")\n btn = gr.Button(value=\"Update Filter\")\n map = gr.Plot().style()\n demo.load(filter_map, [min_price, max_price, boroughs], map)\n btn.click(filter_map, [min_price, max_price, boroughs], map)\n\ndemo.launch()\n
If you run the code above, your app will start running locally.\nYou can even get a temporary shareable link by passing the share=True
parameter to launch
.
But what if you want to a permanent deployment solution?\nLet's deploy our Gradio app to the free HuggingFace Spaces platform.
\n\nIf you haven't used Spaces before, follow the previous guide here.
\n\nAnd you're all done! That's all the code you need to build a map demo.
\n\nHere's a link to the demo Map demo and complete code (on Hugging Face Spaces)
\n", - "tags": ["PLOTS", "MAPS"], - "spaces": [], - "url": "/guides/plot-component-for-maps/", - "contributor": null - } - ], - "preprocessing": "this component does *not* accept input.", - "postprocessing": "expects either a matplotlib.figure.Figure, a plotly.graph_objects._figure.Figure, or a dict corresponding to a bokeh plot (json_item format)", - "parent": "gradio", - "prev_obj": "Number", - "next_obj": "Radio" - }, - "radio": { - "class": null, - "name": "Radio", - "description": "Creates a set of radio buttons of which only one can be selected.Google BigQuery is a cloud-based service for processing very large data sets. It is a serverless and highly scalable data warehousing solution that enables users to analyze data using SQL-like queries.
\n\nIn this tutorial, we will show you how to query a BigQuery dataset in Python and display the data in a dashboard that updates in real time using gradio
. The dashboard will look like this:
We'll cover the following steps in this Guide:
\n\nWe'll be working with the New York Times' COVID dataset that is available as a public dataset on BigQuery. The dataset, named covid19_nyt.us_counties
contains the latest information about the number of confirmed cases and deaths from COVID across US counties.
Prerequisites: This Guide uses Gradio Blocks, so make your are familiar with the Blocks class.
\n\nTo use Gradio with BigQuery, you will need to obtain your BigQuery credentials and use them with the BigQuery Python client. If you already have BigQuery credentials (as a .json
file), you can skip this section. If not, you can do this for free in just a couple of minutes.
First, log in to your Google Cloud account and go to the Google Cloud Console (https://console.cloud.google.com/)
In the Cloud Console, click on the hamburger menu in the top-left corner and select \"APIs & Services\" from the menu. If you do not have an existing project, you will need to create one.
Then, click the \"+ Enabled APIs & services\" button, which allows you to enable specific services for your project. Search for \"BigQuery API\", click on it, and click the \"Enable\" button. If you see the \"Manage\" button, then the BigQuery is already enabled, and you're all set.
In the APIs & Services menu, click on the \"Credentials\" tab and then click on the \"Create credentials\" button.
In the \"Create credentials\" dialog, select \"Service account key\" as the type of credentials to create, and give it a name. Also grant the service account permissions by giving it a role such as \"BigQuery User\", which will allow you to run queries.
After selecting the service account, select the \"JSON\" key type and then click on the \"Create\" button. This will download the JSON key file containing your credentials to your computer. It will look something like this:
{\n \"type\": \"service_account\",\n \"project_id\": \"your project\",\n \"private_key_id\": \"your private key id\",\n \"private_key\": \"private key\",\n \"client_email\": \"email\",\n \"client_id\": \"client id\",\n \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n \"token_uri\": \"https://accounts.google.com/o/oauth2/token\",\n \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/email_id\"\n}\n
Once you have the credentials, you will need to use the BigQuery Python client to authenticate using your credentials. To do this, you will need to install the BigQuery Python client by running the following command in the terminal:
\n\npip install google-cloud-bigquery[pandas]\n
You'll notice that we've installed the pandas add-on, which will be helpful for processing the BigQuery dataset as a pandas dataframe. Once the client is installed, you can authenticate using your credentials by running the following code:
\n\nfrom google.cloud import bigquery\n\nclient = bigquery.Client.from_service_account_json(\"path/to/key.json\")\n
With your credentials authenticated, you can now use the BigQuery Python client to interact with your BigQuery datasets.
\n\nHere is an example of a function which queries the covid19_nyt.us_counties
dataset in BigQuery to show the top 20 counties with the most confirmed cases as of the current day:
import numpy as np\n\nQUERY = (\n 'SELECT * FROM `bigquery-public-data.covid19_nyt.us_counties` ' \n 'ORDER BY date DESC,confirmed_cases DESC '\n 'LIMIT 20')\n\ndef run_query():\n query_job = client.query(QUERY) \n query_result = query_job.result() \n df = query_result.to_dataframe()\n # Select a subset of columns \n df = df[[\"confirmed_cases\", \"deaths\", \"county\", \"state_name\"]]\n # Convert numeric columns to standard numpy types\n df = df.astype({\"deaths\": np.int64, \"confirmed_cases\": np.int64})\n return df\n
Once you have a function to query the data, you can use the gr.DataFrame
component from the Gradio library to display the results in a tabular format. This is a useful way to inspect the data and make sure that it has been queried correctly.
Here is an example of how to use the gr.DataFrame
component to display the results. By passing in the run_query
function to gr.DataFrame
, we instruct Gradio to run the function as soon as the page loads and show the results. In addition, you also pass in the keyword every
to tell the dashboard to refresh every hour (60*60 seconds).
import gradio as gr\n\nwith gr.Blocks() as demo:\n gr.DataFrame(run_query, every=60*60)\n\ndemo.queue().launch() # Run the demo using queuing\n
Perhaps you'd like to add a visualization to our dashboard. You can use the gr.ScatterPlot()
component to visualize the data in a scatter plot. This allows you to see the relationship between different variables such as case count and case deaths in the dataset and can be useful for exploring the data and gaining insights. Again, we can do this in real-time\nby passing in the every
parameter.
Here is a complete example showing how to use the gr.ScatterPlot
to visualize in addition to displaying data with the gr.DataFrame
import gradio as gr\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"# \ud83d\udc89 Covid Dashboard (Updated Hourly)\")\n with gr.Row():\n gr.DataFrame(run_query, every=60*60)\n gr.ScatterPlot(run_query, every=60*60, x=\"confirmed_cases\", \n y=\"deaths\", tooltip=\"county\", width=500, height=500)\n\ndemo.queue().launch() # Run the demo with queuing enabled\n
It seems that cryptocurrencies, NFTs, and the web3 movement are all the rage these days! Digital assets are being listed on marketplaces for astounding amounts of money, and just about every celebrity is debuting their own NFT collection. While your crypto assets may be taxable, such as in Canada, today we'll explore some fun and tax-free ways to generate your own assortment of procedurally generated CryptoPunks.
\n\nGenerative Adversarial Networks, often known just as GANs, are a specific class of deep-learning models that are designed to learn from an input dataset to create (generate!) new material that is convincingly similar to elements of the original training set. Famously, the website thispersondoesnotexist.com went viral with lifelike, yet synthetic, images of people generated with a model called StyleGAN2. GANs have gained traction in the machine learning world, and are now being used to generate all sorts of images, text, and even music!
\n\nToday we'll briefly look at the high-level intuition behind GANs, and then we'll build a small demo around a pre-trained GAN to see what all the fuss is about. Here's a peek at what we're going to be putting together:
\n\n\n\nMake sure you have the gradio
Python package already installed. To use the pretrained model, also install torch
and torchvision
.
Originally proposed in Goodfellow et al. 2014, GANs are made up of neural networks which compete with the intention of outsmarting each other. One network, known as the generator, is responsible for generating images. The other network, the discriminator, receives an image at a time from the generator along with a real image from the training data set. The discriminator then has to guess: which image is the fake?
\n\nThe generator is constantly training to create images which are trickier for the discriminator to identify, while the discriminator raises the bar for the generator every time it correctly detects a fake. As the networks engage in this competitive (adversarial!) relationship, the images that get generated improve to the point where they become indistinguishable to human eyes!
\n\nFor a more in-depth look at GANs, you can take a look at this excellent post on Analytics Vidhya or this PyTorch tutorial. For now, though, we'll dive into a demo!
\n\nTo generate new images with a GAN, you only need the generator model. There are many different architectures that the generator could use, but for this demo we'll use a pretrained GAN generator model with the following architecture:
\n\nfrom torch import nn\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n
We're taking the generator from this repo by @teddykoker, where you can also see the original discriminator model structure.
\n\nAfter instantiating the model, we'll load in the weights from the Hugging Face Hub, stored at nateraw/cryptopunks-gan:
\n\nfrom huggingface_hub import hf_hub_download\nimport torch\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n
predict
functionThe predict
function is the key to making Gradio work! Whatever inputs we choose through the Gradio interface will get passed through our predict
function, which should operate on the inputs and generate outputs that we can display with Gradio output components. For GANs it's common to pass random noise into our model as the input, so we'll generate a tensor of random numbers and pass that through the model. We can then use torchvision
's save_image
function to save the output of the model as a png
file, and return the file name:
from torchvision.utils import save_image\n\ndef predict(seed):\n num_punks = 4\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
We're giving our predict
function a seed
parameter, so that we can fix the random tensor generation with a seed. We'll then be able to reproduce punks if we want to see them again by passing in the same seed.
Note! Our model needs an input tensor of dimensions 100x1x1 to do a single inference, or (BatchSize)x100x1x1 for generating a batch of images. In this demo we'll start by generating 4 punks at a time.
\n\nAt this point you can even run the code you have with predict(<SOME_NUMBER>)
, and you'll find your freshly generated punks in your file system at ./punks.png
. To make a truly interactive demo, though, we'll build out a simple interface with Gradio. Our goals here are to:
predict()
to take the seed and generate the imagesWith gr.Interface()
, we can define all of that with a single function call:
import gradio as gr\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n ],\n outputs=\"image\",\n).launch()\n
Launching the interface should present you with something like this:
\n\n\n\nGenerating 4 punks at a time is a good start, but maybe we'd like to control how many we want to make each time. Adding more inputs to our Gradio interface is as simple as adding another item to the inputs
list that we pass to gr.Interface
:
gr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10), # Adding another slider!\n ],\n outputs=\"image\",\n).launch()\n
The new input will be passed to our predict()
function, so we have to make some changes to that function to accept a new parameter:
def predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
When you relaunch your interface, you should see a second slider that'll let you control the number of punks!
\n\nYour Gradio app is pretty much good to go, but you can add a few extra things to really make it ready for the spotlight \u2728
\n\nWe can add some examples that users can easily try out by adding this to the gr.Interface
:
gr.Interface(\n # ...\n # keep everything as it is, and then add\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True) # cache_examples is optional\n
The examples
parameter takes a list of lists, where each item in the sublists is ordered in the same order that we've listed the inputs
. So in our case, [seed, num_punks]
. Give it a try!
You can also try adding a title
, description
, and article
to the gr.Interface
. Each of those parameters accepts a string, so try it out and see what happens \ud83d\udc40 article
will also accept HTML, as explored in a previous guide!
When you're all done, you may end up with something like this:
\n\n\n\nFor reference, here is our full code:
\n\nimport torch\nfrom torch import nn\nfrom huggingface_hub import hf_hub_download\nfrom torchvision.utils import save_image\nimport gradio as gr\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n\ndef predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10),\n ],\n outputs=\"image\",\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True)\n
Congratulations! You've built out your very own GAN-powered CryptoPunks generator, with a fancy Gradio interface that makes it easy for anyone to use. Now you can scour the Hub for more GANs (or train your own) and continue making even more awesome demos \ud83e\udd17
\n", - "tags": ["GAN", "IMAGE", "HUB"], - "spaces": [ - "https://huggingface.co/spaces/NimaBoscarino/cryptopunks", - "https://huggingface.co/spaces/nateraw/cryptopunks-generator" - ], - "url": "/guides/create-your-own-friends-with-a-gan/", - "contributor": "Nima Boscarino and Nate Raw" - } - ], - "preprocessing": "passes slider value as a float into the function.", - "postprocessing": "expects an int or float returned from function and sets slider value to it as long as it is within range.", - "examples-format": "A float or int representing the slider's value.", - "parent": "gradio", - "prev_obj": "ScatterPlot", - "next_obj": "State" - }, - "state": { - "class": null, - "name": "State", - "description": "Special hidden component that stores session state across runs of the demo by the same user. The value of the State variable is cleared when the user refreshes the page.Automatic speech recognition (ASR), the conversion of spoken speech to text, is a very important and thriving area of machine learning. ASR algorithms run on practically every smartphone, and are becoming increasingly embedded in professional workflows, such as digital assistants for nurses and doctors. Because ASR algorithms are designed to be used directly by customers and end users, it is important to validate that they are behaving as expected when confronted with a wide variety of speech patterns (different accents, pitches, and background audio conditions).
\n\nUsing gradio
, you can easily build a demo of your ASR model and share that with a testing team, or test it yourself by speaking through the microphone on your device.
This tutorial will show how to take a pretrained speech-to-text model and deploy it with a Gradio interface. We will start with a full-context model, in which the user speaks the entire audio before the prediction runs. Then we will adapt the demo to make it streaming, meaning that the audio model will convert speech as you speak. The streaming demo that we create will look something like this (try it below or in a new tab!):
\n\n\n\nReal-time ASR is inherently stateful, meaning that the model's predictions change depending on what words the user previously spoke. So, in this tutorial, we will also cover how to use state with Gradio demos.
\n\nMake sure you have the gradio
Python package already installed. You will also need a pretrained speech recognition model. In this tutorial, we will build demos from 2 ASR libraries:
pip install transformers
and pip install torch
) pip install deepspeech==0.8.2
)Make sure you have at least one of these installed so that you can follow along the tutorial. You will also need ffmpeg
installed on your system, if you do not already have it, to process files from the microphone.
Here's how to build a real time speech recognition (ASR) app:
\n\nFirst, you will need to have an ASR model that you have either trained yourself or you will need to download a pretrained model. In this tutorial, we will start by using a pretrained ASR model from the Hugging Face model, Wav2Vec2
.
Here is the code to load Wav2Vec2
from Hugging Face transformers
.
from transformers import pipeline\n\np = pipeline(\"automatic-speech-recognition\")\n
That's it! By default, the automatic speech recognition model pipeline loads Facebook's facebook/wav2vec2-base-960h
model.
We will start by creating a full-context ASR demo, in which the user speaks the full audio before using the ASR model to run inference. This is very easy with Gradio -- we simply create a function around the pipeline
object above.
We will use gradio
's built in Audio
component, configured to take input from the user's microphone and return a filepath for the recorded audio. The output component will be a plain Textbox
.
import gradio as gr\n\ndef transcribe(audio):\n text = p(audio)[\"text\"]\n return text\n\ngr.Interface(\n fn=transcribe, \n inputs=gr.Audio(source=\"microphone\", type=\"filepath\"), \n outputs=\"text\").launch()\n
So what's happening here? The transcribe
function takes a single parameter, audio
, which is a filepath to the audio file that the user has recorded. The pipeline
object expects a filepath and converts it to text, which is returned to the frontend and displayed in a textbox.
Let's see it in action! (Record a short audio clip and then click submit, or open in a new tab):
\n\n\n\nOk great! We've built an ASR model that works well for short audio clips. However, if you are recording longer audio clips, you probably want a streaming interface, one that transcribes audio as the user speaks instead of just all-at-once at the end.
\n\nThe good news is that it's not too difficult to adapt the demo we just made to make it streaming, using the same Wav2Vec2
model.
The biggest change is that we must now introduce a state
parameter, which holds the audio that has been transcribed so far. This allows us to only the latest chunk of audio and simply append it to the audio we previously transcribed.
When adding state to a Gradio demo, you need to do a total of 3 things:
\n\nstate
parameter to the functionstate
at the end of the function\"state\"
components to the inputs
and outputs
in Interface
Here's what the code looks like:
\n\ndef transcribe(audio, state=\"\"):\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\n# Set the starting state to an empty string\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\" \n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Notice that we've also made one other change, which is that we've set live=True
. This keeps the Gradio interface running constantly, so it automatically transcribes audio without the user having to repeatedly hit the submit button.
Let's see how it does (try below or in a new tab)!
\n\n\n\nOne thing that you may notice is that the transcription quality has dropped since the chunks of audio are so small, they lack the context to properly be transcribed. A \"hacky\" fix to this is to simply increase the runtime of the transcribe()
function so that longer audio chunks are processed. We can do this by adding a time.sleep()
inside the function, as shown below (we'll see a proper fix next)
from transformers import pipeline\nimport gradio as gr\nimport time\n\np = pipeline(\"automatic-speech-recognition\")\n\ndef transcribe(audio, state=\"\"):\n time.sleep(2)\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\"\n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Try the demo below to see the difference (or open in a new tab)!
\n\n\n\nYou're not restricted to ASR models from the transformers
library -- you can use your own models or models from other libraries. The DeepSpeech
library contains models that are specifically designed to handle streaming audio data. These models perform really well with streaming data as they are able to account for previous chunks of audio data when making predictions.
Going through the DeepSpeech library is beyond the scope of this Guide (check out their excellent documentation here), but you can use Gradio very similarly with a DeepSpeech ASR model as with a Transformers ASR model.
\n\nHere's a complete example (on Linux):
\n\nFirst install the DeepSpeech library and download the pretrained models from the terminal:
\n\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.pbmm\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer\napt install libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 ffmpeg\npip install deepspeech==0.8.2\n
Then, create a similar transcribe()
function as before:
from deepspeech import Model\nimport numpy as np\n\nmodel_file_path = \"deepspeech-0.8.2-models.pbmm\"\nlm_file_path = \"deepspeech-0.8.2-models.scorer\"\nbeam_width = 100\nlm_alpha = 0.93\nlm_beta = 1.18\n\nmodel = Model(model_file_path)\nmodel.enableExternalScorer(lm_file_path)\nmodel.setScorerAlphaBeta(lm_alpha, lm_beta)\nmodel.setBeamWidth(beam_width)\n\n\ndef reformat_freq(sr, y):\n if sr not in (\n 48000,\n 16000,\n ): # Deepspeech only supports 16k, (we convert 48k -> 16k)\n raise ValueError(\"Unsupported rate\", sr)\n if sr == 48000:\n y = (\n ((y / max(np.max(y), 1)) * 32767)\n .reshape((-1, 3))\n .mean(axis=1)\n .astype(\"int16\")\n )\n sr = 16000\n return sr, y\n\n\ndef transcribe(speech, stream):\n _, y = reformat_freq(*speech)\n if stream is None:\n stream = model.createStream()\n stream.feedAudioContent(y)\n text = stream.intermediateDecode()\n return text, stream\n\n
Then, create a Gradio Interface as before (the only difference being that the return type should be numpy
instead of a filepath
to be compatible with the DeepSpeech models)
import gradio as gr\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"numpy\"), \n \"state\" \n ], \n outputs= [\n \"text\", \n \"state\"\n ], \n live=True).launch()\n
Running all of this should allow you to deploy your realtime ASR model with a nice GUI. Try it out and see how well it works for you.
\n\nAnd you're done! That's all the code you need to build a web-based GUI for your ASR model.
\n\nFun tip: you can share your ASR model instantly with others simply by setting share=True
in launch()
.
Automatic speech recognition (ASR), the conversion of spoken speech to text, is a very important and thriving area of machine learning. ASR algorithms run on practically every smartphone, and are becoming increasingly embedded in professional workflows, such as digital assistants for nurses and doctors. Because ASR algorithms are designed to be used directly by customers and end users, it is important to validate that they are behaving as expected when confronted with a wide variety of speech patterns (different accents, pitches, and background audio conditions).
\n\nUsing gradio
, you can easily build a demo of your ASR model and share that with a testing team, or test it yourself by speaking through the microphone on your device.
This tutorial will show how to take a pretrained speech-to-text model and deploy it with a Gradio interface. We will start with a full-context model, in which the user speaks the entire audio before the prediction runs. Then we will adapt the demo to make it streaming, meaning that the audio model will convert speech as you speak. The streaming demo that we create will look something like this (try it below or in a new tab!):
\n\n\n\nReal-time ASR is inherently stateful, meaning that the model's predictions change depending on what words the user previously spoke. So, in this tutorial, we will also cover how to use state with Gradio demos.
\n\nMake sure you have the gradio
Python package already installed. You will also need a pretrained speech recognition model. In this tutorial, we will build demos from 2 ASR libraries:
pip install transformers
and pip install torch
) pip install deepspeech==0.8.2
)Make sure you have at least one of these installed so that you can follow along the tutorial. You will also need ffmpeg
installed on your system, if you do not already have it, to process files from the microphone.
Here's how to build a real time speech recognition (ASR) app:
\n\nFirst, you will need to have an ASR model that you have either trained yourself or you will need to download a pretrained model. In this tutorial, we will start by using a pretrained ASR model from the Hugging Face model, Wav2Vec2
.
Here is the code to load Wav2Vec2
from Hugging Face transformers
.
from transformers import pipeline\n\np = pipeline(\"automatic-speech-recognition\")\n
That's it! By default, the automatic speech recognition model pipeline loads Facebook's facebook/wav2vec2-base-960h
model.
We will start by creating a full-context ASR demo, in which the user speaks the full audio before using the ASR model to run inference. This is very easy with Gradio -- we simply create a function around the pipeline
object above.
We will use gradio
's built in Audio
component, configured to take input from the user's microphone and return a filepath for the recorded audio. The output component will be a plain Textbox
.
import gradio as gr\n\ndef transcribe(audio):\n text = p(audio)[\"text\"]\n return text\n\ngr.Interface(\n fn=transcribe, \n inputs=gr.Audio(source=\"microphone\", type=\"filepath\"), \n outputs=\"text\").launch()\n
So what's happening here? The transcribe
function takes a single parameter, audio
, which is a filepath to the audio file that the user has recorded. The pipeline
object expects a filepath and converts it to text, which is returned to the frontend and displayed in a textbox.
Let's see it in action! (Record a short audio clip and then click submit, or open in a new tab):
\n\n\n\nOk great! We've built an ASR model that works well for short audio clips. However, if you are recording longer audio clips, you probably want a streaming interface, one that transcribes audio as the user speaks instead of just all-at-once at the end.
\n\nThe good news is that it's not too difficult to adapt the demo we just made to make it streaming, using the same Wav2Vec2
model.
The biggest change is that we must now introduce a state
parameter, which holds the audio that has been transcribed so far. This allows us to only the latest chunk of audio and simply append it to the audio we previously transcribed.
When adding state to a Gradio demo, you need to do a total of 3 things:
\n\nstate
parameter to the functionstate
at the end of the function\"state\"
components to the inputs
and outputs
in Interface
Here's what the code looks like:
\n\ndef transcribe(audio, state=\"\"):\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\n# Set the starting state to an empty string\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\" \n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Notice that we've also made one other change, which is that we've set live=True
. This keeps the Gradio interface running constantly, so it automatically transcribes audio without the user having to repeatedly hit the submit button.
Let's see how it does (try below or in a new tab)!
\n\n\n\nOne thing that you may notice is that the transcription quality has dropped since the chunks of audio are so small, they lack the context to properly be transcribed. A \"hacky\" fix to this is to simply increase the runtime of the transcribe()
function so that longer audio chunks are processed. We can do this by adding a time.sleep()
inside the function, as shown below (we'll see a proper fix next)
from transformers import pipeline\nimport gradio as gr\nimport time\n\np = pipeline(\"automatic-speech-recognition\")\n\ndef transcribe(audio, state=\"\"):\n time.sleep(2)\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\"\n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Try the demo below to see the difference (or open in a new tab)!
\n\n\n\nYou're not restricted to ASR models from the transformers
library -- you can use your own models or models from other libraries. The DeepSpeech
library contains models that are specifically designed to handle streaming audio data. These models perform really well with streaming data as they are able to account for previous chunks of audio data when making predictions.
Going through the DeepSpeech library is beyond the scope of this Guide (check out their excellent documentation here), but you can use Gradio very similarly with a DeepSpeech ASR model as with a Transformers ASR model.
\n\nHere's a complete example (on Linux):
\n\nFirst install the DeepSpeech library and download the pretrained models from the terminal:
\n\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.pbmm\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer\napt install libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 ffmpeg\npip install deepspeech==0.8.2\n
Then, create a similar transcribe()
function as before:
from deepspeech import Model\nimport numpy as np\n\nmodel_file_path = \"deepspeech-0.8.2-models.pbmm\"\nlm_file_path = \"deepspeech-0.8.2-models.scorer\"\nbeam_width = 100\nlm_alpha = 0.93\nlm_beta = 1.18\n\nmodel = Model(model_file_path)\nmodel.enableExternalScorer(lm_file_path)\nmodel.setScorerAlphaBeta(lm_alpha, lm_beta)\nmodel.setBeamWidth(beam_width)\n\n\ndef reformat_freq(sr, y):\n if sr not in (\n 48000,\n 16000,\n ): # Deepspeech only supports 16k, (we convert 48k -> 16k)\n raise ValueError(\"Unsupported rate\", sr)\n if sr == 48000:\n y = (\n ((y / max(np.max(y), 1)) * 32767)\n .reshape((-1, 3))\n .mean(axis=1)\n .astype(\"int16\")\n )\n sr = 16000\n return sr, y\n\n\ndef transcribe(speech, stream):\n _, y = reformat_freq(*speech)\n if stream is None:\n stream = model.createStream()\n stream.feedAudioContent(y)\n text = stream.intermediateDecode()\n return text, stream\n\n
Then, create a Gradio Interface as before (the only difference being that the return type should be numpy
instead of a filepath
to be compatible with the DeepSpeech models)
import gradio as gr\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"numpy\"), \n \"state\" \n ], \n outputs= [\n \"text\", \n \"state\"\n ], \n live=True).launch()\n
Running all of this should allow you to deploy your realtime ASR model with a nice GUI. Try it out and see how well it works for you.
\n\nAnd you're done! That's all the code you need to build a web-based GUI for your ASR model.
\n\nFun tip: you can share your ASR model instantly with others simply by setting share=True
in launch()
.
The Hugging Face Hub is a central platform that has over 190,000 models, 32,000 datasets and 40,000 demos, also known as Spaces. Although Hugging Face is famous for its \ud83e\udd17 transformers and diffusers libraries, the Hub also supports dozens of ML libraries, such as PyTorch, TensorFlow, spaCy, and many others across a variety of domains, from computer vision to reinforcement learning.
\n\nGradio has multiple features that make it extremely easy to leverage existing models and Spaces on the Hub. This guide walks through these features.
\n\npipeline
First, let's build a simple interface that translates text from English to Spanish. Between the over a thousand models shared by the University of Helsinki, there is an existing model, opus-mt-en-es
, that does precisely this!
The \ud83e\udd17 transformers library has a very easy-to-use abstraction, pipeline()
that handles most of the complex code to offer a simple API for common tasks. By specifying the task and an (optional) model, you can use an existing model with few lines:
import gradio as gr\n\nfrom transformers import pipeline\n\npipe = pipeline(\"translation\", model=\"Helsinki-NLP/opus-mt-en-es\")\n\ndef predict(text):\n return pipe(text)[0][\"translation_text\"]\n\ndemo = gr.Interface(\n fn=predict, \n inputs='text',\n outputs='text',\n)\n\ndemo.launch()\n
But gradio
actually makes it even easier to convert a pipeline
to a demo, simply by using the gradio.Interface.from_pipeline
methods, which skips the need to specify the input and output components:
from transformers import pipeline\nimport gradio as gr\n\npipe = pipeline(\"translation\", model=\"Helsinki-NLP/opus-mt-en-es\")\n\ndemo = gr.Interface.from_pipeline(pipe)\ndemo.launch()\n
The previous code produces the following interface, which you can try right here in your browser:
\n\nHugging Face has a free service called the Inference API, which allows you to send HTTP requests to models in the Hub. For transformers or diffusers-based models, the API can be 2 to 10 times faster than running the inference yourself. The API is free (rate limited), and you can switch to dedicated Inference Endpoints when you want to use it in production.
\n\nLet's try the same demo as above but using the Inference API instead of loading the model yourself. Given a Hugging Face model supported in the Inference API, Gradio can automatically infer the expected input and output and make the underlying server calls, so you don't have to worry about defining the prediction function. Here is what the code would look like!
\n\nimport gradio as gr\n\ndemo = gr.load(\"Helsinki-NLP/opus-mt-en-es\", src=\"models\")\n\ndemo.launch()\n
Notice that we just put specify the model name and state that the src
should be models
(Hugging Face's Model Hub). There is no need to install any dependencies (except gradio
) since you are not loading the model on your computer.
You might notice that the first inference takes about 20 seconds. This happens since the Inference API is loading the model in the server. You get some benefits afterward:
\n\nHugging Face Spaces allows anyone to host their Gradio demos freely, and uploading your Gradio demos take a couple of minutes. You can head to hf.co/new-space, select the Gradio SDK, create an app.py
file, and voila! You have a demo you can share with anyone else. To learn more, read this guide how to host on Hugging Face Spaces using the website.
Alternatively, you can create a Space programmatically, making use of the huggingface_hub client library library. Here's an example:
\n\nfrom huggingface_hub import (\n create_repo,\n get_full_repo_name,\n upload_file,\n)\ncreate_repo(name=target_space_name, token=hf_token, repo_type=\"space\", space_sdk=\"gradio\")\nrepo_name = get_full_repo_name(model_id=target_space_name, token=hf_token)\nfile_url = upload_file(\n path_or_fileobj=\"file.txt\",\n path_in_repo=\"app.py\",\n repo_id=repo_name,\n repo_type=\"space\",\n token=hf_token,\n)\n
Here, create_repo
creates a gradio repo with the target name under a specific account using that account's Write Token. repo_name
gets the full repo name of the related repo. Finally upload_file
uploads a file inside the repo with the name app.py
.
Throughout this guide, you've seen many embedded Gradio demos. You can also do this on own website! The first step is to create a Hugging Face Space with the demo you want to showcase. Then, follow the steps here to embed the Space on your website.
\n\nYou can also use and remix existing Gradio demos on Hugging Face Spaces. For example, you could take two existing Gradio demos and put them as separate tabs and create a new demo. You can run this new demo locally, or upload it to Spaces, allowing endless possibilities to remix and create new demos!
\n\nHere's an example that does exactly that:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Tab(\"Translate to Spanish\"):\n gr.load(\"gradio/helsinki_translation_en_es\", src=\"spaces\")\n with gr.Tab(\"Translate to French\"):\n gr.load(\"abidlabs/en2fr\", src=\"spaces\")\n\ndemo.launch()\n
Notice that we use gr.load()
, the same method we used to load models using the Inference API. However, here we specify that the src
is spaces
(Hugging Face Spaces).
That's it! Let's recap the various ways Gradio and Hugging Face work together:
\n\ntransformers
pipeline into a Gradio demo using from_pipeline()
gr.load()
gr.load()
.\ud83e\udd17
\n", - "tags": ["HUB", "SPACES", "EMBED"], - "spaces": [ - "https://huggingface.co/spaces/gradio/helsinki_translation_en_es" - ], - "url": "/guides/using-hugging-face-integrations/", - "contributor": "Omar Sanseviero \ud83e\udd99 " - }, - { - "name": "image-classification-in-pytorch", - "category": "integrating-other-frameworks", - "pretty_category": "Integrating Other Frameworks", - "guide_index": null, - "absolute_index": 20, - "pretty_name": "Image Classification In Pytorch", - "content": "# Image Classification in PyTorch\n\n\n\n\n## Introduction\n\nImage classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from autonomous vehicles to medical imaging. \n\nSuch models are perfect to use with Gradio's *image* input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):\n\n\n\n\nLet's get started!\n\n### Prerequisites\n\nMake sure you have the `gradio` Python package already [installed](/getting_started). We will be using a pretrained image classification model, so you should also have `torch` installed.\n\n## Step 1 \u2014 Setting up the Image Classification Model\n\nFirst, we will need an image classification model. For this tutorial, we will use a pretrained Resnet-18 model, as it is easily downloadable from [PyTorch Hub](https://pytorch.org/hub/pytorch_vision_resnet/). You can use a different pretrained model or train your own. \n\n```python\nimport torch\n\nmodel = torch.hub.load('pytorch/vision:v0.6.0', 'resnet18', pretrained=True).eval()\n```\n\nBecause we will be using the model for inference, we have called the `.eval()` method.\n\n## Step 2 \u2014 Defining a `predict` function\n\nNext, we will need to define a function that takes in the *user input*, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this [text file](https://git.io/JJkYN).\n\nIn the case of our pretrained model, it will look like this:\n\n```python\nimport requests\nfrom PIL import Image\nfrom torchvision import transforms\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef predict(inp):\n inp = transforms.ToTensor()(inp).unsqueeze(0)\n with torch.no_grad():\n prediction = torch.nn.functional.softmax(model(inp)[0], dim=0)\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)} \n return confidences\n```\n\nLet's break this down. The function takes one parameter:\n\n* `inp`: the input image as a `PIL` image\n\nThen, the function converts the image to a PIL Image and then eventually a PyTorch `tensor`, passes it through the model, and returns:\n\n* `confidences`: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilities\n\n## Step 3 \u2014 Creating a Gradio Interface\n\nNow that we have our predictive function set up, we can create a Gradio Interface around it. \n\nIn this case, the input component is a drag-and-drop image component. To create this input, we use `Image(type=\"pil\")` which creates the component and handles the preprocessing to convert that to a `PIL` image. \n\nThe output component will be a `Label`, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images by constructing it as `Label(num_top_classes=3)`.\n\nFinally, we'll add one more parameter, the `examples`, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:\n\n```python\nimport gradio as gr\n\ngr.Interface(fn=predict, \n inputs=gr.Image(type=\"pil\"),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"lion.jpg\", \"cheetah.jpg\"]).launch()\n```\n\nThis produces the following interface, which you can try right here in your browser (try uploading your own examples!):\n\n\n\n----------\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting `share=True` when you `launch()` the Interface!\n\n", - "html": "Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from autonomous vehicles to medical imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained image classification model, so you should also have torch
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Resnet-18 model, as it is easily downloadable from PyTorch Hub. You can use a different pretrained model or train your own.
\n\nimport torch\n\nmodel = torch.hub.load('pytorch/vision:v0.6.0', 'resnet18', pretrained=True).eval()\n
Because we will be using the model for inference, we have called the .eval()
method.
predict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\nfrom PIL import Image\nfrom torchvision import transforms\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef predict(inp):\n inp = transforms.ToTensor()(inp).unsqueeze(0)\n with torch.no_grad():\n prediction = torch.nn.functional.softmax(model(inp)[0], dim=0)\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)} \n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a PIL
imageThen, the function converts the image to a PIL Image and then eventually a PyTorch tensor
, passes it through the model, and returns:
confidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we use Image(type=\"pil\")
which creates the component and handles the preprocessing to convert that to a PIL
image.
The output component will be a Label
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images by constructing it as Label(num_top_classes=3)
.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=predict, \n inputs=gr.Image(type=\"pil\"),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"lion.jpg\", \"cheetah.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from traffic control systems to satellite imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained Keras image classification model, so you should also have tensorflow
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Mobile Net model, as it is easily downloadable from Keras. You can use a different pretrained model or train your own.
\n\nimport tensorflow as tf\n\ninception_net = tf.keras.applications.MobileNetV2()\n
This line automatically downloads the MobileNet model and weights using the Keras library.
\n\npredict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)}\n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a numpy
arrayThen, the function adds a batch dimension, passes it through the model, and returns:
\n\nconfidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we can use the \"gradio.inputs.Image\"
class, which creates the component and handles the preprocessing to convert that to a numpy array. We will instantiate the class with a parameter that automatically preprocesses the input image to be 224 pixels by 224 pixels, which is the size that MobileNet expects.
The output component will be a \"label\"
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=classify_image, \n inputs=gr.Image(shape=(224, 224)),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"banana.jpg\", \"car.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from facial recognition to manufacturing quality control.
\n\nState-of-the-art image classifiers are based on the transformers architectures, originally popularized for NLP tasks. Such architectures are typically called vision transformers (ViT). Such models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in a single line of Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed.
First, we will need an image classification model. For this tutorial, we will use a model from the Hugging Face Model Hub. The Hub contains thousands of models covering dozens of different machine learning tasks.
\n\nExpand the Tasks category on the left sidebar and select \"Image Classification\" as our task of interest. You will then see all of the models on the Hub that are designed to classify images.
\n\nAt the time of writing, the most popular one is google/vit-base-patch16-224
, which has been trained on ImageNet images at a resolution of 224x224 pixels. We will use this model for our demo.
When using a model from the Hugging Face Hub, we do not need to define the input or output components for the demo. Similarly, we do not need to be concerned with the details of preprocessing or postprocessing. \nAll of these are automatically inferred from the model tags.
\n\nBesides the import statement, it only takes a single line of Python to load and launch the demo.
\n\nWe use the gr.Interface.load()
method and pass in the path to the model including the huggingface/
to designate that it is from the Hugging Face Hub.
import gradio as gr\n\ngr.Interface.load(\n \"huggingface/google/vit-base-patch16-224\",\n examples=[\"alligator.jpg\", \"laptop.jpg\"]).launch()\n
Notice that we have added one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples.
This produces the following interface, which you can try right here in your browser. When you input an image, it is automatically preprocessed and sent to the Hugging Face Hub API, where it is passed through the model and returned as a human-interpretable prediction. Try uploading your own image!
\n\n\n\nAnd you're done! In one line of code, you have built a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
It seems that cryptocurrencies, NFTs, and the web3 movement are all the rage these days! Digital assets are being listed on marketplaces for astounding amounts of money, and just about every celebrity is debuting their own NFT collection. While your crypto assets may be taxable, such as in Canada, today we'll explore some fun and tax-free ways to generate your own assortment of procedurally generated CryptoPunks.
\n\nGenerative Adversarial Networks, often known just as GANs, are a specific class of deep-learning models that are designed to learn from an input dataset to create (generate!) new material that is convincingly similar to elements of the original training set. Famously, the website thispersondoesnotexist.com went viral with lifelike, yet synthetic, images of people generated with a model called StyleGAN2. GANs have gained traction in the machine learning world, and are now being used to generate all sorts of images, text, and even music!
\n\nToday we'll briefly look at the high-level intuition behind GANs, and then we'll build a small demo around a pre-trained GAN to see what all the fuss is about. Here's a peek at what we're going to be putting together:
\n\n\n\nMake sure you have the gradio
Python package already installed. To use the pretrained model, also install torch
and torchvision
.
Originally proposed in Goodfellow et al. 2014, GANs are made up of neural networks which compete with the intention of outsmarting each other. One network, known as the generator, is responsible for generating images. The other network, the discriminator, receives an image at a time from the generator along with a real image from the training data set. The discriminator then has to guess: which image is the fake?
\n\nThe generator is constantly training to create images which are trickier for the discriminator to identify, while the discriminator raises the bar for the generator every time it correctly detects a fake. As the networks engage in this competitive (adversarial!) relationship, the images that get generated improve to the point where they become indistinguishable to human eyes!
\n\nFor a more in-depth look at GANs, you can take a look at this excellent post on Analytics Vidhya or this PyTorch tutorial. For now, though, we'll dive into a demo!
\n\nTo generate new images with a GAN, you only need the generator model. There are many different architectures that the generator could use, but for this demo we'll use a pretrained GAN generator model with the following architecture:
\n\nfrom torch import nn\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n
We're taking the generator from this repo by @teddykoker, where you can also see the original discriminator model structure.
\n\nAfter instantiating the model, we'll load in the weights from the Hugging Face Hub, stored at nateraw/cryptopunks-gan:
\n\nfrom huggingface_hub import hf_hub_download\nimport torch\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n
predict
functionThe predict
function is the key to making Gradio work! Whatever inputs we choose through the Gradio interface will get passed through our predict
function, which should operate on the inputs and generate outputs that we can display with Gradio output components. For GANs it's common to pass random noise into our model as the input, so we'll generate a tensor of random numbers and pass that through the model. We can then use torchvision
's save_image
function to save the output of the model as a png
file, and return the file name:
from torchvision.utils import save_image\n\ndef predict(seed):\n num_punks = 4\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
We're giving our predict
function a seed
parameter, so that we can fix the random tensor generation with a seed. We'll then be able to reproduce punks if we want to see them again by passing in the same seed.
Note! Our model needs an input tensor of dimensions 100x1x1 to do a single inference, or (BatchSize)x100x1x1 for generating a batch of images. In this demo we'll start by generating 4 punks at a time.
\n\nAt this point you can even run the code you have with predict(<SOME_NUMBER>)
, and you'll find your freshly generated punks in your file system at ./punks.png
. To make a truly interactive demo, though, we'll build out a simple interface with Gradio. Our goals here are to:
predict()
to take the seed and generate the imagesWith gr.Interface()
, we can define all of that with a single function call:
import gradio as gr\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n ],\n outputs=\"image\",\n).launch()\n
Launching the interface should present you with something like this:
\n\n\n\nGenerating 4 punks at a time is a good start, but maybe we'd like to control how many we want to make each time. Adding more inputs to our Gradio interface is as simple as adding another item to the inputs
list that we pass to gr.Interface
:
gr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10), # Adding another slider!\n ],\n outputs=\"image\",\n).launch()\n
The new input will be passed to our predict()
function, so we have to make some changes to that function to accept a new parameter:
def predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
When you relaunch your interface, you should see a second slider that'll let you control the number of punks!
\n\nYour Gradio app is pretty much good to go, but you can add a few extra things to really make it ready for the spotlight \u2728
\n\nWe can add some examples that users can easily try out by adding this to the gr.Interface
:
gr.Interface(\n # ...\n # keep everything as it is, and then add\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True) # cache_examples is optional\n
The examples
parameter takes a list of lists, where each item in the sublists is ordered in the same order that we've listed the inputs
. So in our case, [seed, num_punks]
. Give it a try!
You can also try adding a title
, description
, and article
to the gr.Interface
. Each of those parameters accepts a string, so try it out and see what happens \ud83d\udc40 article
will also accept HTML, as explored in a previous guide!
When you're all done, you may end up with something like this:
\n\n\n\nFor reference, here is our full code:
\n\nimport torch\nfrom torch import nn\nfrom huggingface_hub import hf_hub_download\nfrom torchvision.utils import save_image\nimport gradio as gr\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n\ndef predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10),\n ],\n outputs=\"image\",\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True)\n
Congratulations! You've built out your very own GAN-powered CryptoPunks generator, with a fancy Gradio interface that makes it easy for anyone to use. Now you can scour the Hub for more GANs (or train your own) and continue making even more awesome demos \ud83e\udd17
\n", - "tags": ["GAN", "IMAGE", "HUB"], - "spaces": [ - "https://huggingface.co/spaces/NimaBoscarino/cryptopunks", - "https://huggingface.co/spaces/nateraw/cryptopunks-generator" - ], - "url": "/guides/create-your-own-friends-with-a-gan/", - "contributor": "Nima Boscarino and Nate Raw" - } - ], - "parent": "gradio", - "prev_obj": "load", - "next_obj": "Progress" - }, - "progress": { - "class": null, - "name": "Progress", - "description": "The Progress class provides a custom progress tracker that is used in a function signature. To attach a Progress tracker to a function, simply add a parameter right after the input parameters that has a default value set to a `gradio.Progress()` instance. The Progress tracker can then be updated in the function by calling the Progress object or using the `tqdm` method on an Iterable. The Progress tracker is currently only available with `queue()`.", - "tags": { "demos": "progress" }, - "parameters": [ - { - "name": "self", - "annotation": "When you demo a machine learning model, you might want to collect data from users who try the model, particularly data points in which the model is not behaving as expected. Capturing these \"hard\" data points is valuable because it allows you to improve your machine learning model and make it more reliable and robust.
\n\nGradio simplifies the collection of this data by including a Flag button with every Interface
. This allows a user or tester to easily send data back to the machine where the demo is running. In this Guide, we discuss more about how to use the flagging feature, both with gradio.Interface
as well as with gradio.Blocks
.
gradio.Interface
Flagging with Gradio's Interface
is especially easy. By default, underneath the output components, there is a button marked Flag. When a user testing your model sees input with interesting output, they can click the flag button to send the input and output data back to the machine where the demo is running. The sample is saved to a CSV log file (by default). If the demo involves images, audio, video, or other types of files, these are saved separately in a parallel directory and the paths to these files are saved in the CSV file.
There are four parameters in gradio.Interface
that control how flagging works. We will go over them in greater detail.
allow_flagging
: this parameter can be set to either \"manual\"
(default), \"auto\"
, or \"never\"
. manual
: users will see a button to flag, and samples are only flagged when the button is clicked.auto
: users will not see a button to flag, but every sample will be flagged automatically. never
: users will not see a button to flag, and no sample will be flagged. flagging_options
: this parameter can be either None
(default) or a list of strings.\nNone
, then the user simply clicks on the Flag button and no additional options are shown.[\"Incorrect\", \"Ambiguous\"]
, then buttons labeled Flag as Incorrect and Flag as Ambiguous appear. This only applies if allow_flagging
is \"manual\"
.flagging_dir
: this parameter takes a string.\nflagging_callback
: this parameter takes an instance of a subclass of the FlaggingCallback
class\ngr.CSVLogger
gr.HuggingFaceDatasetSaver
which can allow you to pipe any flagged data into a HuggingFace Dataset. (See more below.)Within the directory provided by the flagging_dir
argument, a CSV file will log the flagged data.
Here's an example: The code below creates the calculator interface embedded below it:
\n\nimport gradio as gr\n\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n return num1 / num2\n\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n allow_flagging=\"manual\"\n)\n\niface.launch()\n
When you click the flag button above, the directory where the interface was launched will include a new flagged subfolder, with a csv file inside it. This csv file includes all the data that was flagged.
\n\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output,timestamp\n5,add,7,12,2022-01-31 11:40:51.093412\n6,subtract,1.5,4.5,2022-01-31 03:25:32.023542\n
If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well. For example an image
input to image
output interface will create the following structure.
+-- flagged/\n| +-- logs.csv\n| +-- image/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output timestamp\nim/0.png,Output/0.png,2022-02-04 19:49:58.026963\nim/1.png,Output/1.png,2022-02-02 10:40:51.093412\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of these choices when flagging, and the option will be saved as an additional column to the CSV.
If we go back to the calculator example, the following code will create the interface embedded below it.
\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n allow_flagging=\"manual\",\n flagging_options=[\"wrong sign\", \"off by one\", \"other\"]\n)\n\niface.launch()\n
When users click the flag button, the csv file will now include a column indicating the selected option.
\n\nflagged/logs.csv
\n\nnum1,operation,num2,Output,flag,timestamp\n5,add,7,-12,wrong sign,2022-02-04 11:40:51.093412\n6,subtract,1.5,3.5,off by one,2022-02-04 11:42:32.062512\n
Sometimes, saving the data to a local CSV file doesn't make sense. For example, on Hugging Face\nSpaces, developers typically don't have access to the underlying ephemeral machine hosting the Gradio\ndemo. That's why, by default, flagging is turned off in Hugging Face Space. However,\nyou may want to do something else with the flagged data.
\n\nWe've made this super easy with the flagging_callback
parameter.
For example, below we're going to pipe flagged data from our calculator example into a Hugging Face Dataset, e.g. so that we can build a \"crowd-sourced\" dataset:
\n\nimport os\n\nHF_TOKEN = os.getenv('HF_TOKEN')\nhf_writer = gr.HuggingFaceDatasetSaver(HF_TOKEN, \"crowdsourced-calculator-demo\")\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n description=\"Check out the crowd-sourced dataset at: [https://huggingface.co/datasets/aliabd/crowdsourced-calculator-demo](https://huggingface.co/datasets/aliabd/crowdsourced-calculator-demo)\",\n allow_flagging=\"manual\",\n flagging_options=[\"wrong sign\", \"off by one\", \"other\"],\n flagging_callback=hf_writer\n)\n\niface.launch()\n
Notice that we define our own \ninstance of gradio.HuggingFaceDatasetSaver
using our Hugging Face token and\nthe name of a dataset we'd like to save samples to. In addition, we also set allow_flagging=\"manual\"
\nbecause on Hugging Face Spaces, allow_flagging
is set to \"never\"
by default. Here's our demo:
You can now see all the examples flagged above in this public Hugging Face dataset.
\n\n\n\nWe created the gradio.HuggingFaceDatasetSaver
class, but you can pass your own custom class as long as it inherits from FLaggingCallback
defined in this file. If you create a cool callback, contribute it to the repo!
What about if you are using gradio.Blocks
? On one hand, you have even more flexibility\nwith Blocks -- you can write whatever Python code you want to run when a button is clicked,\nand assign that using the built-in events in Blocks.
At the same time, you might want to use an existing FlaggingCallback
to avoid writing extra code.\nThis requires two steps:
.setup()
somewhere in the code prior to the \nfirst time you flag data.flag()
method,\nmaking sure to collect the arguments correctly and disabling the typical preprocessing. Here is an example with an image sepia filter Blocks demo that lets you flag\ndata using the default CSVLogger
:
import numpy as np\nimport gradio as gr\n\ndef sepia(input_img, strength):\n sepia_filter = strength * np.array(\n [[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]\n ) + (1-strength) * np.identity(3)\n sepia_img = input_img.dot(sepia_filter.T)\n sepia_img /= sepia_img.max()\n return sepia_img\n\ncallback = gr.CSVLogger()\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n img_input = gr.Image()\n strength = gr.Slider(0, 1, 0.5)\n img_output = gr.Image()\n with gr.Row():\n btn = gr.Button(\"Flag\")\n\n # This needs to be called at some point prior to the first call to callback.flag()\n callback.setup([img_input, strength, img_output], \"flagged_data_points\")\n\n img_input.change(sepia, [img_input, strength], img_output)\n strength.change(sepia, [img_input, strength], img_output)\n\n # We can choose which components to flag -- in this case, we'll flag all of them\n btn.click(lambda *args: callback.flag(args), [img_input, strength, img_output], None, preprocess=False)\n\ndemo.launch()\n\n
Important Note: please make sure your users understand when the data they submit is being saved, and what you plan on doing with it. This is especially important when you use allow_flagging=auto
(when all of the data submitted through the demo is being flagged)
When you demo a machine learning model, you might want to collect data from users who try the model, particularly data points in which the model is not behaving as expected. Capturing these \"hard\" data points is valuable because it allows you to improve your machine learning model and make it more reliable and robust.
\n\nGradio simplifies the collection of this data by including a Flag button with every Interface
. This allows a user or tester to easily send data back to the machine where the demo is running. In this Guide, we discuss more about how to use the flagging feature, both with gradio.Interface
as well as with gradio.Blocks
.
gradio.Interface
Flagging with Gradio's Interface
is especially easy. By default, underneath the output components, there is a button marked Flag. When a user testing your model sees input with interesting output, they can click the flag button to send the input and output data back to the machine where the demo is running. The sample is saved to a CSV log file (by default). If the demo involves images, audio, video, or other types of files, these are saved separately in a parallel directory and the paths to these files are saved in the CSV file.
There are four parameters in gradio.Interface
that control how flagging works. We will go over them in greater detail.
allow_flagging
: this parameter can be set to either \"manual\"
(default), \"auto\"
, or \"never\"
. manual
: users will see a button to flag, and samples are only flagged when the button is clicked.auto
: users will not see a button to flag, but every sample will be flagged automatically. never
: users will not see a button to flag, and no sample will be flagged. flagging_options
: this parameter can be either None
(default) or a list of strings.\nNone
, then the user simply clicks on the Flag button and no additional options are shown.[\"Incorrect\", \"Ambiguous\"]
, then buttons labeled Flag as Incorrect and Flag as Ambiguous appear. This only applies if allow_flagging
is \"manual\"
.flagging_dir
: this parameter takes a string.\nflagging_callback
: this parameter takes an instance of a subclass of the FlaggingCallback
class\ngr.CSVLogger
gr.HuggingFaceDatasetSaver
which can allow you to pipe any flagged data into a HuggingFace Dataset. (See more below.)Within the directory provided by the flagging_dir
argument, a CSV file will log the flagged data.
Here's an example: The code below creates the calculator interface embedded below it:
\n\nimport gradio as gr\n\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n return num1 / num2\n\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n allow_flagging=\"manual\"\n)\n\niface.launch()\n
When you click the flag button above, the directory where the interface was launched will include a new flagged subfolder, with a csv file inside it. This csv file includes all the data that was flagged.
\n\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output,timestamp\n5,add,7,12,2022-01-31 11:40:51.093412\n6,subtract,1.5,4.5,2022-01-31 03:25:32.023542\n
If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well. For example an image
input to image
output interface will create the following structure.
+-- flagged/\n| +-- logs.csv\n| +-- image/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output timestamp\nim/0.png,Output/0.png,2022-02-04 19:49:58.026963\nim/1.png,Output/1.png,2022-02-02 10:40:51.093412\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of these choices when flagging, and the option will be saved as an additional column to the CSV.
If we go back to the calculator example, the following code will create the interface embedded below it.
\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n allow_flagging=\"manual\",\n flagging_options=[\"wrong sign\", \"off by one\", \"other\"]\n)\n\niface.launch()\n
When users click the flag button, the csv file will now include a column indicating the selected option.
\n\nflagged/logs.csv
\n\nnum1,operation,num2,Output,flag,timestamp\n5,add,7,-12,wrong sign,2022-02-04 11:40:51.093412\n6,subtract,1.5,3.5,off by one,2022-02-04 11:42:32.062512\n
Sometimes, saving the data to a local CSV file doesn't make sense. For example, on Hugging Face\nSpaces, developers typically don't have access to the underlying ephemeral machine hosting the Gradio\ndemo. That's why, by default, flagging is turned off in Hugging Face Space. However,\nyou may want to do something else with the flagged data.
\n\nWe've made this super easy with the flagging_callback
parameter.
For example, below we're going to pipe flagged data from our calculator example into a Hugging Face Dataset, e.g. so that we can build a \"crowd-sourced\" dataset:
\n\nimport os\n\nHF_TOKEN = os.getenv('HF_TOKEN')\nhf_writer = gr.HuggingFaceDatasetSaver(HF_TOKEN, \"crowdsourced-calculator-demo\")\n\niface = gr.Interface(\n calculator,\n [\"number\", gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]), \"number\"],\n \"number\",\n description=\"Check out the crowd-sourced dataset at: [https://huggingface.co/datasets/aliabd/crowdsourced-calculator-demo](https://huggingface.co/datasets/aliabd/crowdsourced-calculator-demo)\",\n allow_flagging=\"manual\",\n flagging_options=[\"wrong sign\", \"off by one\", \"other\"],\n flagging_callback=hf_writer\n)\n\niface.launch()\n
Notice that we define our own \ninstance of gradio.HuggingFaceDatasetSaver
using our Hugging Face token and\nthe name of a dataset we'd like to save samples to. In addition, we also set allow_flagging=\"manual\"
\nbecause on Hugging Face Spaces, allow_flagging
is set to \"never\"
by default. Here's our demo:
You can now see all the examples flagged above in this public Hugging Face dataset.
\n\n\n\nWe created the gradio.HuggingFaceDatasetSaver
class, but you can pass your own custom class as long as it inherits from FLaggingCallback
defined in this file. If you create a cool callback, contribute it to the repo!
What about if you are using gradio.Blocks
? On one hand, you have even more flexibility\nwith Blocks -- you can write whatever Python code you want to run when a button is clicked,\nand assign that using the built-in events in Blocks.
At the same time, you might want to use an existing FlaggingCallback
to avoid writing extra code.\nThis requires two steps:
.setup()
somewhere in the code prior to the \nfirst time you flag data.flag()
method,\nmaking sure to collect the arguments correctly and disabling the typical preprocessing. Here is an example with an image sepia filter Blocks demo that lets you flag\ndata using the default CSVLogger
:
import numpy as np\nimport gradio as gr\n\ndef sepia(input_img, strength):\n sepia_filter = strength * np.array(\n [[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]\n ) + (1-strength) * np.identity(3)\n sepia_img = input_img.dot(sepia_filter.T)\n sepia_img /= sepia_img.max()\n return sepia_img\n\ncallback = gr.CSVLogger()\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n img_input = gr.Image()\n strength = gr.Slider(0, 1, 0.5)\n img_output = gr.Image()\n with gr.Row():\n btn = gr.Button(\"Flag\")\n\n # This needs to be called at some point prior to the first call to callback.flag()\n callback.setup([img_input, strength, img_output], \"flagged_data_points\")\n\n img_input.change(sepia, [img_input, strength], img_output)\n strength.change(sepia, [img_input, strength], img_output)\n\n # We can choose which components to flag -- in this case, we'll flag all of them\n btn.click(lambda *args: callback.flag(args), [img_input, strength, img_output], None, preprocess=False)\n\ndemo.launch()\n\n
Important Note: please make sure your users understand when the data they submit is being saved, and what you plan on doing with it. This is especially important when you use allow_flagging=auto
(when all of the data submitted through the demo is being flagged)
We took a quick look at Blocks in the Quickstart. Let's dive deeper. This guide will cover the how Blocks are structured, event listeners and their types, running events continuously, updating configurations, and using dictionaries vs lists.
\n\nTake a look at the demo below.
\n\nimport gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\nwith gr.Blocks() as demo:\n name = gr.Textbox(label=\"Name\")\n output = gr.Textbox(label=\"Output Box\")\n greet_btn = gr.Button(\"Greet\")\n greet_btn.click(fn=greet, inputs=name, outputs=output, api_name=\"greet\")\n\n\ndemo.launch()\n
with gr.Blocks() as demo:
clause. The Blocks app code will be contained within this clause.Interface
. However, instead of being passed to some constructor, Components are automatically added to the Blocks as they are created within the with
clause.click()
event listener. Event listeners define the data flow within the app. In the example above, the listener ties the two Textboxes together. The Textbox name
acts as the input and Textbox output
acts as the output to the greet
method. This dataflow is triggered when the Button greet_btn
is clicked. Like an Interface, an event listener can take multiple inputs or outputs.In the example above, you'll notice that you are able to edit Textbox name
, but not Textbox output
. This is because any Component that acts as an input to an event listener is made interactive. However, since Textbox output
acts only as an output, Gradio determines that it should not be made interactive. You can override the default behavior and directly configure the interactivity of a Component with the boolean interactive
keyword argument.
output = gr.Textbox(label=\"Output\", interactive=True)\n
Note: What happens if a Gradio component is neither an input nor an output? If a component is constructed with a default value, then it is presumed to be displaying content and is rendered non-interactive. Otherwise, it is rendered interactive. Again, this behavior can be overridden by specifying a value for the interactive
argument.
Take a look at the demo below:
\n\nimport gradio as gr\n\ndef welcome(name):\n return f\"Welcome to Gradio, {name}!\"\n\nwith gr.Blocks() as demo:\n gr.Markdown(\n \"\"\"\n # Hello World!\n Start typing below to see the output.\n \"\"\")\n inp = gr.Textbox(placeholder=\"What is your name?\")\n out = gr.Textbox()\n inp.change(welcome, inp, out)\n\ndemo.launch()\n
Instead of being triggered by a click, the welcome
function is triggered by typing in the Textbox inp
. This is due to the change()
event listener. Different Components support different event listeners. For example, the Video
Component supports a play()
event listener, triggered when a user presses play. See the Docs for the event listeners for each Component.
A Blocks app is not limited to a single data flow the way Interfaces are. Take a look at the demo below:
\n\nimport gradio as gr\n\ndef increase(num):\n return num + 1\n\nwith gr.Blocks() as demo:\n a = gr.Number(label=\"a\")\n b = gr.Number(label=\"b\")\n btoa = gr.Button(\"a > b\")\n atob = gr.Button(\"b > a\")\n atob.click(increase, a, b)\n btoa.click(increase, b, a)\n\ndemo.launch()\n
Note that num1
can act as input to num2
, and also vice-versa! As your apps get more complex, you will have many data flows connecting various Components.
Here's an example of a \"multi-step\" demo, where the output of one model (a speech-to-text model) gets fed into the next model (a sentiment classifier).
\n\nfrom transformers import pipeline\n\nimport gradio as gr\n\nasr = pipeline(\"automatic-speech-recognition\", \"facebook/wav2vec2-base-960h\")\nclassifier = pipeline(\"text-classification\")\n\n\ndef speech_to_text(speech):\n text = asr(speech)[\"text\"]\n return text\n\n\ndef text_to_sentiment(text):\n return classifier(text)[0][\"label\"]\n\n\ndemo = gr.Blocks()\n\nwith demo:\n audio_file = gr.Audio(type=\"filepath\")\n text = gr.Textbox()\n label = gr.Label()\n\n b1 = gr.Button(\"Recognize Speech\")\n b2 = gr.Button(\"Classify Sentiment\")\n\n b1.click(speech_to_text, inputs=audio_file, outputs=text)\n b2.click(text_to_sentiment, inputs=text, outputs=label)\n\ndemo.launch()\n\n
The event listeners you've seen so far have a single input component. If you'd like to have multiple input components pass data to the function, you have two options on how the function can accept input component values:
\n\nLet's see an example of each:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n a = gr.Number(label=\"a\")\n b = gr.Number(label=\"b\")\n with gr.Row():\n add_btn = gr.Button(\"Add\")\n sub_btn = gr.Button(\"Subtract\")\n c = gr.Number(label=\"sum\")\n\n def add(num1, num2):\n return num1 + num2\n add_btn.click(add, inputs=[a, b], outputs=c)\n\n def sub(data):\n return data[a] - data[b]\n sub_btn.click(sub, inputs={a, b}, outputs=c)\n\n\ndemo.launch()\n
Both add()
and sub()
take a
and b
as inputs. However, the syntax is different between these listeners.
add_btn
listener, we pass the inputs as a list. The function add()
takes each of these inputs as arguments. The value of a
maps to the argument num1
, and the value of b
maps to the argument num2
.sub_btn
listener, we pass the inputs as a set (note the curly brackets!). The function sub()
takes a single dictionary argument data
, where the keys are the input components, and the values are the values of those components.It is a matter of preference which syntax you prefer! For functions with many input components, option 2 may be easier to manage.
\n\nSimilarly, you may return values for multiple output components either as:
\n\nLet's first see an example of (1), where we set the values of two output components by returning two values:
\n\nwith gr.Blocks() as demo:\n food_box = gr.Number(value=10, label=\"Food Count\")\n status_box = gr.Textbox()\n def eat(food):\n if food > 0:\n return food - 1, \"full\"\n else:\n return 0, \"hungry\"\n gr.Button(\"EAT\").click(\n fn=eat, \n inputs=food_box,\n outputs=[food_box, status_box]\n )\n
Above, each return statement returns two values corresponding to food_box
and status_box
, respectively.
Instead of returning a list of values corresponding to each output component in order, you can also return a dictionary, with the key corresponding to the output component and the value as the new value. This also allows you to skip updating some output components.
\n\nwith gr.Blocks() as demo:\n food_box = gr.Number(value=10, label=\"Food Count\")\n status_box = gr.Textbox()\n def eat(food):\n if food > 0:\n return {food_box: food - 1, status_box: \"full\"}\n else:\n return {status_box: \"hungry\"}\n gr.Button(\"EAT\").click(\n fn=eat, \n inputs=food_box,\n outputs=[food_box, status_box]\n )\n
Notice how when there is no food, we only update the status_box
element. We skipped updating the food_box
component.
Dictionary returns are helpful when an event listener affects many components on return, or conditionally affects outputs and not others.
\n\nKeep in mind that with dictionary returns, we still need to specify the possible outputs in the event listener.
\n\nThe return value of an event listener function is usually the updated value of the corresponding output Component. Sometimes we want to update the configuration of the Component as well, such as the visibility. In this case, we return a gr.update()
object instead of just the update Component value.
import gradio as gr\n\ndef change_textbox(choice):\n if choice == \"short\":\n return gr.update(lines=2, visible=True, value=\"Short story: \")\n elif choice == \"long\":\n return gr.update(lines=8, visible=True, value=\"Long story...\")\n else:\n return gr.update(visible=False)\n\nwith gr.Blocks() as demo:\n radio = gr.Radio(\n [\"short\", \"long\", \"none\"], label=\"Essay Length to Write?\"\n )\n text = gr.Textbox(lines=2, interactive=True)\n radio.change(fn=change_textbox, inputs=radio, outputs=text)\n\ndemo.launch()\n
See how we can configure the Textbox itself through the gr.update()
method. The value=
argument can still be used to update the value along with Component configuration.
You can also run events consecutively by using the then
method of an event listener. This will run an event after the previous event has finished running. This is useful for running events that update components in multiple steps.
For example, in the chatbot example below, we first update the chatbot with the user message immediately, and then update the chatbot with the computer response after a simulated delay.
\n\nimport gradio as gr\nimport random\nimport time\n\nwith gr.Blocks() as demo:\n chatbot = gr.Chatbot()\n msg = gr.Textbox()\n clear = gr.Button(\"Clear\")\n\n def user(user_message, history):\n return \"\", history + [[user_message, None]]\n\n def bot(history):\n bot_message = random.choice([\"How are you?\", \"I love you\", \"I'm very hungry\"])\n time.sleep(2)\n history[-1][1] = bot_message\n return history\n\n msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(\n bot, chatbot, chatbot\n )\n clear.click(lambda: None, None, chatbot, queue=False)\n\ndemo.queue()\ndemo.launch()\n\n
The .then()
method of an event listener executes the subsequent event regardless of whether the previous event raised any errors. If you'd like to only run subsequent events if the previous event executed successfully, use the .success()
method, which takes the same arguments as .then()
.
You can run events on a fixed schedule using the every
parameter of the event listener. This will run the event\nevery
number of seconds while the client connection is open. If the connection is closed, the event will stop running after the following iteration.\nNote that this does not take into account the runtime of the event itself. So a function\nwith a 1 second runtime running with every=5
, would actually run every 6 seconds.
Here is an example of a sine curve that updates every second!
\n\nimport math\nimport gradio as gr\nimport plotly.express as px\nimport numpy as np\n\n\nplot_end = 2 * math.pi\n\n\ndef get_plot(period=1):\n global plot_end\n x = np.arange(plot_end - 2 * math.pi, plot_end, 0.02)\n y = np.sin(2*math.pi*period * x)\n fig = px.line(x=x, y=y)\n plot_end += 2 * math.pi\n if plot_end > 1000:\n plot_end = 2 * math.pi\n return fig\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n gr.Markdown(\"Change the value of the slider to automatically update the plot\")\n period = gr.Slider(label=\"Period of plot\", value=1, minimum=0, maximum=10, step=1)\n plot = gr.Plot(label=\"Plot (updates every half second)\")\n\n dep = demo.load(get_plot, None, plot, every=1)\n period.change(get_plot, period, plot, every=1, cancels=[dep])\n\n\nif __name__ == \"__main__\":\n demo.queue().launch()\n\n
You can gather specific data about an event by adding the associated event data class as a type hint to an argument in the event listener function.
\n\nFor example, event data for .select()
can be type hinted by a gradio.SelectData
argument. This event is triggered when a user selects some part of the triggering component, and the event data includes information about what the user specifically selected. If a user selected a specific word in a Textbox
, a specific image in a Gallery
, or a specific cell in a DataFrame
, the event data argument would contain information about the specific selection.
In the 2 player tic-tac-toe demo below, a user can select a cell in the DataFrame
to make a move. The event data argument contains information about the specific cell that was selected. We can first check to see if the cell is empty, and then update the cell with the user's move.
import gradio as gr\n\nwith gr.Blocks() as demo:\n turn = gr.Textbox(\"X\", interactive=False, label=\"Turn\")\n board = gr.Dataframe(value=[[\"\", \"\", \"\"]] * 3, interactive=False, type=\"array\")\n\n def place(board, turn, evt: gr.SelectData):\n if evt.value:\n return board, turn\n board[evt.index[0]][evt.index[1]] = turn\n turn = \"O\" if turn == \"X\" else \"X\"\n return board, turn\n\n board.select(place, [board, turn], [board, turn])\n\ndemo.launch()\n
By default, Components in Blocks are arranged vertically. Let's take a look at how we can rearrange Components. Under the hood, this layout structure uses the flexbox model of web development.
\n\nElements within a with gr.Row
clause will all be displayed horizontally. For example, to display two Buttons side by side:
with gr.Blocks() as demo:\n with gr.Row():\n btn1 = gr.Button(\"Button 1\")\n btn2 = gr.Button(\"Button 2\")\n
To make every element in a Row have the same height, use the equal_height
argument of the style
method.
with gr.Blocks() as demo:\n with gr.Row().style(equal_height=True):\n textbox = gr.Textbox()\n btn2 = gr.Button(\"Button 2\")\n
The widths of elements in a Row can be controlled via a combination of scale
and min_width
arguments that are present in every Component.
scale
is an integer that defines how an element will take up space in a Row. If scale is set to 0
, and element will not expand to take up space. If scale is set to 1
or greater, the element well expand. Multiple elements in a row will expand proportional to their scale. Below, btn1
will expand twice as much as btn2
, while btn0
will not expand at all:with gr.Blocks() as demo:\n with gr.Row():\n btn0 = gr.Button(\"Button 0\", scale=0)\n btn1 = gr.Button(\"Button 1\", scale=1)\n btn2 = gr.Button(\"Button 2\", scale=2)\n
min_width
will set the minimum width the element will take. The Row will wrap if there isn't sufficient space to satisfy all min_width
values.Learn more about Rows in the docs.
\n\nComponents within a Column will be placed vertically atop each other. Since the vertical layout is the default layout for Blocks apps anyway, to be useful, Columns are usually nested within Rows. For example:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n text1 = gr.Textbox(label=\"t1\")\n slider2 = gr.Textbox(label=\"s2\")\n drop3 = gr.Dropdown([\"a\", \"b\", \"c\"], label=\"d3\")\n with gr.Row():\n with gr.Column(scale=1, min_width=600):\n text1 = gr.Textbox(label=\"prompt 1\")\n text2 = gr.Textbox(label=\"prompt 2\")\n inbtw = gr.Button(\"Between\")\n text4 = gr.Textbox(label=\"prompt 1\")\n text5 = gr.Textbox(label=\"prompt 2\")\n with gr.Column(scale=2, min_width=600):\n img1 = gr.Image(\"images/cheetah.jpg\")\n btn = gr.Button(\"Go\").style(full_width=True)\n\ndemo.launch()\n
See how the first column has two Textboxes arranged vertically. The second column has an Image and Button arranged vertically. Notice how the relative widths of the two columns is set by the scale
parameter. The column with twice the scale
value takes up twice the width.
Learn more about Columns in the docs.
\n\nYou can also create Tabs using the with gr.Tab('tab_name'):
clause. Any component created inside of a with gr.Tab('tab_name'):
context appears in that tab. Consecutive Tab clauses are grouped together so that a single tab can be selected at one time, and only the components within that Tab's context are shown.
For example:
\n\nimport numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
Also note the gr.Accordion('label')
in this example. The Accordion is a layout that can be toggled open or closed. Like Tabs
, it is a layout element that can selectively hide or show content. Any components that are defined inside of a with gr.Accordion('label'):
will be hidden or shown when the accordion's toggle icon is clicked.
Learn more about Tabs and Accordions in the docs.
\n\nBoth Components and Layout elements have a visible
argument that can set initially and also updated using gr.update()
. Setting gr.update(visible=...)
on a Column can be used to show or hide a set of Components.
import gradio as gr\n\nwith gr.Blocks() as demo:\n error_box = gr.Textbox(label=\"Error\", visible=False)\n\n name_box = gr.Textbox(label=\"Name\")\n age_box = gr.Number(label=\"Age\", minimum=0, maximum=100)\n symptoms_box = gr.CheckboxGroup([\"Cough\", \"Fever\", \"Runny Nose\"])\n submit_btn = gr.Button(\"Submit\")\n\n with gr.Column(visible=False) as output_col:\n diagnosis_box = gr.Textbox(label=\"Diagnosis\")\n patient_summary_box = gr.Textbox(label=\"Patient Summary\")\n\n def submit(name, age, symptoms):\n if len(name) == 0:\n return {error_box: gr.update(value=\"Enter name\", visible=True)}\n return {\n output_col: gr.update(visible=True),\n diagnosis_box: \"covid\" if \"Cough\" in symptoms else \"flu\",\n patient_summary_box: f\"{name}, {age} y/o\",\n }\n\n submit_btn.click(\n submit,\n [name_box, age_box, symptoms_box],\n [error_box, diagnosis_box, patient_summary_box, output_col],\n )\n\ndemo.launch()\n\n
By adjusting the visibility of components in a dynamic way, it is possible to create\ndemos with Gradio that support a variable numbers of outputs. Here's a very simple example\nwhere the number of output textboxes is controlled by an input slider:
\n\nimport gradio as gr\n\nmax_textboxes = 10\n\ndef variable_outputs(k):\n k = int(k)\n return [gr.Textbox.update(visible=True)]*k + [gr.Textbox.update(visible=False)]*(max_textboxes-k)\n\nwith gr.Blocks() as demo:\n s = gr.Slider(1, max_textboxes, value=max_textboxes, step=1, label=\"How many textboxes to show:\")\n textboxes = []\n for i in range(max_textboxes):\n t = gr.Textbox(f\"Textbox {i}\")\n textboxes.append(t)\n\n s.change(variable_outputs, s, textboxes)\n\nif __name__ == \"__main__\":\n demo.launch()\n\n
In some cases, you might want to define components before you actually render them in your UI. For instance, you might want to show an examples section using gr.Examples
above the corresponding gr.Textbox
input. Since gr.Examples
requires as a parameter the input component object, you will need to first define the input component, but then render it later, after you have defined the gr.Examples
object.
The solution to this is to define the gr.Textbox
outside of the gr.Blocks()
scope and use the component's .render()
method wherever you'd like it placed in the UI.
Here's a full code example:
\n\ninput_textbox = gr.Textbox()\n\nwith gr.Blocks() as demo:\n gr.Examples([\"hello\", \"bonjour\", \"merhaba\"], input_textbox)\n input_textbox.render()\n
We covered State in Interfaces, this guide takes a look at state in Blocks, which works mostly the same.
\n\nGlobal state in Blocks works the same as in Interface. Any variable created outside a function call is a reference shared between all users.
\n\nGradio supports session state, where data persists across multiple submits within a page session, in Blocks apps as well. To reiterate, session data is not shared between different users of your model. To store data in a session state, you need to do three things:
\n\ngr.State()
object. If there is a default value to this stateful object, pass that into the constructor.State
object as an input and output.Let's take a look at a game of hangman.
\n\nimport gradio as gr\n\nsecret_word = \"gradio\"\n\nwith gr.Blocks() as demo: \n used_letters_var = gr.State([])\n with gr.Row() as row:\n with gr.Column():\n input_letter = gr.Textbox(label=\"Enter letter\")\n btn = gr.Button(\"Guess Letter\")\n with gr.Column():\n hangman = gr.Textbox(\n label=\"Hangman\",\n value=\"_\"*len(secret_word)\n )\n used_letters_box = gr.Textbox(label=\"Used Letters\")\n\n def guess_letter(letter, used_letters):\n used_letters.append(letter)\n answer = \"\".join([\n (letter if letter in used_letters else \"_\")\n for letter in secret_word\n ])\n return {\n used_letters_var: used_letters,\n used_letters_box: \", \".join(used_letters),\n hangman: answer\n }\n btn.click(\n guess_letter, \n [input_letter, used_letters_var],\n [used_letters_var, used_letters_box, hangman]\n )\ndemo.launch()\n
Let's see how we do each of the 3 steps listed above in this game:
\n\nused_letters_var
. In the constructor of State
, we set the initial value of this to []
, an empty list. btn.click()
, we have a reference to used_letters_var
in both the inputs and outputs.guess_letter
, we pass the value of this State
to used_letters
, and then return an updated value of this State
in the return statement.With more complex apps, you will likely have many State variables storing session state in a single Blocks app.
\n\nLearn more about State
in the docs.
This guide covers how to style Blocks with more flexibility, as well as adding Javascript code to event listeners.
\n\nWarning: The use of query selectors in custom JS and CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using query selectors sparingly.
\n\nGradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the theme=
kwarg to the Blocks
constructor. For example:
with gr.Blocks(theme=gr.themes.Glass()):\n ...\n
Gradio comes with a set of prebuilt themes which you can load from gr.themes.*
. You can extend these themes or create your own themes from scratch - see the Theming guide for more details.
For additional styling ability, you can pass any CSS to your app using the css=
kwarg.
The base class for the Gradio app is gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Blocks(css=\".gradio-container {background-color: red}\") as demo:\n ...\n
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with \"file=\"
, for example:
with gr.Blocks(css=\".gradio-container {background: url('file=clouds.jpg')}\") as demo:\n ...\n
You can also pass the filepath to a CSS file to the css
argument.
elem_id
and elem_classes
ArgumentsYou can elem_id
to add an HTML element id
to any component, and elem_classes
to add a class or list of classes. This will allow you to select elements more easily with CSS. This approach is also more likely to be stable across Gradio versions as built-in class names or ids may change (however, as mentioned in the warning above, we cannot guarantee complete compatibility between Gradio versions if you use custom CSS as the DOM elements may themselves change).
css = \"\"\"\n#warning {background-color: #FFCCCB} \n.feedback textarea {font-size: 24px !important}\n\"\"\"\n\nwith gr.Blocks(css=css) as demo:\n box1 = gr.Textbox(value=\"Good Job\", elem_classes=\"feedback\")\n box2 = gr.Textbox(value=\"Failure\", elem_id=\"warning\", elem_classes=\"feedback\")\n
The CSS #warning
ruleset will only target the second Textbox, while the .feedback
ruleset will target both. Note that when targeting classes, you might need to put the !important
selector to override the default Gradio styles.
Event listeners have a _js
argument that can take a Javascript function as a string and treat it just like a Python event listener function. You can pass both a Javascript function and a Python function (in which case the Javascript function is run first) or only Javascript (and set the Python fn
to None
). Take a look at the code below:
import gradio as gr\n\nblocks = gr.Blocks()\n\nwith blocks as demo:\n subject = gr.Textbox(placeholder=\"subject\")\n verb = gr.Radio([\"ate\", \"loved\", \"hated\"])\n object = gr.Textbox(placeholder=\"object\")\n\n with gr.Row():\n btn = gr.Button(\"Create sentence.\")\n reverse_btn = gr.Button(\"Reverse sentence.\")\n foo_bar_btn = gr.Button(\"Append foo\")\n reverse_then_to_the_server_btn = gr.Button(\n \"Reverse sentence and send to server.\"\n )\n\n def sentence_maker(w1, w2, w3):\n return f\"{w1} {w2} {w3}\"\n\n output1 = gr.Textbox(label=\"output 1\")\n output2 = gr.Textbox(label=\"verb\")\n output3 = gr.Textbox(label=\"verb reversed\")\n output4 = gr.Textbox(label=\"front end process and then send to backend\")\n\n btn.click(sentence_maker, [subject, verb, object], output1)\n reverse_btn.click(\n None, [subject, verb, object], output2, _js=\"(s, v, o) => o + ' ' + v + ' ' + s\"\n )\n verb.change(lambda x: x, verb, output3, _js=\"(x) => [...x].reverse().join('')\")\n foo_bar_btn.click(None, [], subject, _js=\"(x) => x + ' foo'\")\n\n reverse_then_to_the_server_btn.click(\n sentence_maker,\n [subject, verb, object],\n output4,\n _js=\"(s, v, o) => [s, v, o].map(x => [...x].reverse().join(''))\",\n )\n\ndemo.launch()\n\n
Prerequisite: This Guide requires you to know about Blocks and the interpretation feature of Interfaces.\nMake sure to read the Guide to Blocks first as well as the\ninterpretation section of the Advanced Interface Features Guide.
\n\nIf you have experience working with the Interface class, then you know that interpreting the prediction of your machine learning model\nis as easy as setting the interpretation
parameter to either \"default\" or \"shap\".
You may be wondering if it is possible to add the same interpretation functionality to an app built with the Blocks API.\nNot only is it possible, but the flexibility of Blocks lets you display the interpretation output in ways that are\nimpossible to do with Interfaces!
\n\nThis guide will show how to:
\n\nLet's get started!
\n\nLet's build a sentiment classification app with the Blocks API.\nThis app will take text as input and output the probability that this text expresses either negative or positive sentiment.\nWe'll have a single input Textbox
and a single output Label
component.\nBelow is the code for the app as well as the app itself.
import gradio as gr \nfrom transformers import pipeline\n\nsentiment_classifier = pipeline(\"text-classification\", return_all_scores=True)\n\ndef classifier(text):\n pred = sentiment_classifier(text)\n return {p[\"label\"]: p[\"score\"] for p in pred[0]}\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n\n classify.click(classifier, input_text, label)\ndemo.launch()\n
Our goal is to present to our users how the words in the input contribute to the model's prediction.\nThis will help our users understand how the model works and also evaluate its effectiveness.\nFor example, we should expect our model to identify the words \"happy\" and \"love\" with positive sentiment - if not it's a sign we made a mistake in training it!
\n\nFor each word in the input, we will compute a score of how much the model's prediction of positive sentiment is changed by that word.\nOnce we have those (word, score)
pairs we can use gradio to visualize them for the user.
The shap library will help us compute the (word, score)
pairs and\ngradio will take care of displaying the output to the user.
The following code computes the (word, score)
pairs:
def interpretation_function(text):\n explainer = shap.Explainer(sentiment_classifier)\n shap_values = explainer([text])\n\n # Dimensions are (batch size, text size, number of classes)\n # Since we care about positive sentiment, use index 1\n scores = list(zip(shap_values.data[0], shap_values.values[0, :, 1]))\n # Scores contains (word, score) pairs\n\n\n # Format expected by gr.components.Interpretation\n return {\"original\": text, \"interpretation\": scores}\n
Now, all we have to do is add a button that runs this function when clicked.\nTo display the interpretation, we will use gr.components.Interpretation
.\nThis will color each word in the input either red or blue.\nRed if it contributes to positive sentiment and blue if it contributes to negative sentiment.\nThis is how Interface
displays the interpretation output for text.
with gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n interpret = gr.Button(\"Interpret\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n with gr.Column():\n interpretation = gr.components.Interpretation(input_text)\n classify.click(classifier, input_text, label)\n interpret.click(interpretation_function, input_text, interpretation)\n\ndemo.launch()\n
The gr.components.Interpretation
component does a good job of showing how individual words contribute to the sentiment prediction,\nbut what if we also wanted to display the score themselves along with the words?
One way to do this would be to generate a bar plot where the words are on the horizontal axis and the bar height corresponds\nto the shap score.
\n\nWe can do this by modifying our interpretation_function
to additionally return a matplotlib bar plot.\nWe will display it with the gr.Plot
component in a separate tab.
This is how the interpretation function will look:
\n\ndef interpretation_function(text):\n explainer = shap.Explainer(sentiment_classifier)\n shap_values = explainer([text])\n # Dimensions are (batch size, text size, number of classes)\n # Since we care about positive sentiment, use index 1\n scores = list(zip(shap_values.data[0], shap_values.values[0, :, 1]))\n\n scores_desc = sorted(scores, key=lambda t: t[1])[::-1]\n\n # Filter out empty string added by shap\n scores_desc = [t for t in scores_desc if t[0] != \"\"]\n\n fig_m = plt.figure()\n\n # Select top 5 words that contribute to positive sentiment\n plt.bar(x=[s[0] for s in scores_desc[:5]],\n height=[s[1] for s in scores_desc[:5]])\n plt.title(\"Top words contributing to positive sentiment\")\n plt.ylabel(\"Shap Value\")\n plt.xlabel(\"Word\")\n return {\"original\": text, \"interpretation\": scores}, fig_m\n
And this is how the app code will look:
\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n interpret = gr.Button(\"Interpret\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n with gr.Column():\n with gr.Tabs():\n with gr.TabItem(\"Display interpretation with built-in component\"):\n interpretation = gr.components.Interpretation(input_text)\n with gr.TabItem(\"Display interpretation with plot\"):\n interpretation_plot = gr.Plot()\n\n classify.click(classifier, input_text, label)\n interpret.click(interpretation_function, input_text, [interpretation, interpretation_plot])\n\ndemo.launch()\n
You can see the demo below!
\n\nAlthough we have focused on sentiment classification so far, you can add interpretations to almost any machine learning model.\nThe output must be an gr.Image
or gr.Label
but the input can be almost anything (gr.Number
, gr.Slider
, gr.Radio
, gr.Image
).
Here is a demo built with blocks of interpretations for an image classification model:
\n\nWe did a deep dive \ud83e\udd3f into how interpretations work and how you can add them to your Blocks app.
\n\nWe also showed how the Blocks API gives you the power to control how the interpretation is visualized in your app.
\n\nAdding interpretations is a helpful way to make your users understand and gain trust in your model.\nNow you have all the tools you need to add them to all of your apps!
\n", "tags": ["INTERPRETATION", "SENTIMENT ANALYSIS"], "spaces": [], "url": "/guides/custom-interpretations-with-blocks/", "contributor": null}, {"name": "using-blocks-like-functions", "category": "building-with-blocks", "pretty_category": "Building With Blocks", "guide_index": 5, "absolute_index": 12, "pretty_name": "Using Blocks Like Functions", "content": "# Using Gradio Blocks Like Functions\n\n\n\n**Prerequisite**: This Guide builds on the Blocks Introduction. Make sure to [read that guide first](https://gradio.app/guides/quickstart/#blocks-more-flexibility-and-control).\n\n## Introduction\n\nDid you know that apart from being a full-stack machine learning demo, a Gradio Blocks app is also a regular-old python function!?\n\nThis means that if you have a gradio Blocks (or Interface) app called `demo`, you can use `demo` like you would any python function.\n\nSo doing something like `output = demo(\"Hello\", \"friend\")` will run the first event defined in `demo` on the inputs \"Hello\" and \"friend\" and store it\nin the variable `output`.\n\nIf I put you to sleep \ud83e\udd71, please bear with me! By using apps like functions, you can seamlessly compose Gradio apps.\nThe following section will show how.\n\n## Treating Blocks like functions\n\nLet's say we have the following demo that translates english text to german text. \n\n```python\nimport gradio as gr\n\nfrom transformers import pipeline\n\npipe = pipeline(\"translation\", model=\"t5-base\")\n\n\ndef translate(text):\n return pipe(text)[0][\"translation_text\"]\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n english = gr.Textbox(label=\"English text\")\n translate_btn = gr.Button(value=\"Translate\")\n with gr.Column():\n german = gr.Textbox(label=\"German Text\")\n\n translate_btn.click(translate, inputs=english, outputs=german, api_name=\"translate-to-german\")\n examples = gr.Examples(examples=[\"I went to the supermarket yesterday.\", \"Helen is a good swimmer.\"],\n inputs=[english])\n\ndemo.launch()\n```\n\nI already went ahead and hosted it in Hugging Face spaces at [gradio/english_translator](https://huggingface.co/spaces/gradio/english_translator).\n\nYou can see the demo below as well:\n\nPrerequisite: This Guide builds on the Blocks Introduction. Make sure to read that guide first.
\n\nDid you know that apart from being a full-stack machine learning demo, a Gradio Blocks app is also a regular-old python function!?
\n\nThis means that if you have a gradio Blocks (or Interface) app called demo
, you can use demo
like you would any python function.
So doing something like output = demo(\"Hello\", \"friend\")
will run the first event defined in demo
on the inputs \"Hello\" and \"friend\" and store it\nin the variable output
.
If I put you to sleep \ud83e\udd71, please bear with me! By using apps like functions, you can seamlessly compose Gradio apps.\nThe following section will show how.
\n\nLet's say we have the following demo that translates english text to german text.
\n\nimport gradio as gr\n\nfrom transformers import pipeline\n\npipe = pipeline(\"translation\", model=\"t5-base\")\n\n\ndef translate(text):\n return pipe(text)[0][\"translation_text\"]\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n english = gr.Textbox(label=\"English text\")\n translate_btn = gr.Button(value=\"Translate\")\n with gr.Column():\n german = gr.Textbox(label=\"German Text\")\n\n translate_btn.click(translate, inputs=english, outputs=german, api_name=\"translate-to-german\")\n examples = gr.Examples(examples=[\"I went to the supermarket yesterday.\", \"Helen is a good swimmer.\"],\n inputs=[english])\n\ndemo.launch()\n
I already went ahead and hosted it in Hugging Face spaces at gradio/english_translator.
\n\nYou can see the demo below as well:
\n\nNow, let's say you have an app that generates english text, but you wanted to additionally generate german text.
\n\nYou could either:
\n\nCopy the source code of my english-to-german translation and paste it in your app.
Load my english-to-german translation in your app and treat it like a normal python function.
Option 1 technically always works, but it often introduces unwanted complexity.
\n\nOption 2 lets you borrow the functionality you want without tightly coupling our apps.
\n\nAll you have to do is call the Blocks.load
class method in your source file.\nAfter that, you can use my translation app like a regular python function!
The following code snippet and demo shows how to use Blocks.load
.
Note that the variable english_translator
is my english to german app, but its used in generate_text
like a regular function.
import gradio as gr\n\nfrom transformers import pipeline\n\nenglish_translator = gr.Blocks.load(name=\"spaces/gradio/english_translator\")\nenglish_generator = pipeline(\"text-generation\", model=\"distilgpt2\")\n\n\ndef generate_text(text):\n english_text = english_generator(text)[0][\"generated_text\"]\n german_text = english_translator(english_text)\n return english_text, german_text\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n seed = gr.Text(label=\"Input Phrase\")\n with gr.Column():\n english = gr.Text(label=\"Generated English Text\")\n german = gr.Text(label=\"Generated German Text\")\n btn = gr.Button(\"Generate\")\n btn.click(generate_text, inputs=[seed], outputs=[english, german])\n gr.Examples([\"My name is Clara and I am\"], inputs=[seed])\n\ndemo.launch()\n
If the app you are loading defines more than one function, you can specify which function to use\nwith the fn_index
and api_name
parameters.
In the code for our english to german demo, you'll see the following line:
\n\ntranslate_btn.click(translate, inputs=english, outputs=german, api_name=\"translate-to-german\")\n
The api_name
gives this function a unique name in our app. You can use this name to tell gradio which\nfunction in the upstream space you want to use:
english_generator(text, api_name=\"translate-to-german\")[0][\"generated_text\"]\n
You can also use the fn_index
parameter.\nImagine my app also defined an english to spanish translation function.\nIn order to use it in our text generation app, we would use the following code:
english_generator(text, fn_index=1)[0][\"generated_text\"]\n
Functions in gradio spaces are zero-indexed, so since the spanish translator would be the second function in my space,\nyou would use index 1.
\n\nWe showed how treating a Blocks app like a regular python helps you compose functionality across different apps.\nAny Blocks app can be treated like a function, but a powerful pattern is to load
an app hosted on \nHugging Face Spaces prior to treating it like a function in your own app.\nYou can also load models hosted on the Hugging Face Model Hub - see the Using Hugging Face Integrations guide for an example.
By default, Components in Blocks are arranged vertically. Let's take a look at how we can rearrange Components. Under the hood, this layout structure uses the flexbox model of web development.
\n\nElements within a with gr.Row
clause will all be displayed horizontally. For example, to display two Buttons side by side:
with gr.Blocks() as demo:\n with gr.Row():\n btn1 = gr.Button(\"Button 1\")\n btn2 = gr.Button(\"Button 2\")\n
To make every element in a Row have the same height, use the equal_height
argument of the style
method.
with gr.Blocks() as demo:\n with gr.Row().style(equal_height=True):\n textbox = gr.Textbox()\n btn2 = gr.Button(\"Button 2\")\n
The widths of elements in a Row can be controlled via a combination of scale
and min_width
arguments that are present in every Component.
scale
is an integer that defines how an element will take up space in a Row. If scale is set to 0
, and element will not expand to take up space. If scale is set to 1
or greater, the element well expand. Multiple elements in a row will expand proportional to their scale. Below, btn1
will expand twice as much as btn2
, while btn0
will not expand at all:with gr.Blocks() as demo:\n with gr.Row():\n btn0 = gr.Button(\"Button 0\", scale=0)\n btn1 = gr.Button(\"Button 1\", scale=1)\n btn2 = gr.Button(\"Button 2\", scale=2)\n
min_width
will set the minimum width the element will take. The Row will wrap if there isn't sufficient space to satisfy all min_width
values.Learn more about Rows in the docs.
\n\nComponents within a Column will be placed vertically atop each other. Since the vertical layout is the default layout for Blocks apps anyway, to be useful, Columns are usually nested within Rows. For example:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n text1 = gr.Textbox(label=\"t1\")\n slider2 = gr.Textbox(label=\"s2\")\n drop3 = gr.Dropdown([\"a\", \"b\", \"c\"], label=\"d3\")\n with gr.Row():\n with gr.Column(scale=1, min_width=600):\n text1 = gr.Textbox(label=\"prompt 1\")\n text2 = gr.Textbox(label=\"prompt 2\")\n inbtw = gr.Button(\"Between\")\n text4 = gr.Textbox(label=\"prompt 1\")\n text5 = gr.Textbox(label=\"prompt 2\")\n with gr.Column(scale=2, min_width=600):\n img1 = gr.Image(\"images/cheetah.jpg\")\n btn = gr.Button(\"Go\").style(full_width=True)\n\ndemo.launch()\n
See how the first column has two Textboxes arranged vertically. The second column has an Image and Button arranged vertically. Notice how the relative widths of the two columns is set by the scale
parameter. The column with twice the scale
value takes up twice the width.
Learn more about Columns in the docs.
\n\nYou can also create Tabs using the with gr.Tab('tab_name'):
clause. Any component created inside of a with gr.Tab('tab_name'):
context appears in that tab. Consecutive Tab clauses are grouped together so that a single tab can be selected at one time, and only the components within that Tab's context are shown.
For example:
\n\nimport numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
Also note the gr.Accordion('label')
in this example. The Accordion is a layout that can be toggled open or closed. Like Tabs
, it is a layout element that can selectively hide or show content. Any components that are defined inside of a with gr.Accordion('label'):
will be hidden or shown when the accordion's toggle icon is clicked.
Learn more about Tabs and Accordions in the docs.
\n\nBoth Components and Layout elements have a visible
argument that can set initially and also updated using gr.update()
. Setting gr.update(visible=...)
on a Column can be used to show or hide a set of Components.
import gradio as gr\n\nwith gr.Blocks() as demo:\n error_box = gr.Textbox(label=\"Error\", visible=False)\n\n name_box = gr.Textbox(label=\"Name\")\n age_box = gr.Number(label=\"Age\", minimum=0, maximum=100)\n symptoms_box = gr.CheckboxGroup([\"Cough\", \"Fever\", \"Runny Nose\"])\n submit_btn = gr.Button(\"Submit\")\n\n with gr.Column(visible=False) as output_col:\n diagnosis_box = gr.Textbox(label=\"Diagnosis\")\n patient_summary_box = gr.Textbox(label=\"Patient Summary\")\n\n def submit(name, age, symptoms):\n if len(name) == 0:\n return {error_box: gr.update(value=\"Enter name\", visible=True)}\n return {\n output_col: gr.update(visible=True),\n diagnosis_box: \"covid\" if \"Cough\" in symptoms else \"flu\",\n patient_summary_box: f\"{name}, {age} y/o\",\n }\n\n submit_btn.click(\n submit,\n [name_box, age_box, symptoms_box],\n [error_box, diagnosis_box, patient_summary_box, output_col],\n )\n\ndemo.launch()\n\n
By adjusting the visibility of components in a dynamic way, it is possible to create\ndemos with Gradio that support a variable numbers of outputs. Here's a very simple example\nwhere the number of output textboxes is controlled by an input slider:
\n\nimport gradio as gr\n\nmax_textboxes = 10\n\ndef variable_outputs(k):\n k = int(k)\n return [gr.Textbox.update(visible=True)]*k + [gr.Textbox.update(visible=False)]*(max_textboxes-k)\n\nwith gr.Blocks() as demo:\n s = gr.Slider(1, max_textboxes, value=max_textboxes, step=1, label=\"How many textboxes to show:\")\n textboxes = []\n for i in range(max_textboxes):\n t = gr.Textbox(f\"Textbox {i}\")\n textboxes.append(t)\n\n s.change(variable_outputs, s, textboxes)\n\nif __name__ == \"__main__\":\n demo.launch()\n\n
In some cases, you might want to define components before you actually render them in your UI. For instance, you might want to show an examples section using gr.Examples
above the corresponding gr.Textbox
input. Since gr.Examples
requires as a parameter the input component object, you will need to first define the input component, but then render it later, after you have defined the gr.Examples
object.
The solution to this is to define the gr.Textbox
outside of the gr.Blocks()
scope and use the component's .render()
method wherever you'd like it placed in the UI.
Here's a full code example:
\n\ninput_textbox = gr.Textbox()\n\nwith gr.Blocks() as demo:\n gr.Examples([\"hello\", \"bonjour\", \"merhaba\"], input_textbox)\n input_textbox.render()\n
By default, Components in Blocks are arranged vertically. Let's take a look at how we can rearrange Components. Under the hood, this layout structure uses the flexbox model of web development.
\n\nElements within a with gr.Row
clause will all be displayed horizontally. For example, to display two Buttons side by side:
with gr.Blocks() as demo:\n with gr.Row():\n btn1 = gr.Button(\"Button 1\")\n btn2 = gr.Button(\"Button 2\")\n
To make every element in a Row have the same height, use the equal_height
argument of the style
method.
with gr.Blocks() as demo:\n with gr.Row().style(equal_height=True):\n textbox = gr.Textbox()\n btn2 = gr.Button(\"Button 2\")\n
The widths of elements in a Row can be controlled via a combination of scale
and min_width
arguments that are present in every Component.
scale
is an integer that defines how an element will take up space in a Row. If scale is set to 0
, and element will not expand to take up space. If scale is set to 1
or greater, the element well expand. Multiple elements in a row will expand proportional to their scale. Below, btn1
will expand twice as much as btn2
, while btn0
will not expand at all:with gr.Blocks() as demo:\n with gr.Row():\n btn0 = gr.Button(\"Button 0\", scale=0)\n btn1 = gr.Button(\"Button 1\", scale=1)\n btn2 = gr.Button(\"Button 2\", scale=2)\n
min_width
will set the minimum width the element will take. The Row will wrap if there isn't sufficient space to satisfy all min_width
values.Learn more about Rows in the docs.
\n\nComponents within a Column will be placed vertically atop each other. Since the vertical layout is the default layout for Blocks apps anyway, to be useful, Columns are usually nested within Rows. For example:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n text1 = gr.Textbox(label=\"t1\")\n slider2 = gr.Textbox(label=\"s2\")\n drop3 = gr.Dropdown([\"a\", \"b\", \"c\"], label=\"d3\")\n with gr.Row():\n with gr.Column(scale=1, min_width=600):\n text1 = gr.Textbox(label=\"prompt 1\")\n text2 = gr.Textbox(label=\"prompt 2\")\n inbtw = gr.Button(\"Between\")\n text4 = gr.Textbox(label=\"prompt 1\")\n text5 = gr.Textbox(label=\"prompt 2\")\n with gr.Column(scale=2, min_width=600):\n img1 = gr.Image(\"images/cheetah.jpg\")\n btn = gr.Button(\"Go\").style(full_width=True)\n\ndemo.launch()\n
See how the first column has two Textboxes arranged vertically. The second column has an Image and Button arranged vertically. Notice how the relative widths of the two columns is set by the scale
parameter. The column with twice the scale
value takes up twice the width.
Learn more about Columns in the docs.
\n\nYou can also create Tabs using the with gr.Tab('tab_name'):
clause. Any component created inside of a with gr.Tab('tab_name'):
context appears in that tab. Consecutive Tab clauses are grouped together so that a single tab can be selected at one time, and only the components within that Tab's context are shown.
For example:
\n\nimport numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
Also note the gr.Accordion('label')
in this example. The Accordion is a layout that can be toggled open or closed. Like Tabs
, it is a layout element that can selectively hide or show content. Any components that are defined inside of a with gr.Accordion('label'):
will be hidden or shown when the accordion's toggle icon is clicked.
Learn more about Tabs and Accordions in the docs.
\n\nBoth Components and Layout elements have a visible
argument that can set initially and also updated using gr.update()
. Setting gr.update(visible=...)
on a Column can be used to show or hide a set of Components.
import gradio as gr\n\nwith gr.Blocks() as demo:\n error_box = gr.Textbox(label=\"Error\", visible=False)\n\n name_box = gr.Textbox(label=\"Name\")\n age_box = gr.Number(label=\"Age\", minimum=0, maximum=100)\n symptoms_box = gr.CheckboxGroup([\"Cough\", \"Fever\", \"Runny Nose\"])\n submit_btn = gr.Button(\"Submit\")\n\n with gr.Column(visible=False) as output_col:\n diagnosis_box = gr.Textbox(label=\"Diagnosis\")\n patient_summary_box = gr.Textbox(label=\"Patient Summary\")\n\n def submit(name, age, symptoms):\n if len(name) == 0:\n return {error_box: gr.update(value=\"Enter name\", visible=True)}\n return {\n output_col: gr.update(visible=True),\n diagnosis_box: \"covid\" if \"Cough\" in symptoms else \"flu\",\n patient_summary_box: f\"{name}, {age} y/o\",\n }\n\n submit_btn.click(\n submit,\n [name_box, age_box, symptoms_box],\n [error_box, diagnosis_box, patient_summary_box, output_col],\n )\n\ndemo.launch()\n\n
By adjusting the visibility of components in a dynamic way, it is possible to create\ndemos with Gradio that support a variable numbers of outputs. Here's a very simple example\nwhere the number of output textboxes is controlled by an input slider:
\n\nimport gradio as gr\n\nmax_textboxes = 10\n\ndef variable_outputs(k):\n k = int(k)\n return [gr.Textbox.update(visible=True)]*k + [gr.Textbox.update(visible=False)]*(max_textboxes-k)\n\nwith gr.Blocks() as demo:\n s = gr.Slider(1, max_textboxes, value=max_textboxes, step=1, label=\"How many textboxes to show:\")\n textboxes = []\n for i in range(max_textboxes):\n t = gr.Textbox(f\"Textbox {i}\")\n textboxes.append(t)\n\n s.change(variable_outputs, s, textboxes)\n\nif __name__ == \"__main__\":\n demo.launch()\n\n
In some cases, you might want to define components before you actually render them in your UI. For instance, you might want to show an examples section using gr.Examples
above the corresponding gr.Textbox
input. Since gr.Examples
requires as a parameter the input component object, you will need to first define the input component, but then render it later, after you have defined the gr.Examples
object.
The solution to this is to define the gr.Textbox
outside of the gr.Blocks()
scope and use the component's .render()
method wherever you'd like it placed in the UI.
Here's a full code example:
\n\ninput_textbox = gr.Textbox()\n\nwith gr.Blocks() as demo:\n gr.Examples([\"hello\", \"bonjour\", \"merhaba\"], input_textbox)\n input_textbox.render()\n
By default, Components in Blocks are arranged vertically. Let's take a look at how we can rearrange Components. Under the hood, this layout structure uses the flexbox model of web development.
\n\nElements within a with gr.Row
clause will all be displayed horizontally. For example, to display two Buttons side by side:
with gr.Blocks() as demo:\n with gr.Row():\n btn1 = gr.Button(\"Button 1\")\n btn2 = gr.Button(\"Button 2\")\n
To make every element in a Row have the same height, use the equal_height
argument of the style
method.
with gr.Blocks() as demo:\n with gr.Row().style(equal_height=True):\n textbox = gr.Textbox()\n btn2 = gr.Button(\"Button 2\")\n
The widths of elements in a Row can be controlled via a combination of scale
and min_width
arguments that are present in every Component.
scale
is an integer that defines how an element will take up space in a Row. If scale is set to 0
, and element will not expand to take up space. If scale is set to 1
or greater, the element well expand. Multiple elements in a row will expand proportional to their scale. Below, btn1
will expand twice as much as btn2
, while btn0
will not expand at all:with gr.Blocks() as demo:\n with gr.Row():\n btn0 = gr.Button(\"Button 0\", scale=0)\n btn1 = gr.Button(\"Button 1\", scale=1)\n btn2 = gr.Button(\"Button 2\", scale=2)\n
min_width
will set the minimum width the element will take. The Row will wrap if there isn't sufficient space to satisfy all min_width
values.Learn more about Rows in the docs.
\n\nComponents within a Column will be placed vertically atop each other. Since the vertical layout is the default layout for Blocks apps anyway, to be useful, Columns are usually nested within Rows. For example:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n text1 = gr.Textbox(label=\"t1\")\n slider2 = gr.Textbox(label=\"s2\")\n drop3 = gr.Dropdown([\"a\", \"b\", \"c\"], label=\"d3\")\n with gr.Row():\n with gr.Column(scale=1, min_width=600):\n text1 = gr.Textbox(label=\"prompt 1\")\n text2 = gr.Textbox(label=\"prompt 2\")\n inbtw = gr.Button(\"Between\")\n text4 = gr.Textbox(label=\"prompt 1\")\n text5 = gr.Textbox(label=\"prompt 2\")\n with gr.Column(scale=2, min_width=600):\n img1 = gr.Image(\"images/cheetah.jpg\")\n btn = gr.Button(\"Go\").style(full_width=True)\n\ndemo.launch()\n
See how the first column has two Textboxes arranged vertically. The second column has an Image and Button arranged vertically. Notice how the relative widths of the two columns is set by the scale
parameter. The column with twice the scale
value takes up twice the width.
Learn more about Columns in the docs.
\n\nYou can also create Tabs using the with gr.Tab('tab_name'):
clause. Any component created inside of a with gr.Tab('tab_name'):
context appears in that tab. Consecutive Tab clauses are grouped together so that a single tab can be selected at one time, and only the components within that Tab's context are shown.
For example:
\n\nimport numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
Also note the gr.Accordion('label')
in this example. The Accordion is a layout that can be toggled open or closed. Like Tabs
, it is a layout element that can selectively hide or show content. Any components that are defined inside of a with gr.Accordion('label'):
will be hidden or shown when the accordion's toggle icon is clicked.
Learn more about Tabs and Accordions in the docs.
\n\nBoth Components and Layout elements have a visible
argument that can set initially and also updated using gr.update()
. Setting gr.update(visible=...)
on a Column can be used to show or hide a set of Components.
import gradio as gr\n\nwith gr.Blocks() as demo:\n error_box = gr.Textbox(label=\"Error\", visible=False)\n\n name_box = gr.Textbox(label=\"Name\")\n age_box = gr.Number(label=\"Age\", minimum=0, maximum=100)\n symptoms_box = gr.CheckboxGroup([\"Cough\", \"Fever\", \"Runny Nose\"])\n submit_btn = gr.Button(\"Submit\")\n\n with gr.Column(visible=False) as output_col:\n diagnosis_box = gr.Textbox(label=\"Diagnosis\")\n patient_summary_box = gr.Textbox(label=\"Patient Summary\")\n\n def submit(name, age, symptoms):\n if len(name) == 0:\n return {error_box: gr.update(value=\"Enter name\", visible=True)}\n return {\n output_col: gr.update(visible=True),\n diagnosis_box: \"covid\" if \"Cough\" in symptoms else \"flu\",\n patient_summary_box: f\"{name}, {age} y/o\",\n }\n\n submit_btn.click(\n submit,\n [name_box, age_box, symptoms_box],\n [error_box, diagnosis_box, patient_summary_box, output_col],\n )\n\ndemo.launch()\n\n
By adjusting the visibility of components in a dynamic way, it is possible to create\ndemos with Gradio that support a variable numbers of outputs. Here's a very simple example\nwhere the number of output textboxes is controlled by an input slider:
\n\nimport gradio as gr\n\nmax_textboxes = 10\n\ndef variable_outputs(k):\n k = int(k)\n return [gr.Textbox.update(visible=True)]*k + [gr.Textbox.update(visible=False)]*(max_textboxes-k)\n\nwith gr.Blocks() as demo:\n s = gr.Slider(1, max_textboxes, value=max_textboxes, step=1, label=\"How many textboxes to show:\")\n textboxes = []\n for i in range(max_textboxes):\n t = gr.Textbox(f\"Textbox {i}\")\n textboxes.append(t)\n\n s.change(variable_outputs, s, textboxes)\n\nif __name__ == \"__main__\":\n demo.launch()\n\n
In some cases, you might want to define components before you actually render them in your UI. For instance, you might want to show an examples section using gr.Examples
above the corresponding gr.Textbox
input. Since gr.Examples
requires as a parameter the input component object, you will need to first define the input component, but then render it later, after you have defined the gr.Examples
object.
The solution to this is to define the gr.Textbox
outside of the gr.Blocks()
scope and use the component's .render()
method wherever you'd like it placed in the UI.
Here's a full code example:
\n\ninput_textbox = gr.Textbox()\n\nwith gr.Blocks() as demo:\n gr.Examples([\"hello\", \"bonjour\", \"merhaba\"], input_textbox)\n input_textbox.render()\n
Chatbots are a popular application of large language models. Using gradio
, you can easily build a demo of your chatbot model and share that with your users, or try it yourself using an intuitive chatbot UI.
This tutorial uses gr.ChatInterface()
, which is a high-level abstraction that allows you to create your chatbot UI fast, often with a single line of code. The chatbot interface that we create will look something like this:
We'll start with a couple of simple examples, and then show how to use gr.ChatInterface()
with real language models from several popular APIs and libraries, including langchain
, openai
, and Hugging Face.
Prerequisites: please make sure you are using the latest version version of Gradio:
\n\n$ pip install --upgrade gradio\n
When working with gr.ChatInterface()
, the first thing you should do is define your chat function. Your chat function should take two arguments: message
and then history
(the arguments can be named anything, but must be in this order).
message
: a str
representing the user's input.history
: a list
of list
representing the conversations up until that point. Each inner list consists of two str
representing a pair: [user input, bot response]
. Your function should return a single string response, which is the bot's response to the particular user input message
. Your function can take into account the history
of messages, as well as the current message.
Let's take a look at a few examples.
\n\nLet's write a chat function that responds Yes
or No
randomly.
Here's our chat function:
\n\nimport random\n\ndef random_response(message, history):\n return random.choice([\"Yes\", \"No\"])\n
Now, we can plug this into gr.ChatInterface()
and call the .launch()
method to create the web interface:
import gradio as gr\n\ngr.ChatInterface(random_response).launch()\n
That's it! Here's our running demo, try it out:
\n\nOf course, the previous example was very simplistic, it didn't even take user input or the previous history into account! Here's another simple example showing how to incorporate a user's input as well as the history.
\n\nimport random\nimport gradio as gr\n\ndef alternatingly_agree(message, history):\n if len(history) % 2 == 0:\n return f\"Yes, I do think that '{message}'\"\n else:\n return \"I don't think so\"\n\ngr.ChatInterface(alternatingly_agree).launch()\n
If in your chat function, you use yield
to generate a sequence of responses, you'll end up with a streaming chatbot. It's that simple!
import time\nimport gradio as gr\n\ndef slow_echo(message, history):\n for i in range(len(message)):\n time.sleep(0.3)\n yield \"You typed: \" + message[: i+1]\n\ngr.ChatInterface(slow_echo).queue().launch()\n
Notice that we've enabled queuing, which is required to use generator functions. While the response is streaming, the \"Submit\" button turns into a \"Stop\" button that can be used to stop the generator function. You can customize the appearance and behavior of the \"Stop\" button using the stop_btn
parameter.
If you're familiar with Gradio's Interface
class, the gr.ChatInterface
includes many of the same arguments that you can use to customize the look and feel of your Chatbot. For example, you can:
title
and description
arguments.theme
and css
arguments respectively.examples
and even enable cache_examples
, which make it easier for users to try it out .submit_btn
, retry_btn
, undo_btn
, clear_btn
.If you want to customize the gr.Chatbot
or gr.Textbox
that compose the ChatInterface
, then you can pass in your own chatbot or textbox as well. Here's an example of how we can use these parameters:
import gradio as gr\n\ndef yes_man(message, history):\n if message.endswith(\"?\"):\n return \"Yes\"\n else:\n return \"Ask me anything!\"\n\ngr.ChatInterface(\n yes_man,\n chatbot=gr.Chatbot(height=300),\n textbox=gr.Textbox(placeholder=\"Ask me a yes or no question\", container=False, scale=7),\n title=\"Yes Man\",\n description=\"Ask Yes Man any question\",\n theme=\"soft\",\n examples=[\"Hello\", \"Am I cool?\", \"Are tomatoes vegetables?\"],\n cache_examples=True,\n retry_btn=None,\n undo_btn=\"Delete Previous\",\n clear_btn=\"Clear\",\n).launch()\n
You may want to add additional parameters to your chatbot and expose them to your users through the Chatbot UI. For example, suppose you want to add a textbox for a system prompt, or a slider that sets the number of tokens in the chatbot's response. The ChatInterface
class supports an additional_inputs
parameter which can be used to add additional input components.
The additional_inputs
parameters accepts a component or a list of components. You can pass the component instances directly, or use their string shortcuts (e.g. \"textbox\"
instead of gr.Textbox()
). If you pass in component instances, and they have not already been rendered, then the components will appear underneath the chatbot (and any examples) within a gr.Accordion()
. You can set the label of this accordion using the additional_inputs_accordion_name
parameter.
Here's a complete example:
\n\nimport gradio as gr\nimport time\n\ndef echo(message, history, system_prompt, tokens):\n response = f\"System prompt: {system_prompt}\\n Message: {message}.\"\n for i in range(min(len(response), int(tokens))):\n time.sleep(0.05)\n yield response[: i+1]\n\ndemo = gr.ChatInterface(echo, \n additional_inputs=[\n gr.Textbox(\"You are helpful AI.\", label=\"System Prompt\"), \n gr.Slider(10, 100)\n ]\n )\n\nif __name__ == \"__main__\":\n demo.queue().launch()\n
If the components you pass into the additional_inputs
have already been rendered in a parent gr.Blocks()
, then they will not be re-rendered in the accordion. This provides flexibility in deciding where to lay out the input components. In the example below, we position the gr.Textbox()
on top of the Chatbot UI, while keeping the slider underneath.
import gradio as gr\nimport time\n\ndef echo(message, history, system_prompt, tokens):\n response = f\"System prompt: {system_prompt}\\n Message: {message}.\"\n for i in range(min(len(response), int(tokens))):\n time.sleep(0.05)\n yield response[: i+1]\n\nwith gr.Blocks() as demo:\n system_prompt = gr.Textbox(\"You are helpful AI.\", label=\"System Prompt\")\n slider = gr.Slider(10, 100, render=False)\n\n gr.ChatInterface(\n echo, additional_inputs=[system_prompt, slider]\n )\n\ndemo.queue().launch()\n
If you need to create something even more custom, then its best to construct the chatbot UI using the low-level gr.Blocks()
API. We have a dedicated guide for that here.
Once you've built your Gradio chatbot and are hosting it on Hugging Face Spaces or somewhere else, then you can query it with a simple API at the /chat
endpoint. The endpoint just expects the user's message (and potentially additional inputs if you have set any using the additional_inputs
parameter), and will return the response, internally keeping track of the messages sent so far.
To use the endpoint, you should use either the Gradio Python Client or the Gradio JS client.
\n\nlangchain
exampleNow, let's actually use the gr.ChatInterface
with some real large language models. We'll start by using langchain
on top of openai
to build a general-purpose streaming chatbot application in 19 lines of code. You'll need to have an OpenAI key for this example (keep reading for the free, open-source equivalent!)
from langchain.chat_models import ChatOpenAI\nfrom langchain.schema import AIMessage, HumanMessage\nimport openai\nimport gradio as gr\n\nos.envrion[\"OPENAI_API_KEY\"] = \"sk-...\" # Replace with your key\n\nllm = ChatOpenAI(temperature=1.0, model='gpt-3.5-turbo-0613')\n\ndef predict(message, history):\n history_langchain_format = []\n for human, ai in history:\n history_langchain_format.append(HumanMessage(content=human))\n history_langchain_format.append(AIMessage(content=ai))\n history_langchain_format.append(HumanMessage(content=message))\n gpt_response = llm(history_langchain_format)\n return gpt_response.content\n\ngr.ChatInterface(predict).launch() \n
openai
Of course, we could also use the openai
library directy. Here a similar example, but this time with streaming results as well:
import openai\nimport gradio as gr\n\nopenai.api_key = \"sk-...\" # Replace with your key\n\ndef predict(message, history):\n history_openai_format = []\n for human, assistant in history:\n history_openai_format.append({\"role\": \"user\", \"content\": human })\n history_openai_format.append({\"role\": \"assistant\", \"content\":assistant})\n history_openai_format.append({\"role\": \"user\", \"content\": message})\n\n response = openai.ChatCompletion.create(\n model='gpt-3.5-turbo',\n messages= history_openai_format, \n temperature=1.0,\n stream=True\n )\n\n partial_message = \"\"\n for chunk in response:\n if len(chunk['choices'][0]['delta']) != 0:\n partial_message = partial_message + chunk['choices'][0]['delta']['content']\n yield partial_message \n\ngr.ChatInterface(predict).queue().launch() \n
Of course, in many cases you want to run a chatbot locally. Here's the equivalent example using Together's RedePajama model, from Hugging Face (this requires you to have a GPU with CUDA).
\n\nimport gradio as gr\nimport torch\nfrom transformers import AutoModelForCausalLM, AutoTokenizer, StoppingCriteria, StoppingCriteriaList, TextIteratorStreamer\nfrom threading import Thread\n\ntokenizer = AutoTokenizer.from_pretrained(\"togethercomputer/RedPajama-INCITE-Chat-3B-v1\")\nmodel = AutoModelForCausalLM.from_pretrained(\"togethercomputer/RedPajama-INCITE-Chat-3B-v1\", torch_dtype=torch.float16)\nmodel = model.to('cuda:0')\n\nclass StopOnTokens(StoppingCriteria):\n def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool:\n stop_ids = [29, 0]\n for stop_id in stop_ids:\n if input_ids[0][-1] == stop_id:\n return True\n return False\n\ndef predict(message, history): \n\n history_transformer_format = history + [[message, \"\"]]\n stop = StopOnTokens()\n\n messages = \"\".join([\"\".join([\"\\n:\"+item[0], \"\\n:\"+item[1]]) #curr_system_message + \n for item in history_transformer_format])\n\n model_inputs = tokenizer([messages], return_tensors=\"pt\").to(\"cuda\")\n streamer = TextIteratorStreamer(tokenizer, timeout=10., skip_prompt=True, skip_special_tokens=True)\n generate_kwargs = dict(\n model_inputs,\n streamer=streamer,\n max_new_tokens=1024,\n do_sample=True,\n top_p=0.95,\n top_k=1000,\n temperature=1.0,\n num_beams=1,\n stopping_criteria=StoppingCriteriaList([stop])\n )\n t = Thread(target=model.generate, kwargs=generate_kwargs)\n t.start()\n\n partial_message = \"\"\n for new_token in streamer:\n if new_token != '<':\n partial_message += new_token\n yield partial_message \n\n\ngr.ChatInterface(predict).queue().launch()\n
With those examples, you should be all set to create your own Gradio Chatbot demos soon! For building even more custom Chatbot applications, check out a dedicated guide using the low-level gr.Blocks()
API.
How to share your Gradio app:
\n\nGradio demos can be easily shared publicly by setting share=True
in the launch()
method. Like this:
demo.launch(share=True)\n
This generates a public, shareable link that you can send to anybody! When you send this link, the user on the other side can try out the model in their browser. Because the processing happens on your device (as long as your device stays on!), you don't have to worry about any packaging any dependencies. A share link usually looks something like this: XXXXX.gradio.app. Although the link is served through a Gradio URL, we are only a proxy for your local server, and do not store any data sent through your app.
\n\nKeep in mind, however, that these links are publicly accessible, meaning that anyone can use your model for prediction! Therefore, make sure not to expose any sensitive information through the functions you write, or allow any critical changes to occur on your device. If you set share=False
(the default, except in colab notebooks), only a local link is created, which can be shared by port-forwarding with specific users.
Share links expire after 72 hours.
\n\nIf you'd like to have a permanent link to your Gradio demo on the internet, use Hugging Face Spaces. Hugging Face Spaces provides the infrastructure to permanently host your machine learning model for free!
\n\nAfter you have created a free Hugging Face account, you have three methods to deploy your Gradio app to Hugging Face Spaces:
\n\nFrom terminal: run gradio deploy
in your app directory. The CLI will gather some basic metadata and then launch your app. To update your space, you can re-run this command or enable the Github Actions option to automatically update the Spaces on git push
.
From your browser: Drag and drop a folder containing your Gradio model and all related files here.
Connect Spaces with your Git repository and Spaces will pull the Gradio app from there. See this guide how to host on Hugging Face Spaces for more information.
Note: Some components, like gr.Image
, will display a \"Share\" button only on Spaces, so that users can share the generated output to the Discussions page of the Space easily. You can disable this with show_share_button
, such as gr.Image(show_share_button=False)
.
sharebutton=True\" />
\n\nOnce you have hosted your app on Hugging Face Spaces (or on your own server), you may want to embed the demo on a different website, such as your blog or your portfolio. Embedding an interactive demo allows people to try out the machine learning model that you have built, without needing to download or install anything \u2014 right in their browser! The best part is that you can embed interactive demos even in static websites, such as GitHub pages.
\n\nThere are two ways to embed your Gradio demos. You can find quick links to both options directly on the Hugging Face Space page, in the \"Embed this Space\" dropdown option:
\n\n\n\nWeb components typically offer a better experience to users than IFrames. Web components load lazily, meaning that they won't slow down the loading time of your website, and they automatically adjust their height based on the size of the Gradio app.
\n\nTo embed with Web Components:
\n\n\n
\n
element where you want to place the app. Set the src=
attribute to your Space's embed URL, which you can find in the \"Embed this Space\" button. For example:
\n
You can see examples of how web components look on the Gradio landing page.
\n\nYou can also customize the appearance and behavior of your web component with attributes that you pass into the <gradio-app>
tag:
src
: as we've seen, the src
attributes links to the URL of the hosted Gradio demo that you would like to embedspace
: an optional shorthand if your Gradio demo is hosted on Hugging Face Space. Accepts a username/space_name
instead of a full URL. Example: gradio/Echocardiogram-Segmentation
. If this attribute attribute is provided, then src
does not need to be provided.control_page_title
: a boolean designating whether the html title of the page should be set to the title of the Gradio app (by default \"false\"
)initial_height
: the initial height of the web component while it is loading the Gradio app, (by default \"300px\"
). Note that the final height is set based on the size of the Gradio app.container
: whether to show the border frame and information about where the Space is hosted (by default \"true\"
)info
: whether to show just the information about where the Space is hosted underneath the embedded app (by default \"true\"
)autoscroll
: whether to autoscroll to the output when prediction has finished (by default \"false\"
)eager
: whether to load the Gradio app as soon as the page loads (by default \"false\"
)theme_mode
: whether to use the dark
, light
, or default system
theme mode (by default \"system\"
)Here's an example of how to use these attributes to create a Gradio app that does not lazy load and has an initial height of 0px.
\n\n \n
Note: While Gradio's CSS will never impact the embedding page, the embedding page can affect the style of the embedded Gradio app. Make sure that any CSS in the parent page isn't so general that it could also apply to the embedded Gradio app and cause the styling to break. Element selectors such as header { ... }
and footer { ... }
will be the most likely to cause issues.
To embed with IFrames instead (if you cannot add javascript to your website, for example), add this element:
\n\n\n
Again, you can find the src=
attribute to your Space's embed URL, which you can find in the \"Embed this Space\" button.
Note: if you use IFrames, you'll probably want to add a fixed height
attribute and set style=\"border:0;\"
to remove the boreder. In addition, if your app requires permissions such as access to the webcam or the microphone, you'll need to provide that as well using the allow
attribute.
You can use almost any Gradio app as an API! In the footer of a Gradio app like this one, you'll see a \"Use via API\" link.
\n\n\n\nThis is a page that lists the endpoints that can be used to query the Gradio app, via our supported clients: either the Python client, or the JavaScript client. For each endpoint, Gradio automatically generates the parameters and their types, as well as example inputs.
\n\nThe endpoints are automatically created when you launch a Gradio Interface
. If you are using Gradio Blocks
, you can also set up a Gradio API page, though we recommend that you explicitly name each event listener, such as
btn.click(add, [num1, num2], output, api_name=\"addition\")\n
This will add and document the endpoint /api/addition/
to the automatically generated API page. Otherwise, your API endpoints will appear as \"unnamed\" endpoints.
Note: For Gradio apps in which queueing is enabled, users can bypass the queue if they make a POST request to your API endpoint. To disable this behavior, set api_open=False
in the queue()
method. To disable the API page altogether, set show_api=False
in .launch()
.
You may wish to put an authentication page in front of your app to limit who can open your app. With the auth=
keyword argument in the launch()
method, you can provide a tuple with a username and password, or a list of acceptable username/password tuples; Here's an example that provides password-based authentication for a single user named \"admin\":
demo.launch(auth=(\"admin\", \"pass1234\"))\n
For more complex authentication handling, you can even pass a function that takes a username and password as arguments, and returns True to allow authentication, False otherwise. This can be used for, among other things, making requests to 3rd-party authentication services.
\n\nHere's an example of a function that accepts any login where the username and password are the same:
\n\ndef same_auth(username, password):\n return username == password\ndemo.launch(auth=same_auth)\n
For authentication to work properly, third party cookies must be enabled in your browser.\nThis is not the case by default for Safari, Chrome Incognito Mode.
\n\nWhen a user makes a prediction to your app, you may need the underlying network request, in order to get the request headers (e.g. for advanced authentication), log the client's IP address, or for other reasons. Gradio supports this in a similar manner to FastAPI: simply add a function parameter whose type hint is gr.Request
and Gradio will pass in the network request as that parameter. Here is an example:
import gradio as gr\n\ndef echo(name, request: gr.Request):\n if request:\n print(\"Request headers dictionary:\", request.headers)\n print(\"IP address:\", request.client.host)\n return name\n\nio = gr.Interface(echo, \"textbox\", \"textbox\").launch()\n
Note: if your function is called directly instead of through the UI (this happens, for \nexample, when examples are cached), then request
will be None
. You should handle\nthis case explicitly to ensure that your app does not throw any errors. That is why\nwe have the explicit check if request
.
In some cases, you might have an existing FastAPI app, and you'd like to add a path for a Gradio demo.\nYou can easily do this with gradio.mount_gradio_app()
.
Here's a complete example:
\n\nfrom fastapi import FastAPI\nimport gradio as gr\n\nCUSTOM_PATH = \"/gradio\"\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_main():\n return {\"message\": \"This is your main app\"}\n\n\nio = gr.Interface(lambda x: \"Hello, \" + x + \"!\", \"textbox\", \"textbox\")\napp = gr.mount_gradio_app(app, io, path=CUSTOM_PATH)\n\n\n# Run this from the terminal as you would normally start a FastAPI app: `uvicorn run:app`\n# and navigate to http://localhost:8000/gradio in your browser.\n\n
Note that this approach also allows you run your Gradio apps on custom paths (http://localhost:8000/gradio
in the example above).
Sharing your Gradio app with others (by hosting it on Spaces, on your own server, or through temporary share links) exposes certain files on the host machine to users of your Gradio app.
\n\nIn particular, Gradio apps ALLOW users to access to three kinds of files:
\n\nFiles in the same directory (or a subdirectory) of where the Gradio script is launched from. For example, if the path to your gradio scripts is /home/usr/scripts/project/app.py
and you launch it from /home/usr/scripts/project/
, then users of your shared Gradio app will be able to access any files inside /home/usr/scripts/project/
. This is done so that you can easily reference these files in your Gradio app (e.g. for your app's examples
).
Temporary files created by Gradio. These are files that are created by Gradio as part of running your prediction function. For example, if your prediction function returns a video file, then Gradio will save that video to a temporary file and then send the path to the temporary file to the front end. You can customize the location of temporary files created by Gradio by setting the environment variable GRADIO_TEMP_DIR
to an absolute path, such as /home/usr/scripts/project/temp/
.
Files that you explicitly allow via the allowed_paths
parameter in launch()
. This parameter allows you to pass in a list of additional directories or exact filepaths you'd like to allow users to have access to. (By default, this parameter is an empty list).
Gradio DOES NOT ALLOW access to:
\n\nDotfiles (any files whose name begins with '.'
) or any files that are contained in any directory whose name begins with '.'
Files that you explicitly allow via the blocked_paths
parameter in launch()
. You can pass in a list of additional directories or exact filepaths to the blocked_paths
parameter in launch()
. This parameter takes precedence over the files that Gradio exposes by default or by the allowed_paths
.
Any other paths on the host machine. Users should NOT be able to access other arbitrary paths on the host.
Please make sure you are running the latest version of gradio
for these security settings to apply.
Prerequisite: Gradio requires Python 3.8 or higher, that's all!
\n\nOne of the best ways to share your machine learning model, API, or data science workflow with others is to create an interactive app that allows your users or colleagues to try out the demo in their browsers.
\n\nGradio allows you to build demos and share them, all in Python. And usually in just a few lines of code! So let's get started.
\n\nTo get Gradio running with a simple \"Hello, World\" example, follow these three steps:
\n\n1. Install Gradio using pip:
\n\npip install gradio\n
2. Run the code below as a Python script or in a Jupyter Notebook (or Google Colab):
\n\nimport gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\ndemo = gr.Interface(fn=greet, inputs=\"text\", outputs=\"text\")\n\ndemo.launch() \n
We shorten the imported name to gr
for better readability of code using Gradio. This is a widely adopted convention that you should follow so that anyone working with your code can easily understand it.
3. The demo below will appear automatically within the Jupyter Notebook, or pop in a browser on http://localhost:7860 if running from a script:
\n\nWhen developing locally, if you want to run the code as a Python script, you can use the Gradio CLI to launch the application in reload mode, which will provide seamless and fast development. Learn more about reloading in the Auto-Reloading Guide.
\n\ngradio app.py\n
Note: you can also do python app.py
, but it won't provide the automatic reload mechanism.
Interface
ClassYou'll notice that in order to make the demo, we created a gr.Interface
. This Interface
class can wrap any Python function with a user interface. In the example above, we saw a simple text-based function, but the function could be anything from music generator to a tax calculator to the prediction function of a pretrained machine learning model.
The core Interface
class is initialized with three required parameters:
fn
: the function to wrap a UI aroundinputs
: which component(s) to use for the input (e.g. \"text\"
, \"image\"
or \"audio\"
)outputs
: which component(s) to use for the output (e.g. \"text\"
, \"image\"
or \"label\"
)Let's take a closer look at these components used to provide input and output.
\n\nWe saw some simple Textbox
components in the previous examples, but what if you want to change how the UI components look or behave?
Let's say you want to customize the input text field \u2014 for example, you wanted it to be larger and have a text placeholder. If we use the actual class for Textbox
instead of using the string shortcut, you have access to much more customizability through component attributes.
import gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\ndemo = gr.Interface(\n fn=greet,\n inputs=gr.Textbox(lines=2, placeholder=\"Name Here...\"),\n outputs=\"text\",\n)\ndemo.launch()\n\n
Suppose you had a more complex function, with multiple inputs and outputs. In the example below, we define a function that takes a string, boolean, and number, and returns a string and number. Take a look how you pass a list of input and output components.
\n\nimport gradio as gr\n\ndef greet(name, is_morning, temperature):\n salutation = \"Good morning\" if is_morning else \"Good evening\"\n greeting = f\"{salutation} {name}. It is {temperature} degrees today\"\n celsius = (temperature - 32) * 5 / 9\n return greeting, round(celsius, 2)\n\ndemo = gr.Interface(\n fn=greet,\n inputs=[\"text\", \"checkbox\", gr.Slider(0, 100)],\n outputs=[\"text\", \"number\"],\n)\ndemo.launch()\n\n
You simply wrap the components in a list. Each component in the inputs
list corresponds to one of the parameters of the function, in order. Each component in the outputs
list corresponds to one of the values returned by the function, again in order.
Gradio supports many types of components, such as Image
, DataFrame
, Video
, or Label
. Let's try an image-to-image function to get a feel for these!
import numpy as np\nimport gradio as gr\n\ndef sepia(input_img):\n sepia_filter = np.array([\n [0.393, 0.769, 0.189], \n [0.349, 0.686, 0.168], \n [0.272, 0.534, 0.131]\n ])\n sepia_img = input_img.dot(sepia_filter.T)\n sepia_img /= sepia_img.max()\n return sepia_img\n\ndemo = gr.Interface(sepia, gr.Image(shape=(200, 200)), \"image\")\ndemo.launch()\n\n
When using the Image
component as input, your function will receive a NumPy array with the shape (height, width, 3)
, where the last dimension represents the RGB values. We'll return an image as well in the form of a NumPy array.
You can also set the datatype used by the component with the type=
keyword argument. For example, if you wanted your function to take a file path to an image instead of a NumPy array, the input Image
component could be written as:
gr.Image(type=\"filepath\", shape=...)\n
Also note that our input Image
component comes with an edit button \ud83d\udd89, which allows for cropping and zooming into images. Manipulating images in this way can help reveal biases or hidden flaws in a machine learning model!
You can read more about the many components and how to use them in the Gradio docs.
\n\nGradio includes a high-level class, gr.ChatInterface
, which is similar to gr.Interface
, but is specifically designed for chatbot UIs. The gr.ChatInterface
class also wraps a function but this function must have a specific signature. The function should take two arguments: message
and then history
(the arguments can be named anything, but must be in this order)
message
: a str
representing the user's inputhistory
: a list
of list
representing the conversations up until that point. Each inner list consists of two str
representing a pair: [user input, bot response]
. Your function should return a single string response, which is the bot's response to the particular user input message
.
Other than that, gr.ChatInterface
has no required parameters (though several are available for customization of the UI).
Here's a toy example:
\n\nimport random\nimport gradio as gr\n\ndef random_response(message, history):\n return random.choice([\"Yes\", \"No\"])\n\ndemo = gr.ChatInterface(random_response)\n\ndemo.launch()\n\n
You can read more about gr.ChatInterface
here.
Gradio offers two approaches to build apps:
\n\n1. Interface and ChatInterface, which provide a high-level abstraction for creating demos that we've been discussing so far.
\n\n2. Blocks, a low-level API for designing web apps with more flexible layouts and data flows. Blocks allows you to do things like feature multiple data flows and demos, control where components appear on the page, handle complex data flows (e.g. outputs can serve as inputs to other functions), and update properties/visibility of components based on user interaction \u2014 still all in Python. If this customizability is what you need, try Blocks
instead!
Let's take a look at a simple example. Note how the API here differs from Interface
.
import gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\nwith gr.Blocks() as demo:\n name = gr.Textbox(label=\"Name\")\n output = gr.Textbox(label=\"Output Box\")\n greet_btn = gr.Button(\"Greet\")\n greet_btn.click(fn=greet, inputs=name, outputs=output, api_name=\"greet\")\n\n\ndemo.launch()\n
Things to note:
\n\nBlocks
are made with a with
clause, and any component created inside this clause is automatically added to the app.Button
was created, and then a click
event-listener was added to this button. The API for this should look familiar! Like an Interface
, the click
method takes a Python function, input components, and output components.Here's an app to give you a taste of what's possible with Blocks
:
import numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
A lot more going on here! We'll cover how to create complex Blocks
apps like this in the building with blocks section for you.
Congrats, you're now familiar with the basics of Gradio! \ud83e\udd73 Go to our next guide to learn more about the key features of Gradio.
\n", "tags": [], "spaces": [], "url": "/guides/quickstart/", "contributor": null}, {"name": "key-features", "category": "getting-started", "pretty_category": "Getting Started", "guide_index": 2, "absolute_index": 1, "pretty_name": "Key Features", "content": "# Key Features\n\nLet's go through some of the most popular features of Gradio! Here are Gradio's key features:\n\n1. [Adding example inputs](#example-inputs)\n2. [Passing custom error messages](#alerts)\n3. [Adding descriptive content](#descriptive-content)\n4. [Setting up flagging](#flagging)\n5. [Preprocessing and postprocessing](#preprocessing-and-postprocessing)\n6. [Styling demos](#styling)\n7. [Queuing users](#queuing)\n8. [Iterative outputs](#iterative-outputs)\n9. [Progress bars](#progress-bars)\n10. [Batch functions](#batch-functions)\n11. [Running on collaborative notebooks](#colab-notebooks)\n\n## Example Inputs\n\nYou can provide example data that a user can easily load into `Interface`. This can be helpful to demonstrate the types of inputs the model expects, as well as to provide a way to explore your dataset in conjunction with your model. To load example data, you can provide a **nested list** to the `examples=` keyword argument of the Interface constructor. Each sublist within the outer list represents a data sample, and each element within the sublist represents an input for each input component. The format of example data for each component is specified in the [Docs](https://gradio.app/docs#components).\n\n```python\nimport gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n if num2 == 0:\n raise gr.Error(\"Cannot divide by zero!\")\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\", \n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n examples=[\n [5, \"add\", 3],\n [4, \"divide\", 2],\n [-4, \"multiply\", 2.5],\n [0, \"subtract\", 1.2],\n ],\n title=\"Toy Calculator\",\n description=\"Here's a sample toy calculator. Allows you to calculate things like $2+2=4$\",\n)\ndemo.launch()\n\n```\nLet's go through some of the most popular features of Gradio! Here are Gradio's key features:
\n\nYou can provide example data that a user can easily load into Interface
. This can be helpful to demonstrate the types of inputs the model expects, as well as to provide a way to explore your dataset in conjunction with your model. To load example data, you can provide a nested list to the examples=
keyword argument of the Interface constructor. Each sublist within the outer list represents a data sample, and each element within the sublist represents an input for each input component. The format of example data for each component is specified in the Docs.
import gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n if num2 == 0:\n raise gr.Error(\"Cannot divide by zero!\")\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\", \n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n examples=[\n [5, \"add\", 3],\n [4, \"divide\", 2],\n [-4, \"multiply\", 2.5],\n [0, \"subtract\", 1.2],\n ],\n title=\"Toy Calculator\",\n description=\"Here's a sample toy calculator. Allows you to calculate things like $2+2=4$\",\n)\ndemo.launch()\n\n
You can load a large dataset into the examples to browse and interact with the dataset through Gradio. The examples will be automatically paginated (you can configure this through the examples_per_page
argument of Interface
).
Continue learning about examples in the More On Examples guide.
\n\nYou wish to pass custom error messages to the user. To do so, raise a gr.Error(\"custom message\")
to display an error message. If you try to divide by zero in the calculator demo above, a popup modal will display the custom error message. Learn more about Error in the docs.
You can also issue gr.Warning(\"message\")
and gr.Info(\"message\")
by having them as standalone lines in your function, which will immediately display modals while continuing the execution of your function. Queueing needs to be enabled for this to work.
Note below how the gr.Error
has to be raised, while the gr.Warning
and gr.Info
are single lines.
def start_process(name):\n gr.Info(\"Starting process\")\n if name is None:\n gr.Warning(\"Name is empty\")\n ...\n if success == False:\n raise gr.Error(\"Process failed\")\n
In the previous example, you may have noticed the title=
and description=
keyword arguments in the Interface
constructor that helps users understand your app.
There are three arguments in the Interface
constructor to specify where this content should go:
title
: which accepts text and can display it at the very top of interface, and also becomes the page title.description
: which accepts text, markdown or HTML and places it right under the title.article
: which also accepts text, markdown or HTML and places it below the interface.If you're using the Blocks
API instead, you can insert text, markdown, or HTML anywhere using the gr.Markdown(...)
or gr.HTML(...)
components, with descriptive content inside the Component
constructor.
Another useful keyword argument is label=
, which is present in every Component
. This modifies the label text at the top of each Component
. You can also add the info=
keyword argument to form elements like Textbox
or Radio
to provide further information on their usage.
gr.Number(label='Age', info='In years, must be greater than 0')\n
By default, an Interface
will have \"Flag\" button. When a user testing your Interface
sees input with interesting output, such as erroneous or unexpected model behaviour, they can flag the input for you to review. Within the directory provided by the flagging_dir=
argument to the Interface
constructor, a CSV file will log the flagged inputs. If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well.
For example, with the calculator interface shown above, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- calculator.py\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output\n5,add,7,12\n6,subtract,1.5,4.5\n
With the sepia interface shown earlier, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- sepia.py\n+-- flagged/\n| +-- logs.csv\n| +-- im/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output\nim/0.png,Output/0.png\nim/1.png,Output/1.png\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of the strings when flagging, which will be saved as an additional column to the CSV.
As you've seen, Gradio includes components that can handle a variety of different data types, such as images, audio, and video. Most components can be used both as inputs or outputs.
\n\nWhen a component is used as an input, Gradio automatically handles the preprocessing needed to convert the data from a type sent by the user's browser (such as a base64 representation of a webcam snapshot) to a form that can be accepted by your function (such as a numpy
array).
Similarly, when a component is used as an output, Gradio automatically handles the postprocessing needed to convert the data from what is returned by your function (such as a list of image paths) to a form that can be displayed in the user's browser (such as a Gallery
of images in base64 format).
You can control the preprocessing using the parameters when constructing the image component. For example, here if you instantiate the Image
component with the following parameters, it will convert the image to the PIL
type and reshape it to be (100, 100)
no matter the original size that it was submitted as:
img = gr.Image(shape=(100, 100), type=\"pil\")\n
In contrast, here we keep the original size of the image, but invert the colors before converting it to a numpy array:
\n\nimg = gr.Image(invert_colors=True, type=\"numpy\")\n
Postprocessing is a lot easier! Gradio automatically recognizes the format of the returned data (e.g. is the Image
a numpy
array or a str
filepath?) and postprocesses it into a format that can be displayed by the browser.
Take a look at the Docs to see all the preprocessing-related parameters for each Component.
\n\nGradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the theme=
kwarg to the Interface
constructor. For example:
demo = gr.Interface(..., theme=gr.themes.Monochrome())\n
Gradio comes with a set of prebuilt themes which you can load from gr.themes.*
. You can extend these themes or create your own themes from scratch - see the Theming guide for more details.
For additional styling ability, you can pass any CSS to your app using the css=
kwarg.\nThe base class for the Gradio app is gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Interface(css=\".gradio-container {background-color: red}\") as demo:\n ...\n
Some components can be additionally styled through the style()
method. For example:
img = gr.Image(\"lion.jpg\").style(height='24', rounded=False)\n
Take a look at the Docs to see all the styling options for each Component.
\n\nIf your app expects heavy traffic, use the queue()
method to control processing rate. This will queue up calls so only a certain number of requests are processed at a single time. Queueing uses websockets, which also prevent network timeouts, so you should use queueing if the inference time of your function is long (> 1min).
With Interface
:
demo = gr.Interface(...).queue()\ndemo.launch()\n
With Blocks
:
with gr.Blocks() as demo:\n #...\ndemo.queue()\ndemo.launch()\n
You can control the number of requests processed at a single time as such:
\n\ndemo.queue(concurrency_count=3)\n
See the Docs on queueing on configuring other queuing parameters.
\n\nTo specify only certain functions for queueing in Blocks:
\n\nwith gr.Blocks() as demo2:\n num1 = gr.Number()\n num2 = gr.Number()\n output = gr.Number()\n gr.Button(\"Add\").click(\n lambda a, b: a + b, [num1, num2], output)\n gr.Button(\"Multiply\").click(\n lambda a, b: a * b, [num1, num2], output, queue=True)\ndemo2.launch()\n
In some cases, you may want to stream a sequence of outputs rather than show a single output at once. For example, you might have an image generation model and you want to show the image that is generated at each step, leading up to the final image. Or you might have a chatbot which streams its response one word at a time instead of returning it all at once.
\n\nIn such cases, you can supply a generator function into Gradio instead of a regular function. Creating generators in Python is very simple: instead of a single return
value, a function should yield
a series of values instead. Usually the yield
statement is put in some kind of loop. Here's an example of an generator that simply counts up to a given number:
def my_generator(x):\n for i in range(x):\n yield i\n
You supply a generator into Gradio the same way as you would a regular function. For example, here's a a (fake) image generation model that generates noise for several steps before outputting an image:
\n\nimport gradio as gr\nimport numpy as np\nimport time\n\n# define core fn, which returns a generator {steps} times before returning the image\ndef fake_diffusion(steps):\n for _ in range(steps):\n time.sleep(1)\n image = np.random.random((600, 600, 3))\n yield image\n image = \"https://gradio-builds.s3.amazonaws.com/diffusion_image/cute_dog.jpg\"\n yield image\n\n\ndemo = gr.Interface(fake_diffusion, inputs=gr.Slider(1, 10, 3), outputs=\"image\")\n\n# define queue - required for generators\ndemo.queue()\n\ndemo.launch()\n\n
Note that we've added a time.sleep(1)
in the iterator to create an artificial pause between steps so that you are able to observe the steps of the iterator (in a real image generation model, this probably wouldn't be necessary).
Supplying a generator into Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio supports the ability to create a custom Progress Bars so that you have customizability and control over the progress update that you show to the user. In order to enable this, simply add an argument to your method that has a default value of a gr.Progress
instance. Then you can update the progress levels by calling this instance directly with a float between 0 and 1, or using the tqdm()
method of the Progress
instance to track progress over an iterable, as shown below. Queueing must be enabled for progress updates.
import gradio as gr\nimport time\n\ndef slowly_reverse(word, progress=gr.Progress()):\n progress(0, desc=\"Starting\")\n time.sleep(1)\n progress(0.05)\n new_string = \"\"\n for letter in progress.tqdm(word, desc=\"Reversing\"):\n time.sleep(0.25)\n new_string = letter + new_string\n return new_string\n\ndemo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())\n\nif __name__ == \"__main__\":\n demo.queue(concurrency_count=10).launch()\n\n
If you use the tqdm
library, you can even report progress updates automatically from any tqdm.tqdm
that already exists within your function by setting the default argument as gr.Progress(track_tqdm=True)
!
Gradio supports the ability to pass batch functions. Batch functions are just\nfunctions which take in a list of inputs and return a list of predictions.
\n\nFor example, here is a batched function that takes in two lists of inputs (a list of\nwords and a list of ints), and returns a list of trimmed words as output:
\n\nimport time\n\ndef trim_words(words, lens):\n trimmed_words = []\n time.sleep(5)\n for w, l in zip(words, lens):\n trimmed_words.append(w[:int(l)]) \n return [trimmed_words]\n
The advantage of using batched functions is that if you enable queuing, the Gradio\nserver can automatically batch incoming requests and process them in parallel,\npotentially speeding up your demo. Here's what the Gradio code looks like (notice\nthe batch=True
and max_batch_size=16
-- both of these parameters can be passed\ninto event triggers or into the Interface
class)
With Interface
:
demo = gr.Interface(trim_words, [\"textbox\", \"number\"], [\"output\"], \n batch=True, max_batch_size=16)\ndemo.queue()\ndemo.launch()\n
With Blocks
:
import gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n word = gr.Textbox(label=\"word\")\n leng = gr.Number(label=\"leng\")\n output = gr.Textbox(label=\"Output\")\n with gr.Row():\n run = gr.Button()\n\n event = run.click(trim_words, [word, leng], output, batch=True, max_batch_size=16)\n\ndemo.queue()\ndemo.launch()\n
In the example above, 16 requests could be processed in parallel (for a total inference\ntime of 5 seconds), instead of each request being processed separately (for a total\ninference time of 80 seconds). Many Hugging Face transformers
and diffusers
models\nwork very naturally with Gradio's batch mode: here's an example demo using diffusers to\ngenerate images in batches
Note: using batch functions with Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio is able to run anywhere you run Python, including local jupyter notebooks as well as collaborative notebooks, such as Google Colab. In the case of local jupyter notebooks and Google Colab notbooks, Gradio runs on a local server which you can interact with in your browser. (Note: for Google Colab, this is accomplished by service worker tunneling, which requires cookies to be enabled in your browser.) For other remote notebooks, Gradio will also run on a server, but you will need to use SSH tunneling to view the app in your local browser. Often a simpler options is to use Gradio's built-in public links, discussed in the next Guide.
\n", "tags": [], "spaces": [], "url": "/guides/key-features/", "contributor": null}, {"name": "sharing-your-app", "category": "getting-started", "pretty_category": "Getting Started", "guide_index": 3, "absolute_index": 2, "pretty_name": "Sharing Your App", "content": "# Sharing Your App\n\nHow to share your Gradio app: \n\n1. [Sharing demos with the share parameter](#sharing-demos)\n2. [Hosting on HF Spaces](#hosting-on-hf-spaces)\n3. [Embedding hosted spaces](#embedding-hosted-spaces)\n4. [Embedding with web components](#embedding-with-web-components)\n5. [Using the API page](#api-page)\n6. [Adding authentication to the page](#authentication)\n7. [Accessing Network Requests](#accessing-the-network-request-directly)\n8. [Mounting within FastAPI](#mounting-within-another-fast-api-app)\n9. [Security](#security-and-file-access)\n\n## Sharing Demos\n\nGradio demos can be easily shared publicly by setting `share=True` in the `launch()` method. Like this:\n\n```python\ndemo.launch(share=True)\n```\n\nThis generates a public, shareable link that you can send to anybody! When you send this link, the user on the other side can try out the model in their browser. Because the processing happens on your device (as long as your device stays on!), you don't have to worry about any packaging any dependencies. A share link usually looks something like this: **XXXXX.gradio.app**. Although the link is served through a Gradio URL, we are only a proxy for your local server, and do not store any data sent through your app.\n\nKeep in mind, however, that these links are publicly accessible, meaning that anyone can use your model for prediction! Therefore, make sure not to expose any sensitive information through the functions you write, or allow any critical changes to occur on your device. If you set `share=False` (the default, except in colab notebooks), only a local link is created, which can be shared by [port-forwarding](https://www.ssh.com/ssh/tunneling/example) with specific users. \n\n![sharing](https://github.com/gradio-app/gradio/blob/main/guides/assets/sharing.svg?raw=true)\n\nShare links expire after 72 hours.\n\n## Hosting on HF Spaces\n\nIf you'd like to have a permanent link to your Gradio demo on the internet, use Hugging Face Spaces. [Hugging Face Spaces](http://huggingface.co/spaces/) provides the infrastructure to permanently host your machine learning model for free! \n\nAfter you have [created a free Hugging Face account](https://huggingface.co/join), you have three methods to deploy your Gradio app to Hugging Face Spaces:\n\n1. From terminal: run `gradio deploy` in your app directory. The CLI will gather some basic metadata and then launch your app. To update your space, you can re-run this command or enable the Github Actions option to automatically update the Spaces on `git push`.\n\n2. From your browser: Drag and drop a folder containing your Gradio model and all related files [here](https://huggingface.co/new-space).\n\n3. Connect Spaces with your Git repository and Spaces will pull the Gradio app from there. See [this guide how to host on Hugging Face Spaces](https://huggingface.co/blog/gradio-spaces) for more information. \n\n\n\nNote: Some components, like `gr.Image`, will display a \"Share\" button only on Spaces, so that users can share the generated output to the Discussions page of the Space easily. You can disable this with `show_share_button`, such as `gr.Image(show_share_button=False)`. \n\n![Image with show_share_button=True](https://github.com/gradio-app/gradio/blob/main/guides/assets/share_icon.png?raw=true)\n\n## Embedding Hosted Spaces\n\nOnce you have hosted your app on Hugging Face Spaces (or on your own server), you may want to embed the demo on a different website, such as your blog or your portfolio. Embedding an interactive demo allows people to try out the machine learning model that you have built, without needing to download or install anything \u2014 right in their browser! The best part is that you can embed interactive demos even in static websites, such as GitHub pages.\n\nThere are two ways to embed your Gradio demos. You can find quick links to both options directly on the Hugging Face Space page, in the \"Embed this Space\" dropdown option:\n\n![Embed this Space dropdown option](https://github.com/gradio-app/gradio/blob/main/guides/assets/embed_this_space.png?raw=true)\n\n### Embedding with Web Components\n\nWeb components typically offer a better experience to users than IFrames. Web components load lazily, meaning that they won't slow down the loading time of your website, and they automatically adjust their height based on the size of the Gradio app. \n\nTo embed with Web Components:\n\n1. Import the gradio JS library into into your site by adding the script below in your site (replace {GRADIO_VERSION} in the URL with the library version of Gradio you are using). \n\n```html\n\n```\n\n2. Add \n```html\nHow to share your Gradio app:
\n\nGradio demos can be easily shared publicly by setting share=True
in the launch()
method. Like this:
demo.launch(share=True)\n
This generates a public, shareable link that you can send to anybody! When you send this link, the user on the other side can try out the model in their browser. Because the processing happens on your device (as long as your device stays on!), you don't have to worry about any packaging any dependencies. A share link usually looks something like this: XXXXX.gradio.app. Although the link is served through a Gradio URL, we are only a proxy for your local server, and do not store any data sent through your app.
\n\nKeep in mind, however, that these links are publicly accessible, meaning that anyone can use your model for prediction! Therefore, make sure not to expose any sensitive information through the functions you write, or allow any critical changes to occur on your device. If you set share=False
(the default, except in colab notebooks), only a local link is created, which can be shared by port-forwarding with specific users.
Share links expire after 72 hours.
\n\nIf you'd like to have a permanent link to your Gradio demo on the internet, use Hugging Face Spaces. Hugging Face Spaces provides the infrastructure to permanently host your machine learning model for free!
\n\nAfter you have created a free Hugging Face account, you have three methods to deploy your Gradio app to Hugging Face Spaces:
\n\nFrom terminal: run gradio deploy
in your app directory. The CLI will gather some basic metadata and then launch your app. To update your space, you can re-run this command or enable the Github Actions option to automatically update the Spaces on git push
.
From your browser: Drag and drop a folder containing your Gradio model and all related files here.
Connect Spaces with your Git repository and Spaces will pull the Gradio app from there. See this guide how to host on Hugging Face Spaces for more information.
Note: Some components, like gr.Image
, will display a \"Share\" button only on Spaces, so that users can share the generated output to the Discussions page of the Space easily. You can disable this with show_share_button
, such as gr.Image(show_share_button=False)
.
sharebutton=True\" />
\n\nOnce you have hosted your app on Hugging Face Spaces (or on your own server), you may want to embed the demo on a different website, such as your blog or your portfolio. Embedding an interactive demo allows people to try out the machine learning model that you have built, without needing to download or install anything \u2014 right in their browser! The best part is that you can embed interactive demos even in static websites, such as GitHub pages.
\n\nThere are two ways to embed your Gradio demos. You can find quick links to both options directly on the Hugging Face Space page, in the \"Embed this Space\" dropdown option:
\n\n\n\nWeb components typically offer a better experience to users than IFrames. Web components load lazily, meaning that they won't slow down the loading time of your website, and they automatically adjust their height based on the size of the Gradio app.
\n\nTo embed with Web Components:
\n\n\n
\n
element where you want to place the app. Set the src=
attribute to your Space's embed URL, which you can find in the \"Embed this Space\" button. For example:
\n
You can see examples of how web components look on the Gradio landing page.
\n\nYou can also customize the appearance and behavior of your web component with attributes that you pass into the <gradio-app>
tag:
src
: as we've seen, the src
attributes links to the URL of the hosted Gradio demo that you would like to embedspace
: an optional shorthand if your Gradio demo is hosted on Hugging Face Space. Accepts a username/space_name
instead of a full URL. Example: gradio/Echocardiogram-Segmentation
. If this attribute attribute is provided, then src
does not need to be provided.control_page_title
: a boolean designating whether the html title of the page should be set to the title of the Gradio app (by default \"false\"
)initial_height
: the initial height of the web component while it is loading the Gradio app, (by default \"300px\"
). Note that the final height is set based on the size of the Gradio app.container
: whether to show the border frame and information about where the Space is hosted (by default \"true\"
)info
: whether to show just the information about where the Space is hosted underneath the embedded app (by default \"true\"
)autoscroll
: whether to autoscroll to the output when prediction has finished (by default \"false\"
)eager
: whether to load the Gradio app as soon as the page loads (by default \"false\"
)theme_mode
: whether to use the dark
, light
, or default system
theme mode (by default \"system\"
)Here's an example of how to use these attributes to create a Gradio app that does not lazy load and has an initial height of 0px.
\n\n \n
Note: While Gradio's CSS will never impact the embedding page, the embedding page can affect the style of the embedded Gradio app. Make sure that any CSS in the parent page isn't so general that it could also apply to the embedded Gradio app and cause the styling to break. Element selectors such as header { ... }
and footer { ... }
will be the most likely to cause issues.
To embed with IFrames instead (if you cannot add javascript to your website, for example), add this element:
\n\n\n
Again, you can find the src=
attribute to your Space's embed URL, which you can find in the \"Embed this Space\" button.
Note: if you use IFrames, you'll probably want to add a fixed height
attribute and set style=\"border:0;\"
to remove the boreder. In addition, if your app requires permissions such as access to the webcam or the microphone, you'll need to provide that as well using the allow
attribute.
You can use almost any Gradio app as an API! In the footer of a Gradio app like this one, you'll see a \"Use via API\" link.
\n\n\n\nThis is a page that lists the endpoints that can be used to query the Gradio app, via our supported clients: either the Python client, or the JavaScript client. For each endpoint, Gradio automatically generates the parameters and their types, as well as example inputs.
\n\nThe endpoints are automatically created when you launch a Gradio Interface
. If you are using Gradio Blocks
, you can also set up a Gradio API page, though we recommend that you explicitly name each event listener, such as
btn.click(add, [num1, num2], output, api_name=\"addition\")\n
This will add and document the endpoint /api/addition/
to the automatically generated API page. Otherwise, your API endpoints will appear as \"unnamed\" endpoints.
Note: For Gradio apps in which queueing is enabled, users can bypass the queue if they make a POST request to your API endpoint. To disable this behavior, set api_open=False
in the queue()
method. To disable the API page altogether, set show_api=False
in .launch()
.
You may wish to put an authentication page in front of your app to limit who can open your app. With the auth=
keyword argument in the launch()
method, you can provide a tuple with a username and password, or a list of acceptable username/password tuples; Here's an example that provides password-based authentication for a single user named \"admin\":
demo.launch(auth=(\"admin\", \"pass1234\"))\n
For more complex authentication handling, you can even pass a function that takes a username and password as arguments, and returns True to allow authentication, False otherwise. This can be used for, among other things, making requests to 3rd-party authentication services.
\n\nHere's an example of a function that accepts any login where the username and password are the same:
\n\ndef same_auth(username, password):\n return username == password\ndemo.launch(auth=same_auth)\n
For authentication to work properly, third party cookies must be enabled in your browser.\nThis is not the case by default for Safari, Chrome Incognito Mode.
\n\nWhen a user makes a prediction to your app, you may need the underlying network request, in order to get the request headers (e.g. for advanced authentication), log the client's IP address, or for other reasons. Gradio supports this in a similar manner to FastAPI: simply add a function parameter whose type hint is gr.Request
and Gradio will pass in the network request as that parameter. Here is an example:
import gradio as gr\n\ndef echo(name, request: gr.Request):\n if request:\n print(\"Request headers dictionary:\", request.headers)\n print(\"IP address:\", request.client.host)\n return name\n\nio = gr.Interface(echo, \"textbox\", \"textbox\").launch()\n
Note: if your function is called directly instead of through the UI (this happens, for \nexample, when examples are cached), then request
will be None
. You should handle\nthis case explicitly to ensure that your app does not throw any errors. That is why\nwe have the explicit check if request
.
In some cases, you might have an existing FastAPI app, and you'd like to add a path for a Gradio demo.\nYou can easily do this with gradio.mount_gradio_app()
.
Here's a complete example:
\n\nfrom fastapi import FastAPI\nimport gradio as gr\n\nCUSTOM_PATH = \"/gradio\"\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_main():\n return {\"message\": \"This is your main app\"}\n\n\nio = gr.Interface(lambda x: \"Hello, \" + x + \"!\", \"textbox\", \"textbox\")\napp = gr.mount_gradio_app(app, io, path=CUSTOM_PATH)\n\n\n# Run this from the terminal as you would normally start a FastAPI app: `uvicorn run:app`\n# and navigate to http://localhost:8000/gradio in your browser.\n\n
Note that this approach also allows you run your Gradio apps on custom paths (http://localhost:8000/gradio
in the example above).
Sharing your Gradio app with others (by hosting it on Spaces, on your own server, or through temporary share links) exposes certain files on the host machine to users of your Gradio app.
\n\nIn particular, Gradio apps ALLOW users to access to three kinds of files:
\n\nFiles in the same directory (or a subdirectory) of where the Gradio script is launched from. For example, if the path to your gradio scripts is /home/usr/scripts/project/app.py
and you launch it from /home/usr/scripts/project/
, then users of your shared Gradio app will be able to access any files inside /home/usr/scripts/project/
. This is done so that you can easily reference these files in your Gradio app (e.g. for your app's examples
).
Temporary files created by Gradio. These are files that are created by Gradio as part of running your prediction function. For example, if your prediction function returns a video file, then Gradio will save that video to a temporary file and then send the path to the temporary file to the front end. You can customize the location of temporary files created by Gradio by setting the environment variable GRADIO_TEMP_DIR
to an absolute path, such as /home/usr/scripts/project/temp/
.
Files that you explicitly allow via the allowed_paths
parameter in launch()
. This parameter allows you to pass in a list of additional directories or exact filepaths you'd like to allow users to have access to. (By default, this parameter is an empty list).
Gradio DOES NOT ALLOW access to:
\n\nDotfiles (any files whose name begins with '.'
) or any files that are contained in any directory whose name begins with '.'
Files that you explicitly allow via the blocked_paths
parameter in launch()
. You can pass in a list of additional directories or exact filepaths to the blocked_paths
parameter in launch()
. This parameter takes precedence over the files that Gradio exposes by default or by the allowed_paths
.
Any other paths on the host machine. Users should NOT be able to access other arbitrary paths on the host.
Please make sure you are running the latest version of gradio
for these security settings to apply.
This guide covers how State is handled in Gradio. Learn the difference between Global and Session states, and how to use both.
\n\nYour function may use data that persists beyond a single function call. If the data is something accessible to all function calls and all users, you can create a variable outside the function call and access it inside the function. For example, you may load a large model outside the function and use it inside the function so that every function call does not need to reload the model.
\n\nimport gradio as gr\n\nscores = []\n\ndef track_score(score):\n scores.append(score)\n top_scores = sorted(scores, reverse=True)[:3]\n return top_scores\n\ndemo = gr.Interface(\n track_score, \n gr.Number(label=\"Score\"), \n gr.JSON(label=\"Top Scores\")\n)\ndemo.launch()\n
In the code above, the scores
array is shared between all users. If multiple users are accessing this demo, their scores will all be added to the same list, and the returned top 3 scores will be collected from this shared reference.
Another type of data persistence Gradio supports is session state, where data persists across multiple submits within a page session. However, data is not shared between different users of your model. To store data in a session state, you need to do three things:
\n\n'state'
input and 'state'
output components when creating your Interface
A chatbot is an example where you would need session state - you want access to a users previous submissions, but you cannot store chat history in a global variable, because then chat history would get jumbled between different users.
\n\nimport gradio as gr\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\nimport torch\n\ntokenizer = AutoTokenizer.from_pretrained(\"microsoft/DialoGPT-medium\")\nmodel = AutoModelForCausalLM.from_pretrained(\"microsoft/DialoGPT-medium\")\n\n\ndef user(message, history):\n return \"\", history + [[message, None]]\n\n\ndef bot(history):\n user_message = history[-1][0]\n new_user_input_ids = tokenizer.encode(\n user_message + tokenizer.eos_token, return_tensors=\"pt\"\n )\n\n # append the new user input tokens to the chat history\n bot_input_ids = torch.cat([torch.LongTensor([]), new_user_input_ids], dim=-1)\n\n # generate a response\n response = model.generate(\n bot_input_ids, max_length=1000, pad_token_id=tokenizer.eos_token_id\n ).tolist()\n\n # convert the tokens to text, and then split the responses into lines\n response = tokenizer.decode(response[0]).split(\"<|endoftext|>\")\n response = [\n (response[i], response[i + 1]) for i in range(0, len(response) - 1, 2)\n ] # convert to tuples of list\n history[-1] = response[0]\n return history\n\n\nwith gr.Blocks() as demo:\n chatbot = gr.Chatbot()\n msg = gr.Textbox()\n clear = gr.Button(\"Clear\")\n\n msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(\n bot, chatbot, chatbot\n )\n clear.click(lambda: None, None, chatbot, queue=False)\n\ndemo.launch()\n\n
Notice how the state persists across submits within each page, but if you load this demo in another tab (or refresh the page), the demos will not share chat history.
\n\nThe default value of state
is None. If you pass a default value to the state parameter of the function, it is used as the default value of the state instead. The Interface
class only supports a single input and outputs state variable, though it can be a list with multiple elements. For more complex use cases, you can use Blocks, which supports multiple State
variables.
This guide covers how to get Gradio interfaces to refresh automatically or continuously stream data.
\n\nYou can make interfaces automatically refresh by setting live=True
in the interface. Now the interface will recalculate as soon as the user input changes.
import gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\",\n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n live=True,\n)\ndemo.launch()\n\n
Note there is no submit button, because the interface resubmits automatically on change.
\n\nSome components have a \"streaming\" mode, such as Audio
component in microphone mode, or the Image
component in webcam mode. Streaming means data is sent continuously to the backend and the Interface
function is continuously being rerun.
The difference between gr.Audio(source='microphone')
and gr.Audio(source='microphone', streaming=True)
, when both are used in gr.Interface(live=True)
, is that the first Component
will automatically submit data and run the Interface
function when the user stops recording, whereas the second Component
will continuously send data and run the Interface
function during recording.
Here is example code of streaming images from the webcam.
\n\nimport gradio as gr\nimport numpy as np\n\ndef flip(im):\n return np.flipud(im)\n\ndemo = gr.Interface(\n flip, \n gr.Image(source=\"webcam\", streaming=True), \n \"image\",\n live=True\n)\ndemo.launch()\n\n
There's more to cover on the Interface class. This guide covers all the advanced features: Using Interpretation, custom styling, loading from the Hugging Face Hub, and using Parallel and Series.
\n\nMost models are black boxes such that the internal logic of the function is hidden from the end user. To encourage transparency, we've made it very easy to add interpretation to your model by simply setting the interpretation
keyword in the Interface
class to default
. This allows your users to understand what parts of the input are responsible for the output. Take a look at the simple interface below which shows an image classifier that also includes interpretation:
import requests\nimport tensorflow as tf\n\nimport gradio as gr\n\ninception_net = tf.keras.applications.MobileNetV2() # load the model\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n return {labels[i]: float(prediction[i]) for i in range(1000)}\n\n\nimage = gr.Image(shape=(224, 224))\nlabel = gr.Label(num_top_classes=3)\n\ndemo = gr.Interface(\n fn=classify_image, inputs=image, outputs=label, interpretation=\"default\"\n)\n\ndemo.launch()\n\n
In addition to default
, Gradio also includes Shapley-based interpretation, which provides more accurate interpretations, albeit usually with a slower runtime. To use this, simply set the interpretation
parameter to \"shap\"
(note: also make sure the python package shap
is installed). Optionally, you can modify the num_shap
parameter, which controls the tradeoff between accuracy and runtime (increasing this value generally increases accuracy). Here is an example:
gr.Interface(fn=classify_image,\n inputs=image, \n outputs=label, \n interpretation=\"shap\", \n num_shap=5).launch()\n
This will work for any function, even if internally, the model is a complex neural network or some other black box. If you use Gradio's default
or shap
interpretation, the output component must be a Label
. All common input components are supported. Here is an example with text input.
import gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=\"default\",\n)\n\ndemo.launch()\n\n
So what is happening under the hood? With these interpretation methods, Gradio runs the prediction multiple times with modified versions of the input. Based on the results, you'll see that the interface automatically highlights the parts of the text (or image, etc.) that contributed increased the likelihood of the class as red. The intensity of color corresponds to the importance of that part of the input. The parts that decrease the class confidence are highlighted blue.
\n\nYou can also write your own interpretation function. The demo below adds custom interpretation to the previous demo. This function will take the same inputs as the main wrapped function. The output of this interpretation function will be used to highlight the input of each input component - therefore the function must return a list where the number of elements corresponds to the number of input components. To see the format for interpretation for each input component, check the Docs.
\n\nimport re\n\nimport gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\n# Number of arguments to interpretation function must\n# match number of inputs to prediction function\ndef interpret_gender(sentence):\n result = gender_of_sentence(sentence)\n is_male = result[\"male\"] > result[\"female\"]\n interpretation = []\n for word in re.split(\"( )\", sentence):\n score = 0\n token = word.lower()\n if (is_male and token in male_words) or (not is_male and token in female_words):\n score = 1\n elif (is_male and token in female_words) or (\n not is_male and token in male_words\n ):\n score = -1\n interpretation.append((word, score))\n # Output must be a list of lists containing the same number of elements as inputs\n # Each element corresponds to the interpretation scores for the given input\n return [interpretation]\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=interpret_gender,\n)\n\ndemo.launch()\n\n
Learn more about Interpretation in the docs.
\n\nIf you'd like to have more fine-grained control over any aspect of your demo, you can also write your own css or pass in a filepath to a css file, with the css
parameter of the Interface
class.
gr.Interface(..., css=\"body {background-color: red}\")\n
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with \"file=\"
, for example:
gr.Interface(..., css=\"body {background-image: url('file=clouds.jpg')}\")\n
Warning: Custom CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using custom CSS sparingly and instead using Themes whenever possible.
\n\nGradio integrates nicely with the Hugging Face Hub, allowing you to load models and Spaces with just one line of code. To use this, simply use the load()
method in the Interface
class. So:
\"model/\"
or \"huggingface/\"
followed by the model name, like these examples:gr.Interface.load(\"huggingface/gpt2\").launch();\n
gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\", \n inputs=gr.Textbox(lines=5, label=\"Input Text\") # customizes the input component\n).launch()\n
\"spaces/\"
followed by the model name:gr.Interface.load(\"spaces/eugenesiow/remove-bg\", \n inputs=\"webcam\", \n title=\"Remove your webcam background!\").launch()\n
One of the great things about loading Hugging Face models or spaces using Gradio is that you can then immediately use the resulting Interface
object just like function in your Python code (this works for every type of model/space: text, images, audio, video, and even multimodal models):
io = gr.Interface.load(\"models/EleutherAI/gpt-neo-2.7B\")\nio(\"It was the best of times\") # outputs model completion\n
Gradio also lets you mix interfaces very easily using the gradio.Parallel
and gradio.Series
classes. Parallel
lets you put two similar models (if they have the same input type) in parallel to compare model predictions:
generator1 = gr.Interface.load(\"huggingface/gpt2\")\ngenerator2 = gr.Interface.load(\"huggingface/EleutherAI/gpt-neo-2.7B\")\ngenerator3 = gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\")\n\ngr.Parallel(generator1, generator2, generator3).launch()\n
Series
lets you put models and spaces in series, piping the output of one model into the input of the next model.
generator = gr.Interface.load(\"huggingface/gpt2\")\ntranslator = gr.Interface.load(\"huggingface/t5-small\")\n\ngr.Series(generator, translator).launch() \n# this demo generates text, then translates it to German, and outputs the final result.\n
And of course, you can also mix Parallel
and Series
together whenever that makes sense!
Learn more about Parallel and Series in the docs.
\n", "tags": [], "spaces": [], "url": "/guides/advanced-interface-features/", "contributor": null}], "parent": "gradio"}, "tabbedinterface": {"class": null, "name": "TabbedInterface", "description": "A TabbedInterface is created by providing a list of Interfaces, each of which gets rendered in a separate tab.", "tags": {"demos": "stt_or_tts"}, "parameters": [{"name": "self", "annotation": "There's more to cover on the Interface class. This guide covers all the advanced features: Using Interpretation, custom styling, loading from the Hugging Face Hub, and using Parallel and Series.
\n\nMost models are black boxes such that the internal logic of the function is hidden from the end user. To encourage transparency, we've made it very easy to add interpretation to your model by simply setting the interpretation
keyword in the Interface
class to default
. This allows your users to understand what parts of the input are responsible for the output. Take a look at the simple interface below which shows an image classifier that also includes interpretation:
import requests\nimport tensorflow as tf\n\nimport gradio as gr\n\ninception_net = tf.keras.applications.MobileNetV2() # load the model\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n return {labels[i]: float(prediction[i]) for i in range(1000)}\n\n\nimage = gr.Image(shape=(224, 224))\nlabel = gr.Label(num_top_classes=3)\n\ndemo = gr.Interface(\n fn=classify_image, inputs=image, outputs=label, interpretation=\"default\"\n)\n\ndemo.launch()\n\n
In addition to default
, Gradio also includes Shapley-based interpretation, which provides more accurate interpretations, albeit usually with a slower runtime. To use this, simply set the interpretation
parameter to \"shap\"
(note: also make sure the python package shap
is installed). Optionally, you can modify the num_shap
parameter, which controls the tradeoff between accuracy and runtime (increasing this value generally increases accuracy). Here is an example:
gr.Interface(fn=classify_image,\n inputs=image, \n outputs=label, \n interpretation=\"shap\", \n num_shap=5).launch()\n
This will work for any function, even if internally, the model is a complex neural network or some other black box. If you use Gradio's default
or shap
interpretation, the output component must be a Label
. All common input components are supported. Here is an example with text input.
import gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=\"default\",\n)\n\ndemo.launch()\n\n
So what is happening under the hood? With these interpretation methods, Gradio runs the prediction multiple times with modified versions of the input. Based on the results, you'll see that the interface automatically highlights the parts of the text (or image, etc.) that contributed increased the likelihood of the class as red. The intensity of color corresponds to the importance of that part of the input. The parts that decrease the class confidence are highlighted blue.
\n\nYou can also write your own interpretation function. The demo below adds custom interpretation to the previous demo. This function will take the same inputs as the main wrapped function. The output of this interpretation function will be used to highlight the input of each input component - therefore the function must return a list where the number of elements corresponds to the number of input components. To see the format for interpretation for each input component, check the Docs.
\n\nimport re\n\nimport gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\n# Number of arguments to interpretation function must\n# match number of inputs to prediction function\ndef interpret_gender(sentence):\n result = gender_of_sentence(sentence)\n is_male = result[\"male\"] > result[\"female\"]\n interpretation = []\n for word in re.split(\"( )\", sentence):\n score = 0\n token = word.lower()\n if (is_male and token in male_words) or (not is_male and token in female_words):\n score = 1\n elif (is_male and token in female_words) or (\n not is_male and token in male_words\n ):\n score = -1\n interpretation.append((word, score))\n # Output must be a list of lists containing the same number of elements as inputs\n # Each element corresponds to the interpretation scores for the given input\n return [interpretation]\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=interpret_gender,\n)\n\ndemo.launch()\n\n
Learn more about Interpretation in the docs.
\n\nIf you'd like to have more fine-grained control over any aspect of your demo, you can also write your own css or pass in a filepath to a css file, with the css
parameter of the Interface
class.
gr.Interface(..., css=\"body {background-color: red}\")\n
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with \"file=\"
, for example:
gr.Interface(..., css=\"body {background-image: url('file=clouds.jpg')}\")\n
Warning: Custom CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using custom CSS sparingly and instead using Themes whenever possible.
\n\nGradio integrates nicely with the Hugging Face Hub, allowing you to load models and Spaces with just one line of code. To use this, simply use the load()
method in the Interface
class. So:
\"model/\"
or \"huggingface/\"
followed by the model name, like these examples:gr.Interface.load(\"huggingface/gpt2\").launch();\n
gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\", \n inputs=gr.Textbox(lines=5, label=\"Input Text\") # customizes the input component\n).launch()\n
\"spaces/\"
followed by the model name:gr.Interface.load(\"spaces/eugenesiow/remove-bg\", \n inputs=\"webcam\", \n title=\"Remove your webcam background!\").launch()\n
One of the great things about loading Hugging Face models or spaces using Gradio is that you can then immediately use the resulting Interface
object just like function in your Python code (this works for every type of model/space: text, images, audio, video, and even multimodal models):
io = gr.Interface.load(\"models/EleutherAI/gpt-neo-2.7B\")\nio(\"It was the best of times\") # outputs model completion\n
Gradio also lets you mix interfaces very easily using the gradio.Parallel
and gradio.Series
classes. Parallel
lets you put two similar models (if they have the same input type) in parallel to compare model predictions:
generator1 = gr.Interface.load(\"huggingface/gpt2\")\ngenerator2 = gr.Interface.load(\"huggingface/EleutherAI/gpt-neo-2.7B\")\ngenerator3 = gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\")\n\ngr.Parallel(generator1, generator2, generator3).launch()\n
Series
lets you put models and spaces in series, piping the output of one model into the input of the next model.
generator = gr.Interface.load(\"huggingface/gpt2\")\ntranslator = gr.Interface.load(\"huggingface/t5-small\")\n\ngr.Series(generator, translator).launch() \n# this demo generates text, then translates it to German, and outputs the final result.\n
And of course, you can also mix Parallel
and Series
together whenever that makes sense!
Learn more about Parallel and Series in the docs.
\n", "tags": [], "spaces": [], "url": "/guides/advanced-interface-features/", "contributor": null}], "parent": "gradio"}, "series": {"class": null, "name": "Series", "description": "Creates a new Interface from multiple Interfaces in series (the output of one is fed as the input to the next, and so the input and output components must agree between the interfaces).There's more to cover on the Interface class. This guide covers all the advanced features: Using Interpretation, custom styling, loading from the Hugging Face Hub, and using Parallel and Series.
\n\nMost models are black boxes such that the internal logic of the function is hidden from the end user. To encourage transparency, we've made it very easy to add interpretation to your model by simply setting the interpretation
keyword in the Interface
class to default
. This allows your users to understand what parts of the input are responsible for the output. Take a look at the simple interface below which shows an image classifier that also includes interpretation:
import requests\nimport tensorflow as tf\n\nimport gradio as gr\n\ninception_net = tf.keras.applications.MobileNetV2() # load the model\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n return {labels[i]: float(prediction[i]) for i in range(1000)}\n\n\nimage = gr.Image(shape=(224, 224))\nlabel = gr.Label(num_top_classes=3)\n\ndemo = gr.Interface(\n fn=classify_image, inputs=image, outputs=label, interpretation=\"default\"\n)\n\ndemo.launch()\n\n
In addition to default
, Gradio also includes Shapley-based interpretation, which provides more accurate interpretations, albeit usually with a slower runtime. To use this, simply set the interpretation
parameter to \"shap\"
(note: also make sure the python package shap
is installed). Optionally, you can modify the num_shap
parameter, which controls the tradeoff between accuracy and runtime (increasing this value generally increases accuracy). Here is an example:
gr.Interface(fn=classify_image,\n inputs=image, \n outputs=label, \n interpretation=\"shap\", \n num_shap=5).launch()\n
This will work for any function, even if internally, the model is a complex neural network or some other black box. If you use Gradio's default
or shap
interpretation, the output component must be a Label
. All common input components are supported. Here is an example with text input.
import gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=\"default\",\n)\n\ndemo.launch()\n\n
So what is happening under the hood? With these interpretation methods, Gradio runs the prediction multiple times with modified versions of the input. Based on the results, you'll see that the interface automatically highlights the parts of the text (or image, etc.) that contributed increased the likelihood of the class as red. The intensity of color corresponds to the importance of that part of the input. The parts that decrease the class confidence are highlighted blue.
\n\nYou can also write your own interpretation function. The demo below adds custom interpretation to the previous demo. This function will take the same inputs as the main wrapped function. The output of this interpretation function will be used to highlight the input of each input component - therefore the function must return a list where the number of elements corresponds to the number of input components. To see the format for interpretation for each input component, check the Docs.
\n\nimport re\n\nimport gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\n# Number of arguments to interpretation function must\n# match number of inputs to prediction function\ndef interpret_gender(sentence):\n result = gender_of_sentence(sentence)\n is_male = result[\"male\"] > result[\"female\"]\n interpretation = []\n for word in re.split(\"( )\", sentence):\n score = 0\n token = word.lower()\n if (is_male and token in male_words) or (not is_male and token in female_words):\n score = 1\n elif (is_male and token in female_words) or (\n not is_male and token in male_words\n ):\n score = -1\n interpretation.append((word, score))\n # Output must be a list of lists containing the same number of elements as inputs\n # Each element corresponds to the interpretation scores for the given input\n return [interpretation]\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=interpret_gender,\n)\n\ndemo.launch()\n\n
Learn more about Interpretation in the docs.
\n\nIf you'd like to have more fine-grained control over any aspect of your demo, you can also write your own css or pass in a filepath to a css file, with the css
parameter of the Interface
class.
gr.Interface(..., css=\"body {background-color: red}\")\n
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with \"file=\"
, for example:
gr.Interface(..., css=\"body {background-image: url('file=clouds.jpg')}\")\n
Warning: Custom CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using custom CSS sparingly and instead using Themes whenever possible.
\n\nGradio integrates nicely with the Hugging Face Hub, allowing you to load models and Spaces with just one line of code. To use this, simply use the load()
method in the Interface
class. So:
\"model/\"
or \"huggingface/\"
followed by the model name, like these examples:gr.Interface.load(\"huggingface/gpt2\").launch();\n
gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\", \n inputs=gr.Textbox(lines=5, label=\"Input Text\") # customizes the input component\n).launch()\n
\"spaces/\"
followed by the model name:gr.Interface.load(\"spaces/eugenesiow/remove-bg\", \n inputs=\"webcam\", \n title=\"Remove your webcam background!\").launch()\n
One of the great things about loading Hugging Face models or spaces using Gradio is that you can then immediately use the resulting Interface
object just like function in your Python code (this works for every type of model/space: text, images, audio, video, and even multimodal models):
io = gr.Interface.load(\"models/EleutherAI/gpt-neo-2.7B\")\nio(\"It was the best of times\") # outputs model completion\n
Gradio also lets you mix interfaces very easily using the gradio.Parallel
and gradio.Series
classes. Parallel
lets you put two similar models (if they have the same input type) in parallel to compare model predictions:
generator1 = gr.Interface.load(\"huggingface/gpt2\")\ngenerator2 = gr.Interface.load(\"huggingface/EleutherAI/gpt-neo-2.7B\")\ngenerator3 = gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\")\n\ngr.Parallel(generator1, generator2, generator3).launch()\n
Series
lets you put models and spaces in series, piping the output of one model into the input of the next model.
generator = gr.Interface.load(\"huggingface/gpt2\")\ntranslator = gr.Interface.load(\"huggingface/t5-small\")\n\ngr.Series(generator, translator).launch() \n# this demo generates text, then translates it to German, and outputs the final result.\n
And of course, you can also mix Parallel
and Series
together whenever that makes sense!
Learn more about Parallel and Series in the docs.
\n", "tags": [], "spaces": [], "url": "/guides/advanced-interface-features/", "contributor": null}], "parent": "gradio"}}, "components": {"annotatedimage": {"class": null, "name": "AnnotatedImage", "description": "Displays a base image and colored subsections on top of that image. Subsections can take the from of rectangles (e.g. object detection) or masks (e.g. image segmentation).Automatic speech recognition (ASR), the conversion of spoken speech to text, is a very important and thriving area of machine learning. ASR algorithms run on practically every smartphone, and are becoming increasingly embedded in professional workflows, such as digital assistants for nurses and doctors. Because ASR algorithms are designed to be used directly by customers and end users, it is important to validate that they are behaving as expected when confronted with a wide variety of speech patterns (different accents, pitches, and background audio conditions).
\n\nUsing gradio
, you can easily build a demo of your ASR model and share that with a testing team, or test it yourself by speaking through the microphone on your device.
This tutorial will show how to take a pretrained speech-to-text model and deploy it with a Gradio interface. We will start with a full-context model, in which the user speaks the entire audio before the prediction runs. Then we will adapt the demo to make it streaming, meaning that the audio model will convert speech as you speak. The streaming demo that we create will look something like this (try it below or in a new tab!):
\n\n\n\nReal-time ASR is inherently stateful, meaning that the model's predictions change depending on what words the user previously spoke. So, in this tutorial, we will also cover how to use state with Gradio demos.
\n\nMake sure you have the gradio
Python package already installed. You will also need a pretrained speech recognition model. In this tutorial, we will build demos from 2 ASR libraries:
pip install transformers
and pip install torch
) pip install deepspeech==0.8.2
)Make sure you have at least one of these installed so that you can follow along the tutorial. You will also need ffmpeg
installed on your system, if you do not already have it, to process files from the microphone.
Here's how to build a real time speech recognition (ASR) app:
\n\nFirst, you will need to have an ASR model that you have either trained yourself or you will need to download a pretrained model. In this tutorial, we will start by using a pretrained ASR model from the Hugging Face model, Wav2Vec2
.
Here is the code to load Wav2Vec2
from Hugging Face transformers
.
from transformers import pipeline\n\np = pipeline(\"automatic-speech-recognition\")\n
That's it! By default, the automatic speech recognition model pipeline loads Facebook's facebook/wav2vec2-base-960h
model.
We will start by creating a full-context ASR demo, in which the user speaks the full audio before using the ASR model to run inference. This is very easy with Gradio -- we simply create a function around the pipeline
object above.
We will use gradio
's built in Audio
component, configured to take input from the user's microphone and return a filepath for the recorded audio. The output component will be a plain Textbox
.
import gradio as gr\n\ndef transcribe(audio):\n text = p(audio)[\"text\"]\n return text\n\ngr.Interface(\n fn=transcribe, \n inputs=gr.Audio(source=\"microphone\", type=\"filepath\"), \n outputs=\"text\").launch()\n
So what's happening here? The transcribe
function takes a single parameter, audio
, which is a filepath to the audio file that the user has recorded. The pipeline
object expects a filepath and converts it to text, which is returned to the frontend and displayed in a textbox.
Let's see it in action! (Record a short audio clip and then click submit, or open in a new tab):
\n\n\n\nOk great! We've built an ASR model that works well for short audio clips. However, if you are recording longer audio clips, you probably want a streaming interface, one that transcribes audio as the user speaks instead of just all-at-once at the end.
\n\nThe good news is that it's not too difficult to adapt the demo we just made to make it streaming, using the same Wav2Vec2
model.
The biggest change is that we must now introduce a state
parameter, which holds the audio that has been transcribed so far. This allows us to only the latest chunk of audio and simply append it to the audio we previously transcribed.
When adding state to a Gradio demo, you need to do a total of 3 things:
\n\nstate
parameter to the functionstate
at the end of the function\"state\"
components to the inputs
and outputs
in Interface
Here's what the code looks like:
\n\ndef transcribe(audio, state=\"\"):\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\n# Set the starting state to an empty string\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\" \n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Notice that we've also made one other change, which is that we've set live=True
. This keeps the Gradio interface running constantly, so it automatically transcribes audio without the user having to repeatedly hit the submit button.
Let's see how it does (try below or in a new tab)!
\n\n\n\nOne thing that you may notice is that the transcription quality has dropped since the chunks of audio are so small, they lack the context to properly be transcribed. A \"hacky\" fix to this is to simply increase the runtime of the transcribe()
function so that longer audio chunks are processed. We can do this by adding a time.sleep()
inside the function, as shown below (we'll see a proper fix next)
from transformers import pipeline\nimport gradio as gr\nimport time\n\np = pipeline(\"automatic-speech-recognition\")\n\ndef transcribe(audio, state=\"\"):\n time.sleep(2)\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\"\n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Try the demo below to see the difference (or open in a new tab)!
\n\n\n\nYou're not restricted to ASR models from the transformers
library -- you can use your own models or models from other libraries. The DeepSpeech
library contains models that are specifically designed to handle streaming audio data. These models perform really well with streaming data as they are able to account for previous chunks of audio data when making predictions.
Going through the DeepSpeech library is beyond the scope of this Guide (check out their excellent documentation here), but you can use Gradio very similarly with a DeepSpeech ASR model as with a Transformers ASR model.
\n\nHere's a complete example (on Linux):
\n\nFirst install the DeepSpeech library and download the pretrained models from the terminal:
\n\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.pbmm\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer\napt install libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 ffmpeg\npip install deepspeech==0.8.2\n
Then, create a similar transcribe()
function as before:
from deepspeech import Model\nimport numpy as np\n\nmodel_file_path = \"deepspeech-0.8.2-models.pbmm\"\nlm_file_path = \"deepspeech-0.8.2-models.scorer\"\nbeam_width = 100\nlm_alpha = 0.93\nlm_beta = 1.18\n\nmodel = Model(model_file_path)\nmodel.enableExternalScorer(lm_file_path)\nmodel.setScorerAlphaBeta(lm_alpha, lm_beta)\nmodel.setBeamWidth(beam_width)\n\n\ndef reformat_freq(sr, y):\n if sr not in (\n 48000,\n 16000,\n ): # Deepspeech only supports 16k, (we convert 48k -> 16k)\n raise ValueError(\"Unsupported rate\", sr)\n if sr == 48000:\n y = (\n ((y / max(np.max(y), 1)) * 32767)\n .reshape((-1, 3))\n .mean(axis=1)\n .astype(\"int16\")\n )\n sr = 16000\n return sr, y\n\n\ndef transcribe(speech, stream):\n _, y = reformat_freq(*speech)\n if stream is None:\n stream = model.createStream()\n stream.feedAudioContent(y)\n text = stream.intermediateDecode()\n return text, stream\n\n
Then, create a Gradio Interface as before (the only difference being that the return type should be numpy
instead of a filepath
to be compatible with the DeepSpeech models)
import gradio as gr\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"numpy\"), \n \"state\" \n ], \n outputs= [\n \"text\", \n \"state\"\n ], \n live=True).launch()\n
Running all of this should allow you to deploy your realtime ASR model with a nice GUI. Try it out and see how well it works for you.
\n\nAnd you're done! That's all the code you need to build a web-based GUI for your ASR model.
\n\nFun tip: you can share your ASR model instantly with others simply by setting share=True
in launch()
.
Let's go through some of the most popular features of Gradio! Here are Gradio's key features:
\n\nYou can provide example data that a user can easily load into Interface
. This can be helpful to demonstrate the types of inputs the model expects, as well as to provide a way to explore your dataset in conjunction with your model. To load example data, you can provide a nested list to the examples=
keyword argument of the Interface constructor. Each sublist within the outer list represents a data sample, and each element within the sublist represents an input for each input component. The format of example data for each component is specified in the Docs.
import gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n if num2 == 0:\n raise gr.Error(\"Cannot divide by zero!\")\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\", \n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n examples=[\n [5, \"add\", 3],\n [4, \"divide\", 2],\n [-4, \"multiply\", 2.5],\n [0, \"subtract\", 1.2],\n ],\n title=\"Toy Calculator\",\n description=\"Here's a sample toy calculator. Allows you to calculate things like $2+2=4$\",\n)\ndemo.launch()\n\n
You can load a large dataset into the examples to browse and interact with the dataset through Gradio. The examples will be automatically paginated (you can configure this through the examples_per_page
argument of Interface
).
Continue learning about examples in the More On Examples guide.
\n\nYou wish to pass custom error messages to the user. To do so, raise a gr.Error(\"custom message\")
to display an error message. If you try to divide by zero in the calculator demo above, a popup modal will display the custom error message. Learn more about Error in the docs.
You can also issue gr.Warning(\"message\")
and gr.Info(\"message\")
by having them as standalone lines in your function, which will immediately display modals while continuing the execution of your function. Queueing needs to be enabled for this to work.
Note below how the gr.Error
has to be raised, while the gr.Warning
and gr.Info
are single lines.
def start_process(name):\n gr.Info(\"Starting process\")\n if name is None:\n gr.Warning(\"Name is empty\")\n ...\n if success == False:\n raise gr.Error(\"Process failed\")\n
In the previous example, you may have noticed the title=
and description=
keyword arguments in the Interface
constructor that helps users understand your app.
There are three arguments in the Interface
constructor to specify where this content should go:
title
: which accepts text and can display it at the very top of interface, and also becomes the page title.description
: which accepts text, markdown or HTML and places it right under the title.article
: which also accepts text, markdown or HTML and places it below the interface.If you're using the Blocks
API instead, you can insert text, markdown, or HTML anywhere using the gr.Markdown(...)
or gr.HTML(...)
components, with descriptive content inside the Component
constructor.
Another useful keyword argument is label=
, which is present in every Component
. This modifies the label text at the top of each Component
. You can also add the info=
keyword argument to form elements like Textbox
or Radio
to provide further information on their usage.
gr.Number(label='Age', info='In years, must be greater than 0')\n
By default, an Interface
will have \"Flag\" button. When a user testing your Interface
sees input with interesting output, such as erroneous or unexpected model behaviour, they can flag the input for you to review. Within the directory provided by the flagging_dir=
argument to the Interface
constructor, a CSV file will log the flagged inputs. If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well.
For example, with the calculator interface shown above, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- calculator.py\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output\n5,add,7,12\n6,subtract,1.5,4.5\n
With the sepia interface shown earlier, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- sepia.py\n+-- flagged/\n| +-- logs.csv\n| +-- im/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output\nim/0.png,Output/0.png\nim/1.png,Output/1.png\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of the strings when flagging, which will be saved as an additional column to the CSV.
As you've seen, Gradio includes components that can handle a variety of different data types, such as images, audio, and video. Most components can be used both as inputs or outputs.
\n\nWhen a component is used as an input, Gradio automatically handles the preprocessing needed to convert the data from a type sent by the user's browser (such as a base64 representation of a webcam snapshot) to a form that can be accepted by your function (such as a numpy
array).
Similarly, when a component is used as an output, Gradio automatically handles the postprocessing needed to convert the data from what is returned by your function (such as a list of image paths) to a form that can be displayed in the user's browser (such as a Gallery
of images in base64 format).
You can control the preprocessing using the parameters when constructing the image component. For example, here if you instantiate the Image
component with the following parameters, it will convert the image to the PIL
type and reshape it to be (100, 100)
no matter the original size that it was submitted as:
img = gr.Image(shape=(100, 100), type=\"pil\")\n
In contrast, here we keep the original size of the image, but invert the colors before converting it to a numpy array:
\n\nimg = gr.Image(invert_colors=True, type=\"numpy\")\n
Postprocessing is a lot easier! Gradio automatically recognizes the format of the returned data (e.g. is the Image
a numpy
array or a str
filepath?) and postprocesses it into a format that can be displayed by the browser.
Take a look at the Docs to see all the preprocessing-related parameters for each Component.
\n\nGradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the theme=
kwarg to the Interface
constructor. For example:
demo = gr.Interface(..., theme=gr.themes.Monochrome())\n
Gradio comes with a set of prebuilt themes which you can load from gr.themes.*
. You can extend these themes or create your own themes from scratch - see the Theming guide for more details.
For additional styling ability, you can pass any CSS to your app using the css=
kwarg.\nThe base class for the Gradio app is gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Interface(css=\".gradio-container {background-color: red}\") as demo:\n ...\n
Some components can be additionally styled through the style()
method. For example:
img = gr.Image(\"lion.jpg\").style(height='24', rounded=False)\n
Take a look at the Docs to see all the styling options for each Component.
\n\nIf your app expects heavy traffic, use the queue()
method to control processing rate. This will queue up calls so only a certain number of requests are processed at a single time. Queueing uses websockets, which also prevent network timeouts, so you should use queueing if the inference time of your function is long (> 1min).
With Interface
:
demo = gr.Interface(...).queue()\ndemo.launch()\n
With Blocks
:
with gr.Blocks() as demo:\n #...\ndemo.queue()\ndemo.launch()\n
You can control the number of requests processed at a single time as such:
\n\ndemo.queue(concurrency_count=3)\n
See the Docs on queueing on configuring other queuing parameters.
\n\nTo specify only certain functions for queueing in Blocks:
\n\nwith gr.Blocks() as demo2:\n num1 = gr.Number()\n num2 = gr.Number()\n output = gr.Number()\n gr.Button(\"Add\").click(\n lambda a, b: a + b, [num1, num2], output)\n gr.Button(\"Multiply\").click(\n lambda a, b: a * b, [num1, num2], output, queue=True)\ndemo2.launch()\n
In some cases, you may want to stream a sequence of outputs rather than show a single output at once. For example, you might have an image generation model and you want to show the image that is generated at each step, leading up to the final image. Or you might have a chatbot which streams its response one word at a time instead of returning it all at once.
\n\nIn such cases, you can supply a generator function into Gradio instead of a regular function. Creating generators in Python is very simple: instead of a single return
value, a function should yield
a series of values instead. Usually the yield
statement is put in some kind of loop. Here's an example of an generator that simply counts up to a given number:
def my_generator(x):\n for i in range(x):\n yield i\n
You supply a generator into Gradio the same way as you would a regular function. For example, here's a a (fake) image generation model that generates noise for several steps before outputting an image:
\n\nimport gradio as gr\nimport numpy as np\nimport time\n\n# define core fn, which returns a generator {steps} times before returning the image\ndef fake_diffusion(steps):\n for _ in range(steps):\n time.sleep(1)\n image = np.random.random((600, 600, 3))\n yield image\n image = \"https://gradio-builds.s3.amazonaws.com/diffusion_image/cute_dog.jpg\"\n yield image\n\n\ndemo = gr.Interface(fake_diffusion, inputs=gr.Slider(1, 10, 3), outputs=\"image\")\n\n# define queue - required for generators\ndemo.queue()\n\ndemo.launch()\n\n
Note that we've added a time.sleep(1)
in the iterator to create an artificial pause between steps so that you are able to observe the steps of the iterator (in a real image generation model, this probably wouldn't be necessary).
Supplying a generator into Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio supports the ability to create a custom Progress Bars so that you have customizability and control over the progress update that you show to the user. In order to enable this, simply add an argument to your method that has a default value of a gr.Progress
instance. Then you can update the progress levels by calling this instance directly with a float between 0 and 1, or using the tqdm()
method of the Progress
instance to track progress over an iterable, as shown below. Queueing must be enabled for progress updates.
import gradio as gr\nimport time\n\ndef slowly_reverse(word, progress=gr.Progress()):\n progress(0, desc=\"Starting\")\n time.sleep(1)\n progress(0.05)\n new_string = \"\"\n for letter in progress.tqdm(word, desc=\"Reversing\"):\n time.sleep(0.25)\n new_string = letter + new_string\n return new_string\n\ndemo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())\n\nif __name__ == \"__main__\":\n demo.queue(concurrency_count=10).launch()\n\n
If you use the tqdm
library, you can even report progress updates automatically from any tqdm.tqdm
that already exists within your function by setting the default argument as gr.Progress(track_tqdm=True)
!
Gradio supports the ability to pass batch functions. Batch functions are just\nfunctions which take in a list of inputs and return a list of predictions.
\n\nFor example, here is a batched function that takes in two lists of inputs (a list of\nwords and a list of ints), and returns a list of trimmed words as output:
\n\nimport time\n\ndef trim_words(words, lens):\n trimmed_words = []\n time.sleep(5)\n for w, l in zip(words, lens):\n trimmed_words.append(w[:int(l)]) \n return [trimmed_words]\n
The advantage of using batched functions is that if you enable queuing, the Gradio\nserver can automatically batch incoming requests and process them in parallel,\npotentially speeding up your demo. Here's what the Gradio code looks like (notice\nthe batch=True
and max_batch_size=16
-- both of these parameters can be passed\ninto event triggers or into the Interface
class)
With Interface
:
demo = gr.Interface(trim_words, [\"textbox\", \"number\"], [\"output\"], \n batch=True, max_batch_size=16)\ndemo.queue()\ndemo.launch()\n
With Blocks
:
import gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n word = gr.Textbox(label=\"word\")\n leng = gr.Number(label=\"leng\")\n output = gr.Textbox(label=\"Output\")\n with gr.Row():\n run = gr.Button()\n\n event = run.click(trim_words, [word, leng], output, batch=True, max_batch_size=16)\n\ndemo.queue()\ndemo.launch()\n
In the example above, 16 requests could be processed in parallel (for a total inference\ntime of 5 seconds), instead of each request being processed separately (for a total\ninference time of 80 seconds). Many Hugging Face transformers
and diffusers
models\nwork very naturally with Gradio's batch mode: here's an example demo using diffusers to\ngenerate images in batches
Note: using batch functions with Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio is able to run anywhere you run Python, including local jupyter notebooks as well as collaborative notebooks, such as Google Colab. In the case of local jupyter notebooks and Google Colab notbooks, Gradio runs on a local server which you can interact with in your browser. (Note: for Google Colab, this is accomplished by service worker tunneling, which requires cookies to be enabled in your browser.) For other remote notebooks, Gradio will also run on a server, but you will need to use SSH tunneling to view the app in your local browser. Often a simpler options is to use Gradio's built-in public links, discussed in the next Guide.
\n", "tags": [], "spaces": [], "url": "/guides/key-features/", "contributor": null}], "preprocessing": "this component does *not* accept input.", "postprocessing": "expects a valid HTML str.", "parent": "gradio", "prev_obj": "Gallery", "next_obj": "HighlightedText"}, "highlightedtext": {"class": null, "name": "HighlightedText", "description": "Displays text that contains spans that are highlighted by category or numerical value.Named-entity recognition (NER), also known as token classification or text tagging, is the task of taking a sentence and classifying every word (or \"token\") into different categories, such as names of people or names of locations, or different parts of speech.
\n\nFor example, given the sentence:
\n\n\n\n\nDoes Chicago have any Pakistani restaurants?
\n
A named-entity recognition algorithm may identify:
\n\nand so on.
\n\nUsing gradio
(specifically the HighlightedText
component), you can easily build a web demo of your NER model and share that with the rest of your team.
Here is an example of a demo that you'll be able to build:
\n\nThis tutorial will show how to take a pretrained NER model and deploy it with a Gradio interface. We will show two different ways to use the HighlightedText
component -- depending on your NER model, either of these two ways may be easier to learn!
Make sure you have the gradio
Python package already installed. You will also need a pretrained named-entity recognition model. You can use your own, while in this tutorial, we will use one from the transformers
library.
Many named-entity recognition models output a list of dictionaries. Each dictionary consists of an entity, a \"start\" index, and an \"end\" index. This is, for example, how NER models in the transformers
library operate:
from transformers import pipeline \nner_pipeline = pipeline(\"ner\")\nner_pipeline(\"Does Chicago have any Pakistani restaurants\")\n
Output:
\n\n[{'entity': 'I-LOC',\n 'score': 0.9988978,\n 'index': 2,\n 'word': 'Chicago',\n 'start': 5,\n 'end': 12},\n {'entity': 'I-MISC',\n 'score': 0.9958592,\n 'index': 5,\n 'word': 'Pakistani',\n 'start': 22,\n 'end': 31}]\n
If you have such a model, it is very easy to hook it up to Gradio's HighlightedText
component. All you need to do is pass in this list of entities, along with the original text to the model, together as dictionary, with the keys being \"entities\"
and \"text\"
respectively.
Here is a complete example:
\n\nfrom transformers import pipeline\n\nimport gradio as gr\n\nner_pipeline = pipeline(\"ner\")\n\nexamples = [\n \"Does Chicago have any stores and does Joe live here?\",\n]\n\ndef ner(text):\n output = ner_pipeline(text)\n return {\"text\": text, \"entities\": output} \n\ndemo = gr.Interface(ner,\n gr.Textbox(placeholder=\"Enter sentence here...\"), \n gr.HighlightedText(),\n examples=examples)\n\ndemo.launch()\n\n
An alternative way to pass data into the HighlightedText
component is a list of tuples. The first element of each tuple should be the word or words that are being classified into a particular entity. The second element should be the entity label (or None
if they should be unlabeled). The HighlightedText
component automatically strings together the words and labels to display the entities.
In some cases, this can be easier than the first approach. Here is a demo showing this approach using Spacy's parts-of-speech tagger:
\n\nimport gradio as gr\nimport os\nos.system('python -m spacy download en_core_web_sm')\nimport spacy\nfrom spacy import displacy\n\nnlp = spacy.load(\"en_core_web_sm\")\n\ndef text_analysis(text):\n doc = nlp(text)\n html = displacy.render(doc, style=\"dep\", page=True)\n html = (\n \"\"\n + html\n + \"\"\n )\n pos_count = {\n \"char_count\": len(text),\n \"token_count\": 0,\n }\n pos_tokens = []\n\n for token in doc:\n pos_tokens.extend([(token.text, token.pos_), (\" \", None)])\n\n return pos_tokens, pos_count, html\n\ndemo = gr.Interface(\n text_analysis,\n gr.Textbox(placeholder=\"Enter sentence here...\"),\n [\"highlight\", \"json\", \"html\"],\n examples=[\n [\"What a beautiful morning for a walk!\"],\n [\"It was the best of times, it was the worst of times.\"],\n ],\n)\n\ndemo.launch()\n\n
And you're done! That's all you need to know to build a web-based GUI for your NER model.
\n\nFun tip: you can share your NER demo instantly with others simply by setting share=True
in launch()
.
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from autonomous vehicles to medical imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained image classification model, so you should also have torch
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Resnet-18 model, as it is easily downloadable from PyTorch Hub. You can use a different pretrained model or train your own.
\n\nimport torch\n\nmodel = torch.hub.load('pytorch/vision:v0.6.0', 'resnet18', pretrained=True).eval()\n
Because we will be using the model for inference, we have called the .eval()
method.
predict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\nfrom PIL import Image\nfrom torchvision import transforms\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef predict(inp):\n inp = transforms.ToTensor()(inp).unsqueeze(0)\n with torch.no_grad():\n prediction = torch.nn.functional.softmax(model(inp)[0], dim=0)\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)} \n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a PIL
imageThen, the function converts the image to a PIL Image and then eventually a PyTorch tensor
, passes it through the model, and returns:
confidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we use Image(type=\"pil\")
which creates the component and handles the preprocessing to convert that to a PIL
image.
The output component will be a Label
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images by constructing it as Label(num_top_classes=3)
.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=predict, \n inputs=gr.Image(type=\"pil\"),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"lion.jpg\", \"cheetah.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from traffic control systems to satellite imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained Keras image classification model, so you should also have tensorflow
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Mobile Net model, as it is easily downloadable from Keras. You can use a different pretrained model or train your own.
\n\nimport tensorflow as tf\n\ninception_net = tf.keras.applications.MobileNetV2()\n
This line automatically downloads the MobileNet model and weights using the Keras library.
\n\npredict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)}\n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a numpy
arrayThen, the function adds a batch dimension, passes it through the model, and returns:
\n\nconfidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we can use the \"gradio.inputs.Image\"
class, which creates the component and handles the preprocessing to convert that to a numpy array. We will instantiate the class with a parameter that automatically preprocesses the input image to be 224 pixels by 224 pixels, which is the size that MobileNet expects.
The output component will be a \"label\"
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=classify_image, \n inputs=gr.Image(shape=(224, 224)),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"banana.jpg\", \"car.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from facial recognition to manufacturing quality control.
\n\nState-of-the-art image classifiers are based on the transformers architectures, originally popularized for NLP tasks. Such architectures are typically called vision transformers (ViT). Such models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in a single line of Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed.
First, we will need an image classification model. For this tutorial, we will use a model from the Hugging Face Model Hub. The Hub contains thousands of models covering dozens of different machine learning tasks.
\n\nExpand the Tasks category on the left sidebar and select \"Image Classification\" as our task of interest. You will then see all of the models on the Hub that are designed to classify images.
\n\nAt the time of writing, the most popular one is google/vit-base-patch16-224
, which has been trained on ImageNet images at a resolution of 224x224 pixels. We will use this model for our demo.
When using a model from the Hugging Face Hub, we do not need to define the input or output components for the demo. Similarly, we do not need to be concerned with the details of preprocessing or postprocessing. \nAll of these are automatically inferred from the model tags.
\n\nBesides the import statement, it only takes a single line of Python to load and launch the demo.
\n\nWe use the gr.Interface.load()
method and pass in the path to the model including the huggingface/
to designate that it is from the Hugging Face Hub.
import gradio as gr\n\ngr.Interface.load(\n \"huggingface/google/vit-base-patch16-224\",\n examples=[\"alligator.jpg\", \"laptop.jpg\"]).launch()\n
Notice that we have added one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples.
This produces the following interface, which you can try right here in your browser. When you input an image, it is automatically preprocessed and sent to the Hugging Face Hub API, where it is passed through the model and returned as a human-interpretable prediction. Try uploading your own image!
\n\n\n\nAnd you're done! In one line of code, you have built a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
It seems that cryptocurrencies, NFTs, and the web3 movement are all the rage these days! Digital assets are being listed on marketplaces for astounding amounts of money, and just about every celebrity is debuting their own NFT collection. While your crypto assets may be taxable, such as in Canada, today we'll explore some fun and tax-free ways to generate your own assortment of procedurally generated CryptoPunks.
\n\nGenerative Adversarial Networks, often known just as GANs, are a specific class of deep-learning models that are designed to learn from an input dataset to create (generate!) new material that is convincingly similar to elements of the original training set. Famously, the website thispersondoesnotexist.com went viral with lifelike, yet synthetic, images of people generated with a model called StyleGAN2. GANs have gained traction in the machine learning world, and are now being used to generate all sorts of images, text, and even music!
\n\nToday we'll briefly look at the high-level intuition behind GANs, and then we'll build a small demo around a pre-trained GAN to see what all the fuss is about. Here's a peek at what we're going to be putting together:
\n\n\n\nMake sure you have the gradio
Python package already installed. To use the pretrained model, also install torch
and torchvision
.
Originally proposed in Goodfellow et al. 2014, GANs are made up of neural networks which compete with the intention of outsmarting each other. One network, known as the generator, is responsible for generating images. The other network, the discriminator, receives an image at a time from the generator along with a real image from the training data set. The discriminator then has to guess: which image is the fake?
\n\nThe generator is constantly training to create images which are trickier for the discriminator to identify, while the discriminator raises the bar for the generator every time it correctly detects a fake. As the networks engage in this competitive (adversarial!) relationship, the images that get generated improve to the point where they become indistinguishable to human eyes!
\n\nFor a more in-depth look at GANs, you can take a look at this excellent post on Analytics Vidhya or this PyTorch tutorial. For now, though, we'll dive into a demo!
\n\nTo generate new images with a GAN, you only need the generator model. There are many different architectures that the generator could use, but for this demo we'll use a pretrained GAN generator model with the following architecture:
\n\nfrom torch import nn\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n
We're taking the generator from this repo by @teddykoker, where you can also see the original discriminator model structure.
\n\nAfter instantiating the model, we'll load in the weights from the Hugging Face Hub, stored at nateraw/cryptopunks-gan:
\n\nfrom huggingface_hub import hf_hub_download\nimport torch\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n
predict
functionThe predict
function is the key to making Gradio work! Whatever inputs we choose through the Gradio interface will get passed through our predict
function, which should operate on the inputs and generate outputs that we can display with Gradio output components. For GANs it's common to pass random noise into our model as the input, so we'll generate a tensor of random numbers and pass that through the model. We can then use torchvision
's save_image
function to save the output of the model as a png
file, and return the file name:
from torchvision.utils import save_image\n\ndef predict(seed):\n num_punks = 4\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
We're giving our predict
function a seed
parameter, so that we can fix the random tensor generation with a seed. We'll then be able to reproduce punks if we want to see them again by passing in the same seed.
Note! Our model needs an input tensor of dimensions 100x1x1 to do a single inference, or (BatchSize)x100x1x1 for generating a batch of images. In this demo we'll start by generating 4 punks at a time.
\n\nAt this point you can even run the code you have with predict(<SOME_NUMBER>)
, and you'll find your freshly generated punks in your file system at ./punks.png
. To make a truly interactive demo, though, we'll build out a simple interface with Gradio. Our goals here are to:
predict()
to take the seed and generate the imagesWith gr.Interface()
, we can define all of that with a single function call:
import gradio as gr\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n ],\n outputs=\"image\",\n).launch()\n
Launching the interface should present you with something like this:
\n\n\n\nGenerating 4 punks at a time is a good start, but maybe we'd like to control how many we want to make each time. Adding more inputs to our Gradio interface is as simple as adding another item to the inputs
list that we pass to gr.Interface
:
gr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10), # Adding another slider!\n ],\n outputs=\"image\",\n).launch()\n
The new input will be passed to our predict()
function, so we have to make some changes to that function to accept a new parameter:
def predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
When you relaunch your interface, you should see a second slider that'll let you control the number of punks!
\n\nYour Gradio app is pretty much good to go, but you can add a few extra things to really make it ready for the spotlight \u2728
\n\nWe can add some examples that users can easily try out by adding this to the gr.Interface
:
gr.Interface(\n # ...\n # keep everything as it is, and then add\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True) # cache_examples is optional\n
The examples
parameter takes a list of lists, where each item in the sublists is ordered in the same order that we've listed the inputs
. So in our case, [seed, num_punks]
. Give it a try!
You can also try adding a title
, description
, and article
to the gr.Interface
. Each of those parameters accepts a string, so try it out and see what happens \ud83d\udc40 article
will also accept HTML, as explored in a previous guide!
When you're all done, you may end up with something like this:
\n\n\n\nFor reference, here is our full code:
\n\nimport torch\nfrom torch import nn\nfrom huggingface_hub import hf_hub_download\nfrom torchvision.utils import save_image\nimport gradio as gr\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n\ndef predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10),\n ],\n outputs=\"image\",\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True)\n
Congratulations! You've built out your very own GAN-powered CryptoPunks generator, with a fancy Gradio interface that makes it easy for anyone to use. Now you can scour the Hub for more GANs (or train your own) and continue making even more awesome demos \ud83e\udd17
\n", "tags": ["GAN", "IMAGE", "HUB"], "spaces": ["https://huggingface.co/spaces/NimaBoscarino/cryptopunks", "https://huggingface.co/spaces/nateraw/cryptopunks-generator"], "url": "/guides/create-your-own-friends-with-a-gan/", "contributor": "Nima Boscarino and Nate Raw"}], "preprocessing": "passes the uploaded image as a numpy.array, PIL.Image or str filepath depending on `type` -- unless `tool` is `sketch` AND source is one of `upload` or `webcam`. In these cases, a dict with keys `image` and `mask` is passed, and the format of the corresponding values depends on `type`.", "postprocessing": "expects a numpy.array, PIL.Image or str or pathlib.Path filepath to an image and displays the image.", "examples-format": "a str filepath to a local file that contains the image.", "parent": "gradio", "prev_obj": "HighlightedText", "next_obj": "Interpretation"}, "interpretation": {"class": null, "name": "Interpretation", "description": "Used to create an interpretation widget for a component.Prerequisite: This Guide requires you to know about Blocks and the interpretation feature of Interfaces.\nMake sure to read the Guide to Blocks first as well as the\ninterpretation section of the Advanced Interface Features Guide.
\n\nIf you have experience working with the Interface class, then you know that interpreting the prediction of your machine learning model\nis as easy as setting the interpretation
parameter to either \"default\" or \"shap\".
You may be wondering if it is possible to add the same interpretation functionality to an app built with the Blocks API.\nNot only is it possible, but the flexibility of Blocks lets you display the interpretation output in ways that are\nimpossible to do with Interfaces!
\n\nThis guide will show how to:
\n\nLet's get started!
\n\nLet's build a sentiment classification app with the Blocks API.\nThis app will take text as input and output the probability that this text expresses either negative or positive sentiment.\nWe'll have a single input Textbox
and a single output Label
component.\nBelow is the code for the app as well as the app itself.
import gradio as gr \nfrom transformers import pipeline\n\nsentiment_classifier = pipeline(\"text-classification\", return_all_scores=True)\n\ndef classifier(text):\n pred = sentiment_classifier(text)\n return {p[\"label\"]: p[\"score\"] for p in pred[0]}\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n\n classify.click(classifier, input_text, label)\ndemo.launch()\n
Our goal is to present to our users how the words in the input contribute to the model's prediction.\nThis will help our users understand how the model works and also evaluate its effectiveness.\nFor example, we should expect our model to identify the words \"happy\" and \"love\" with positive sentiment - if not it's a sign we made a mistake in training it!
\n\nFor each word in the input, we will compute a score of how much the model's prediction of positive sentiment is changed by that word.\nOnce we have those (word, score)
pairs we can use gradio to visualize them for the user.
The shap library will help us compute the (word, score)
pairs and\ngradio will take care of displaying the output to the user.
The following code computes the (word, score)
pairs:
def interpretation_function(text):\n explainer = shap.Explainer(sentiment_classifier)\n shap_values = explainer([text])\n\n # Dimensions are (batch size, text size, number of classes)\n # Since we care about positive sentiment, use index 1\n scores = list(zip(shap_values.data[0], shap_values.values[0, :, 1]))\n # Scores contains (word, score) pairs\n\n\n # Format expected by gr.components.Interpretation\n return {\"original\": text, \"interpretation\": scores}\n
Now, all we have to do is add a button that runs this function when clicked.\nTo display the interpretation, we will use gr.components.Interpretation
.\nThis will color each word in the input either red or blue.\nRed if it contributes to positive sentiment and blue if it contributes to negative sentiment.\nThis is how Interface
displays the interpretation output for text.
with gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n interpret = gr.Button(\"Interpret\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n with gr.Column():\n interpretation = gr.components.Interpretation(input_text)\n classify.click(classifier, input_text, label)\n interpret.click(interpretation_function, input_text, interpretation)\n\ndemo.launch()\n
The gr.components.Interpretation
component does a good job of showing how individual words contribute to the sentiment prediction,\nbut what if we also wanted to display the score themselves along with the words?
One way to do this would be to generate a bar plot where the words are on the horizontal axis and the bar height corresponds\nto the shap score.
\n\nWe can do this by modifying our interpretation_function
to additionally return a matplotlib bar plot.\nWe will display it with the gr.Plot
component in a separate tab.
This is how the interpretation function will look:
\n\ndef interpretation_function(text):\n explainer = shap.Explainer(sentiment_classifier)\n shap_values = explainer([text])\n # Dimensions are (batch size, text size, number of classes)\n # Since we care about positive sentiment, use index 1\n scores = list(zip(shap_values.data[0], shap_values.values[0, :, 1]))\n\n scores_desc = sorted(scores, key=lambda t: t[1])[::-1]\n\n # Filter out empty string added by shap\n scores_desc = [t for t in scores_desc if t[0] != \"\"]\n\n fig_m = plt.figure()\n\n # Select top 5 words that contribute to positive sentiment\n plt.bar(x=[s[0] for s in scores_desc[:5]],\n height=[s[1] for s in scores_desc[:5]])\n plt.title(\"Top words contributing to positive sentiment\")\n plt.ylabel(\"Shap Value\")\n plt.xlabel(\"Word\")\n return {\"original\": text, \"interpretation\": scores}, fig_m\n
And this is how the app code will look:
\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n input_text = gr.Textbox(label=\"Input Text\")\n with gr.Row():\n classify = gr.Button(\"Classify Sentiment\")\n interpret = gr.Button(\"Interpret\")\n with gr.Column():\n label = gr.Label(label=\"Predicted Sentiment\")\n with gr.Column():\n with gr.Tabs():\n with gr.TabItem(\"Display interpretation with built-in component\"):\n interpretation = gr.components.Interpretation(input_text)\n with gr.TabItem(\"Display interpretation with plot\"):\n interpretation_plot = gr.Plot()\n\n classify.click(classifier, input_text, label)\n interpret.click(interpretation_function, input_text, [interpretation, interpretation_plot])\n\ndemo.launch()\n
You can see the demo below!
\n\nAlthough we have focused on sentiment classification so far, you can add interpretations to almost any machine learning model.\nThe output must be an gr.Image
or gr.Label
but the input can be almost anything (gr.Number
, gr.Slider
, gr.Radio
, gr.Image
).
Here is a demo built with blocks of interpretations for an image classification model:
\n\nWe did a deep dive \ud83e\udd3f into how interpretations work and how you can add them to your Blocks app.
\n\nWe also showed how the Blocks API gives you the power to control how the interpretation is visualized in your app.
\n\nAdding interpretations is a helpful way to make your users understand and gain trust in your model.\nNow you have all the tools you need to add them to all of your apps!
\n", "tags": ["INTERPRETATION", "SENTIMENT ANALYSIS"], "spaces": [], "url": "/guides/custom-interpretations-with-blocks/", "contributor": null}], "preprocessing": "this component does *not* accept input.", "postprocessing": "expects a dict with keys \"original\" and \"interpretation\".", "parent": "gradio", "prev_obj": "Image", "next_obj": "JSON"}, "json": {"class": null, "name": "JSON", "description": "Used to display arbitrary JSON output prettily.Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from autonomous vehicles to medical imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained image classification model, so you should also have torch
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Resnet-18 model, as it is easily downloadable from PyTorch Hub. You can use a different pretrained model or train your own.
\n\nimport torch\n\nmodel = torch.hub.load('pytorch/vision:v0.6.0', 'resnet18', pretrained=True).eval()\n
Because we will be using the model for inference, we have called the .eval()
method.
predict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\nfrom PIL import Image\nfrom torchvision import transforms\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef predict(inp):\n inp = transforms.ToTensor()(inp).unsqueeze(0)\n with torch.no_grad():\n prediction = torch.nn.functional.softmax(model(inp)[0], dim=0)\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)} \n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a PIL
imageThen, the function converts the image to a PIL Image and then eventually a PyTorch tensor
, passes it through the model, and returns:
confidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we use Image(type=\"pil\")
which creates the component and handles the preprocessing to convert that to a PIL
image.
The output component will be a Label
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images by constructing it as Label(num_top_classes=3)
.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=predict, \n inputs=gr.Image(type=\"pil\"),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"lion.jpg\", \"cheetah.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from traffic control systems to satellite imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained Keras image classification model, so you should also have tensorflow
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Mobile Net model, as it is easily downloadable from Keras. You can use a different pretrained model or train your own.
\n\nimport tensorflow as tf\n\ninception_net = tf.keras.applications.MobileNetV2()\n
This line automatically downloads the MobileNet model and weights using the Keras library.
\n\npredict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)}\n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a numpy
arrayThen, the function adds a batch dimension, passes it through the model, and returns:
\n\nconfidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we can use the \"gradio.inputs.Image\"
class, which creates the component and handles the preprocessing to convert that to a numpy array. We will instantiate the class with a parameter that automatically preprocesses the input image to be 224 pixels by 224 pixels, which is the size that MobileNet expects.
The output component will be a \"label\"
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=classify_image, \n inputs=gr.Image(shape=(224, 224)),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"banana.jpg\", \"car.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from facial recognition to manufacturing quality control.
\n\nState-of-the-art image classifiers are based on the transformers architectures, originally popularized for NLP tasks. Such architectures are typically called vision transformers (ViT). Such models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in a single line of Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed.
First, we will need an image classification model. For this tutorial, we will use a model from the Hugging Face Model Hub. The Hub contains thousands of models covering dozens of different machine learning tasks.
\n\nExpand the Tasks category on the left sidebar and select \"Image Classification\" as our task of interest. You will then see all of the models on the Hub that are designed to classify images.
\n\nAt the time of writing, the most popular one is google/vit-base-patch16-224
, which has been trained on ImageNet images at a resolution of 224x224 pixels. We will use this model for our demo.
When using a model from the Hugging Face Hub, we do not need to define the input or output components for the demo. Similarly, we do not need to be concerned with the details of preprocessing or postprocessing. \nAll of these are automatically inferred from the model tags.
\n\nBesides the import statement, it only takes a single line of Python to load and launch the demo.
\n\nWe use the gr.Interface.load()
method and pass in the path to the model including the huggingface/
to designate that it is from the Hugging Face Hub.
import gradio as gr\n\ngr.Interface.load(\n \"huggingface/google/vit-base-patch16-224\",\n examples=[\"alligator.jpg\", \"laptop.jpg\"]).launch()\n
Notice that we have added one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples.
This produces the following interface, which you can try right here in your browser. When you input an image, it is automatically preprocessed and sent to the Hugging Face Hub API, where it is passed through the model and returned as a human-interpretable prediction. Try uploading your own image!
\n\n\n\nAnd you're done! In one line of code, you have built a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
How well can an algorithm guess what you're drawing? A few years ago, Google released the Quick Draw dataset, which contains drawings made by humans of a variety of every objects. Researchers have used this dataset to train models to guess Pictionary-style drawings.
\n\nSuch models are perfect to use with Gradio's sketchpad input, so in this tutorial we will build a Pictionary web application using Gradio. We will be able to build the whole web application in Python, and will look like this (try drawing something!):
\n\n\n\nLet's get started! This guide covers how to build a pictionary app (step-by-step):
\n\n\n\nMake sure you have the gradio
Python package already installed. To use the pretrained sketchpad model, also install torch
.
First, you will need a sketch recognition model. Since many researchers have already trained their own models on the Quick Draw dataset, we will use a pretrained model in this tutorial. Our model is a light 1.5 MB model trained by Nate Raw, that you can download here.
\n\nIf you are interested, here is the code that was used to train the model. We will simply load the pretrained model in PyTorch, as follows:
\n\nimport torch\nfrom torch import nn\n\nmodel = nn.Sequential(\n nn.Conv2d(1, 32, 3, padding='same'),\n nn.ReLU(),\n nn.MaxPool2d(2),\n nn.Conv2d(32, 64, 3, padding='same'),\n nn.ReLU(),\n nn.MaxPool2d(2),\n nn.Conv2d(64, 128, 3, padding='same'),\n nn.ReLU(),\n nn.MaxPool2d(2),\n nn.Flatten(),\n nn.Linear(1152, 256),\n nn.ReLU(),\n nn.Linear(256, len(LABELS)),\n)\nstate_dict = torch.load('pytorch_model.bin', map_location='cpu')\nmodel.load_state_dict(state_dict, strict=False)\nmodel.eval()\n
predict
functionNext, you will need to define a function that takes in the user input, which in this case is a sketched image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nfrom pathlib import Path\n\nLABELS = Path('class_names.txt').read_text().splitlines()\n\ndef predict(img):\n x = torch.tensor(img, dtype=torch.float32).unsqueeze(0).unsqueeze(0) / 255.\n with torch.no_grad():\n out = model(x)\n probabilities = torch.nn.functional.softmax(out[0], dim=0)\n values, indices = torch.topk(probabilities, 5)\n confidences = {LABELS[i]: v.item() for i, v in zip(indices, values)}\n return confidences\n
Let's break this down. The function takes one parameters:
\n\nimg
: the input image as a numpy
arrayThen, the function converts the image to a PyTorch tensor
, passes it through the model, and returns:
confidences
: the top five predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a sketchpad. To create a sketchpad input, we can use the convenient string shortcut, \"sketchpad\"
which creates a canvas for a user to draw on and handles the preprocessing to convert that to a numpy array.
The output component will be a \"label\"
, which displays the top labels in a nice form.
Finally, we'll add one more parameter, setting live=True
, which allows our interface to run in real time, adjusting its predictions every time a user draws on the sketchpad. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=predict, \n inputs=\"sketchpad\",\n outputs=\"label\",\n live=True).launch()\n
This produces the following interface, which you can try right here in your browser (try drawing something, like a \"snake\" or a \"laptop\"):
\n\n\n\nAnd you're done! That's all the code you need to build a Pictionary-style guessing app. Have fun and try to find some edge cases \ud83e\uddd0
\n", "tags": ["SKETCHPAD", "LABELS", "LIVE"], "spaces": ["https://huggingface.co/spaces/nateraw/quickdraw"], "url": "/guides/building-a-pictionary-app/", "contributor": null}], "preprocessing": "this component does *not* accept input.", "postprocessing": "expects a Dict[str, float] of classes and confidences, or str with just the class or an int/float for regression outputs, or a str path to a .json file containing a json dictionary in the structure produced by Label.postprocess().", "parent": "gradio", "prev_obj": "JSON", "next_obj": "LinePlot"}, "lineplot": {"class": null, "name": "LinePlot", "description": "Create a line plot.Let's go through some of the most popular features of Gradio! Here are Gradio's key features:
\n\nYou can provide example data that a user can easily load into Interface
. This can be helpful to demonstrate the types of inputs the model expects, as well as to provide a way to explore your dataset in conjunction with your model. To load example data, you can provide a nested list to the examples=
keyword argument of the Interface constructor. Each sublist within the outer list represents a data sample, and each element within the sublist represents an input for each input component. The format of example data for each component is specified in the Docs.
import gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n if num2 == 0:\n raise gr.Error(\"Cannot divide by zero!\")\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\", \n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n examples=[\n [5, \"add\", 3],\n [4, \"divide\", 2],\n [-4, \"multiply\", 2.5],\n [0, \"subtract\", 1.2],\n ],\n title=\"Toy Calculator\",\n description=\"Here's a sample toy calculator. Allows you to calculate things like $2+2=4$\",\n)\ndemo.launch()\n\n
You can load a large dataset into the examples to browse and interact with the dataset through Gradio. The examples will be automatically paginated (you can configure this through the examples_per_page
argument of Interface
).
Continue learning about examples in the More On Examples guide.
\n\nYou wish to pass custom error messages to the user. To do so, raise a gr.Error(\"custom message\")
to display an error message. If you try to divide by zero in the calculator demo above, a popup modal will display the custom error message. Learn more about Error in the docs.
You can also issue gr.Warning(\"message\")
and gr.Info(\"message\")
by having them as standalone lines in your function, which will immediately display modals while continuing the execution of your function. Queueing needs to be enabled for this to work.
Note below how the gr.Error
has to be raised, while the gr.Warning
and gr.Info
are single lines.
def start_process(name):\n gr.Info(\"Starting process\")\n if name is None:\n gr.Warning(\"Name is empty\")\n ...\n if success == False:\n raise gr.Error(\"Process failed\")\n
In the previous example, you may have noticed the title=
and description=
keyword arguments in the Interface
constructor that helps users understand your app.
There are three arguments in the Interface
constructor to specify where this content should go:
title
: which accepts text and can display it at the very top of interface, and also becomes the page title.description
: which accepts text, markdown or HTML and places it right under the title.article
: which also accepts text, markdown or HTML and places it below the interface.If you're using the Blocks
API instead, you can insert text, markdown, or HTML anywhere using the gr.Markdown(...)
or gr.HTML(...)
components, with descriptive content inside the Component
constructor.
Another useful keyword argument is label=
, which is present in every Component
. This modifies the label text at the top of each Component
. You can also add the info=
keyword argument to form elements like Textbox
or Radio
to provide further information on their usage.
gr.Number(label='Age', info='In years, must be greater than 0')\n
By default, an Interface
will have \"Flag\" button. When a user testing your Interface
sees input with interesting output, such as erroneous or unexpected model behaviour, they can flag the input for you to review. Within the directory provided by the flagging_dir=
argument to the Interface
constructor, a CSV file will log the flagged inputs. If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well.
For example, with the calculator interface shown above, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- calculator.py\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output\n5,add,7,12\n6,subtract,1.5,4.5\n
With the sepia interface shown earlier, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- sepia.py\n+-- flagged/\n| +-- logs.csv\n| +-- im/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output\nim/0.png,Output/0.png\nim/1.png,Output/1.png\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of the strings when flagging, which will be saved as an additional column to the CSV.
As you've seen, Gradio includes components that can handle a variety of different data types, such as images, audio, and video. Most components can be used both as inputs or outputs.
\n\nWhen a component is used as an input, Gradio automatically handles the preprocessing needed to convert the data from a type sent by the user's browser (such as a base64 representation of a webcam snapshot) to a form that can be accepted by your function (such as a numpy
array).
Similarly, when a component is used as an output, Gradio automatically handles the postprocessing needed to convert the data from what is returned by your function (such as a list of image paths) to a form that can be displayed in the user's browser (such as a Gallery
of images in base64 format).
You can control the preprocessing using the parameters when constructing the image component. For example, here if you instantiate the Image
component with the following parameters, it will convert the image to the PIL
type and reshape it to be (100, 100)
no matter the original size that it was submitted as:
img = gr.Image(shape=(100, 100), type=\"pil\")\n
In contrast, here we keep the original size of the image, but invert the colors before converting it to a numpy array:
\n\nimg = gr.Image(invert_colors=True, type=\"numpy\")\n
Postprocessing is a lot easier! Gradio automatically recognizes the format of the returned data (e.g. is the Image
a numpy
array or a str
filepath?) and postprocesses it into a format that can be displayed by the browser.
Take a look at the Docs to see all the preprocessing-related parameters for each Component.
\n\nGradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the theme=
kwarg to the Interface
constructor. For example:
demo = gr.Interface(..., theme=gr.themes.Monochrome())\n
Gradio comes with a set of prebuilt themes which you can load from gr.themes.*
. You can extend these themes or create your own themes from scratch - see the Theming guide for more details.
For additional styling ability, you can pass any CSS to your app using the css=
kwarg.\nThe base class for the Gradio app is gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Interface(css=\".gradio-container {background-color: red}\") as demo:\n ...\n
Some components can be additionally styled through the style()
method. For example:
img = gr.Image(\"lion.jpg\").style(height='24', rounded=False)\n
Take a look at the Docs to see all the styling options for each Component.
\n\nIf your app expects heavy traffic, use the queue()
method to control processing rate. This will queue up calls so only a certain number of requests are processed at a single time. Queueing uses websockets, which also prevent network timeouts, so you should use queueing if the inference time of your function is long (> 1min).
With Interface
:
demo = gr.Interface(...).queue()\ndemo.launch()\n
With Blocks
:
with gr.Blocks() as demo:\n #...\ndemo.queue()\ndemo.launch()\n
You can control the number of requests processed at a single time as such:
\n\ndemo.queue(concurrency_count=3)\n
See the Docs on queueing on configuring other queuing parameters.
\n\nTo specify only certain functions for queueing in Blocks:
\n\nwith gr.Blocks() as demo2:\n num1 = gr.Number()\n num2 = gr.Number()\n output = gr.Number()\n gr.Button(\"Add\").click(\n lambda a, b: a + b, [num1, num2], output)\n gr.Button(\"Multiply\").click(\n lambda a, b: a * b, [num1, num2], output, queue=True)\ndemo2.launch()\n
In some cases, you may want to stream a sequence of outputs rather than show a single output at once. For example, you might have an image generation model and you want to show the image that is generated at each step, leading up to the final image. Or you might have a chatbot which streams its response one word at a time instead of returning it all at once.
\n\nIn such cases, you can supply a generator function into Gradio instead of a regular function. Creating generators in Python is very simple: instead of a single return
value, a function should yield
a series of values instead. Usually the yield
statement is put in some kind of loop. Here's an example of an generator that simply counts up to a given number:
def my_generator(x):\n for i in range(x):\n yield i\n
You supply a generator into Gradio the same way as you would a regular function. For example, here's a a (fake) image generation model that generates noise for several steps before outputting an image:
\n\nimport gradio as gr\nimport numpy as np\nimport time\n\n# define core fn, which returns a generator {steps} times before returning the image\ndef fake_diffusion(steps):\n for _ in range(steps):\n time.sleep(1)\n image = np.random.random((600, 600, 3))\n yield image\n image = \"https://gradio-builds.s3.amazonaws.com/diffusion_image/cute_dog.jpg\"\n yield image\n\n\ndemo = gr.Interface(fake_diffusion, inputs=gr.Slider(1, 10, 3), outputs=\"image\")\n\n# define queue - required for generators\ndemo.queue()\n\ndemo.launch()\n\n
Note that we've added a time.sleep(1)
in the iterator to create an artificial pause between steps so that you are able to observe the steps of the iterator (in a real image generation model, this probably wouldn't be necessary).
Supplying a generator into Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio supports the ability to create a custom Progress Bars so that you have customizability and control over the progress update that you show to the user. In order to enable this, simply add an argument to your method that has a default value of a gr.Progress
instance. Then you can update the progress levels by calling this instance directly with a float between 0 and 1, or using the tqdm()
method of the Progress
instance to track progress over an iterable, as shown below. Queueing must be enabled for progress updates.
import gradio as gr\nimport time\n\ndef slowly_reverse(word, progress=gr.Progress()):\n progress(0, desc=\"Starting\")\n time.sleep(1)\n progress(0.05)\n new_string = \"\"\n for letter in progress.tqdm(word, desc=\"Reversing\"):\n time.sleep(0.25)\n new_string = letter + new_string\n return new_string\n\ndemo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())\n\nif __name__ == \"__main__\":\n demo.queue(concurrency_count=10).launch()\n\n
If you use the tqdm
library, you can even report progress updates automatically from any tqdm.tqdm
that already exists within your function by setting the default argument as gr.Progress(track_tqdm=True)
!
Gradio supports the ability to pass batch functions. Batch functions are just\nfunctions which take in a list of inputs and return a list of predictions.
\n\nFor example, here is a batched function that takes in two lists of inputs (a list of\nwords and a list of ints), and returns a list of trimmed words as output:
\n\nimport time\n\ndef trim_words(words, lens):\n trimmed_words = []\n time.sleep(5)\n for w, l in zip(words, lens):\n trimmed_words.append(w[:int(l)]) \n return [trimmed_words]\n
The advantage of using batched functions is that if you enable queuing, the Gradio\nserver can automatically batch incoming requests and process them in parallel,\npotentially speeding up your demo. Here's what the Gradio code looks like (notice\nthe batch=True
and max_batch_size=16
-- both of these parameters can be passed\ninto event triggers or into the Interface
class)
With Interface
:
demo = gr.Interface(trim_words, [\"textbox\", \"number\"], [\"output\"], \n batch=True, max_batch_size=16)\ndemo.queue()\ndemo.launch()\n
With Blocks
:
import gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n word = gr.Textbox(label=\"word\")\n leng = gr.Number(label=\"leng\")\n output = gr.Textbox(label=\"Output\")\n with gr.Row():\n run = gr.Button()\n\n event = run.click(trim_words, [word, leng], output, batch=True, max_batch_size=16)\n\ndemo.queue()\ndemo.launch()\n
In the example above, 16 requests could be processed in parallel (for a total inference\ntime of 5 seconds), instead of each request being processed separately (for a total\ninference time of 80 seconds). Many Hugging Face transformers
and diffusers
models\nwork very naturally with Gradio's batch mode: here's an example demo using diffusers to\ngenerate images in batches
Note: using batch functions with Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio is able to run anywhere you run Python, including local jupyter notebooks as well as collaborative notebooks, such as Google Colab. In the case of local jupyter notebooks and Google Colab notbooks, Gradio runs on a local server which you can interact with in your browser. (Note: for Google Colab, this is accomplished by service worker tunneling, which requires cookies to be enabled in your browser.) For other remote notebooks, Gradio will also run on a server, but you will need to use SSH tunneling to view the app in your local browser. Often a simpler options is to use Gradio's built-in public links, discussed in the next Guide.
\n", "tags": [], "spaces": [], "url": "/guides/key-features/", "contributor": null}], "preprocessing": "this component does *not* accept input.", "postprocessing": "expects a valid str that can be rendered as Markdown.", "parent": "gradio", "prev_obj": "LinePlot", "next_obj": "Model3D"}, "model3d": {"class": null, "name": "Model3D", "description": "Component allows users to upload or view 3D Model files (.obj, .glb, or .gltf).3D models are becoming more popular in machine learning and make for some of the most fun demos to experiment with. Using gradio
, you can easily build a demo of your 3D image model and share it with anyone. The Gradio 3D Model component accepts 3 file types including: .obj, .glb, & .gltf.
This guide will show you how to build a demo for your 3D image model in a few lines of code; like the one below. Play around with 3D object by clicking around, dragging and zooming:
\n\nMake sure you have the gradio
Python package already installed.
Let's take a look at how to create the minimal interface above. The prediction function in this case will just return the original 3D model mesh, but you can change this function to run inference on your machine learning model. We'll take a look at more complex examples below.
\n\nimport gradio as gr\n\ndef load_mesh(mesh_file_name):\n return mesh_file_name\n\ndemo = gr.Interface(\n fn=load_mesh,\n inputs=gr.Model3D(),\n outputs=gr.Model3D(clear_color=[0.0, 0.0, 0.0, 0.0], label=\"3D Model\"),\n examples=[\n [\"files/Bunny.obj\"],\n [\"files/Duck.glb\"],\n [\"files/Fox.gltf\"],\n [\"files/face.obj\"],\n ],\n cache_examples=True,\n)\n\ndemo.launch()\n
Let's break down the code above:
\n\nload_mesh
: This is our 'prediction' function and for simplicity, this function will take in the 3D model mesh and return it.
Creating the Interface:
\n\nfn
: the prediction function that is used when the user clicks submit. In our case this is the load_mesh
function.inputs
: create a model3D input component. The input expects an uploaded file as a {str} filepath.outputs
: create a model3D output component. The output component also expects a file as a {str} filepath.\nclear_color
: this is the background color of the 3D model canvas. Expects RGBa values.label
: the label that appears on the top left of the component.examples
: list of 3D model files. The 3D model component can accept .obj, .glb, & .gltf file types.cache_examples
: saves the predicted output for the examples, to save time on inference.Below is a demo that uses the DPT model to predict the depth of an image and then uses 3D Point Cloud to create a 3D object. Take a look at the app.py file for a peek into the code and the model prediction function.\n
Below is a demo that uses the PIFu model to convert an image of a clothed human into a 3D digitized model. Take a look at the spaces.py file for a peek into the code and the model prediction function.
\n\nAnd you're done! That's all the code you need to build an interface for your Model3D model. Here are some references that you may find useful:
\n\nThis guide explains how you can use Gradio to plot geographical data on a map using the gradio.Plot
component. The Gradio Plot
component works with Matplotlib, Bokeh and Plotly. Plotly is what we will be working with in this guide. Plotly allows developers to easily create all sorts of maps with their geographical data. Take a look here for some examples.
We will be using the New York City Airbnb dataset, which is hosted on kaggle here. I've uploaded it to the Hugging Face Hub as a dataset here for easier use and download. Using this data we will plot Airbnb locations on a map output and allow filtering based on price and location. Below is the demo that we will be building. \u26a1\ufe0f
\n\nLet's start by loading the Airbnb NYC data from the Hugging Face Hub.
\n\nfrom datasets import load_dataset\n\ndataset = load_dataset(\"gradio/NYC-Airbnb-Open-Data\", split=\"train\")\ndf = dataset.to_pandas()\n\ndef filter_map(min_price, max_price, boroughs):\n new_df = df[(df['neighbourhood_group'].isin(boroughs)) & \n (df['price'] > min_price) & (df['price'] < max_price)]\n names = new_df[\"name\"].tolist()\n prices = new_df[\"price\"].tolist()\n text_list = [(names[i], prices[i]) for i in range(0, len(names))]\n
In the code above, we first load the csv data into a pandas dataframe. Let's begin by defining a function that we will use as the prediction function for the gradio app. This function will accept the minimum price and maximum price range as well as the list of boroughs to filter the resulting map. We can use the passed in values (min_price
, max_price
, and list of boroughs
) to filter the dataframe and create new_df
. Next we will create text_list
of the names and prices of each Airbnb to use as labels on the map.
Plotly makes it easy to work with maps. Let's take a look below how we can create a map figure.
\n\nimport plotly.graph_objects as go\n\nfig = go.Figure(go.Scattermapbox(\n customdata=text_list,\n lat=new_df['latitude'].tolist(),\n lon=new_df['longitude'].tolist(),\n mode='markers',\n marker=go.scattermapbox.Marker(\n size=6\n ),\n hoverinfo=\"text\",\n hovertemplate='Name: %{customdata[0]}
Price: $%{customdata[1]}'\n ))\n\nfig.update_layout(\n mapbox_style=\"open-street-map\",\n hovermode='closest',\n mapbox=dict(\n bearing=0,\n center=go.layout.mapbox.Center(\n lat=40.67,\n lon=-73.90\n ),\n pitch=0,\n zoom=9\n ),\n)\n
Above, we create a scatter plot on mapbox by passing it our list of latitudes and longitudes to plot markers. We also pass in our custom data of names and prices for additional info to appear on every marker we hover over. Next we use update_layout
to specify other map settings such as zoom, and centering.
More info here on scatter plots using Mapbox and Plotly.
\n\nWe will use two gr.Number
components and a gr.CheckboxGroup
to allow users of our app to specify price ranges and borough locations. We will then use the gr.Plot
component as an output for our Plotly + Mapbox map we created earlier.
with gr.Blocks() as demo:\n with gr.Column():\n with gr.Row():\n min_price = gr.Number(value=250, label=\"Minimum Price\")\n max_price = gr.Number(value=1000, label=\"Maximum Price\")\n boroughs = gr.CheckboxGroup(choices=[\"Queens\", \"Brooklyn\", \"Manhattan\", \"Bronx\", \"Staten Island\"], value=[\"Queens\", \"Brooklyn\"], label=\"Select Boroughs:\")\n btn = gr.Button(value=\"Update Filter\")\n map = gr.Plot()\n demo.load(filter_map, [min_price, max_price, boroughs], map)\n btn.click(filter_map, [min_price, max_price, boroughs], map)\n
We layout these components using the gr.Column
and gr.Row
and we'll also add event triggers for when the demo first loads and when our \"Update Filter\" button is clicked in order to trigger the map to update with our new filters.
This is what the full demo code looks like:
\n\nimport gradio as gr\nimport plotly.graph_objects as go\nfrom datasets import load_dataset\n\ndataset = load_dataset(\"gradio/NYC-Airbnb-Open-Data\", split=\"train\")\ndf = dataset.to_pandas()\n\ndef filter_map(min_price, max_price, boroughs):\n\n filtered_df = df[(df['neighbourhood_group'].isin(boroughs)) & \n (df['price'] > min_price) & (df['price'] < max_price)]\n names = filtered_df[\"name\"].tolist()\n prices = filtered_df[\"price\"].tolist()\n text_list = [(names[i], prices[i]) for i in range(0, len(names))]\n fig = go.Figure(go.Scattermapbox(\n customdata=text_list,\n lat=filtered_df['latitude'].tolist(),\n lon=filtered_df['longitude'].tolist(),\n mode='markers',\n marker=go.scattermapbox.Marker(\n size=6\n ),\n hoverinfo=\"text\",\n hovertemplate='Name: %{customdata[0]}
Price: $%{customdata[1]}'\n ))\n\n fig.update_layout(\n mapbox_style=\"open-street-map\",\n hovermode='closest',\n mapbox=dict(\n bearing=0,\n center=go.layout.mapbox.Center(\n lat=40.67,\n lon=-73.90\n ),\n pitch=0,\n zoom=9\n ),\n )\n\n return fig\n\nwith gr.Blocks() as demo:\n with gr.Column():\n with gr.Row():\n min_price = gr.Number(value=250, label=\"Minimum Price\")\n max_price = gr.Number(value=1000, label=\"Maximum Price\")\n boroughs = gr.CheckboxGroup(choices=[\"Queens\", \"Brooklyn\", \"Manhattan\", \"Bronx\", \"Staten Island\"], value=[\"Queens\", \"Brooklyn\"], label=\"Select Boroughs:\")\n btn = gr.Button(value=\"Update Filter\")\n map = gr.Plot().style()\n demo.load(filter_map, [min_price, max_price, boroughs], map)\n btn.click(filter_map, [min_price, max_price, boroughs], map)\n\ndemo.launch()\n
If you run the code above, your app will start running locally.\nYou can even get a temporary shareable link by passing the share=True
parameter to launch
.
But what if you want to a permanent deployment solution?\nLet's deploy our Gradio app to the free HuggingFace Spaces platform.
\n\nIf you haven't used Spaces before, follow the previous guide here.
\n\nAnd you're all done! That's all the code you need to build a map demo.
\n\nHere's a link to the demo Map demo and complete code (on Hugging Face Spaces)
\n", "tags": ["PLOTS", "MAPS"], "spaces": [], "url": "/guides/plot-component-for-maps/", "contributor": null}], "preprocessing": "this component does *not* accept input.", "postprocessing": "expects either a matplotlib.figure.Figure, a plotly.graph_objects._figure.Figure, or a dict corresponding to a bokeh plot (json_item format)", "parent": "gradio", "prev_obj": "Number", "next_obj": "Radio"}, "radio": {"class": null, "name": "Radio", "description": "Creates a set of radio buttons of which only one can be selected.Google BigQuery is a cloud-based service for processing very large data sets. It is a serverless and highly scalable data warehousing solution that enables users to analyze data using SQL-like queries.
\n\nIn this tutorial, we will show you how to query a BigQuery dataset in Python and display the data in a dashboard that updates in real time using gradio
. The dashboard will look like this:
We'll cover the following steps in this Guide:
\n\nWe'll be working with the New York Times' COVID dataset that is available as a public dataset on BigQuery. The dataset, named covid19_nyt.us_counties
contains the latest information about the number of confirmed cases and deaths from COVID across US counties.
Prerequisites: This Guide uses Gradio Blocks, so make your are familiar with the Blocks class.
\n\nTo use Gradio with BigQuery, you will need to obtain your BigQuery credentials and use them with the BigQuery Python client. If you already have BigQuery credentials (as a .json
file), you can skip this section. If not, you can do this for free in just a couple of minutes.
First, log in to your Google Cloud account and go to the Google Cloud Console (https://console.cloud.google.com/)
In the Cloud Console, click on the hamburger menu in the top-left corner and select \"APIs & Services\" from the menu. If you do not have an existing project, you will need to create one.
Then, click the \"+ Enabled APIs & services\" button, which allows you to enable specific services for your project. Search for \"BigQuery API\", click on it, and click the \"Enable\" button. If you see the \"Manage\" button, then the BigQuery is already enabled, and you're all set.
In the APIs & Services menu, click on the \"Credentials\" tab and then click on the \"Create credentials\" button.
In the \"Create credentials\" dialog, select \"Service account key\" as the type of credentials to create, and give it a name. Also grant the service account permissions by giving it a role such as \"BigQuery User\", which will allow you to run queries.
After selecting the service account, select the \"JSON\" key type and then click on the \"Create\" button. This will download the JSON key file containing your credentials to your computer. It will look something like this:
{\n \"type\": \"service_account\",\n \"project_id\": \"your project\",\n \"private_key_id\": \"your private key id\",\n \"private_key\": \"private key\",\n \"client_email\": \"email\",\n \"client_id\": \"client id\",\n \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n \"token_uri\": \"https://accounts.google.com/o/oauth2/token\",\n \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/email_id\"\n}\n
Once you have the credentials, you will need to use the BigQuery Python client to authenticate using your credentials. To do this, you will need to install the BigQuery Python client by running the following command in the terminal:
\n\npip install google-cloud-bigquery[pandas]\n
You'll notice that we've installed the pandas add-on, which will be helpful for processing the BigQuery dataset as a pandas dataframe. Once the client is installed, you can authenticate using your credentials by running the following code:
\n\nfrom google.cloud import bigquery\n\nclient = bigquery.Client.from_service_account_json(\"path/to/key.json\")\n
With your credentials authenticated, you can now use the BigQuery Python client to interact with your BigQuery datasets.
\n\nHere is an example of a function which queries the covid19_nyt.us_counties
dataset in BigQuery to show the top 20 counties with the most confirmed cases as of the current day:
import numpy as np\n\nQUERY = (\n 'SELECT * FROM `bigquery-public-data.covid19_nyt.us_counties` ' \n 'ORDER BY date DESC,confirmed_cases DESC '\n 'LIMIT 20')\n\ndef run_query():\n query_job = client.query(QUERY) \n query_result = query_job.result() \n df = query_result.to_dataframe()\n # Select a subset of columns \n df = df[[\"confirmed_cases\", \"deaths\", \"county\", \"state_name\"]]\n # Convert numeric columns to standard numpy types\n df = df.astype({\"deaths\": np.int64, \"confirmed_cases\": np.int64})\n return df\n
Once you have a function to query the data, you can use the gr.DataFrame
component from the Gradio library to display the results in a tabular format. This is a useful way to inspect the data and make sure that it has been queried correctly.
Here is an example of how to use the gr.DataFrame
component to display the results. By passing in the run_query
function to gr.DataFrame
, we instruct Gradio to run the function as soon as the page loads and show the results. In addition, you also pass in the keyword every
to tell the dashboard to refresh every hour (60*60 seconds).
import gradio as gr\n\nwith gr.Blocks() as demo:\n gr.DataFrame(run_query, every=60*60)\n\ndemo.queue().launch() # Run the demo using queuing\n
Perhaps you'd like to add a visualization to our dashboard. You can use the gr.ScatterPlot()
component to visualize the data in a scatter plot. This allows you to see the relationship between different variables such as case count and case deaths in the dataset and can be useful for exploring the data and gaining insights. Again, we can do this in real-time\nby passing in the every
parameter.
Here is a complete example showing how to use the gr.ScatterPlot
to visualize in addition to displaying data with the gr.DataFrame
import gradio as gr\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"# \ud83d\udc89 Covid Dashboard (Updated Hourly)\")\n with gr.Row():\n gr.DataFrame(run_query, every=60*60)\n gr.ScatterPlot(run_query, every=60*60, x=\"confirmed_cases\", \n y=\"deaths\", tooltip=\"county\", width=500, height=500)\n\ndemo.queue().launch() # Run the demo with queuing enabled\n
It seems that cryptocurrencies, NFTs, and the web3 movement are all the rage these days! Digital assets are being listed on marketplaces for astounding amounts of money, and just about every celebrity is debuting their own NFT collection. While your crypto assets may be taxable, such as in Canada, today we'll explore some fun and tax-free ways to generate your own assortment of procedurally generated CryptoPunks.
\n\nGenerative Adversarial Networks, often known just as GANs, are a specific class of deep-learning models that are designed to learn from an input dataset to create (generate!) new material that is convincingly similar to elements of the original training set. Famously, the website thispersondoesnotexist.com went viral with lifelike, yet synthetic, images of people generated with a model called StyleGAN2. GANs have gained traction in the machine learning world, and are now being used to generate all sorts of images, text, and even music!
\n\nToday we'll briefly look at the high-level intuition behind GANs, and then we'll build a small demo around a pre-trained GAN to see what all the fuss is about. Here's a peek at what we're going to be putting together:
\n\n\n\nMake sure you have the gradio
Python package already installed. To use the pretrained model, also install torch
and torchvision
.
Originally proposed in Goodfellow et al. 2014, GANs are made up of neural networks which compete with the intention of outsmarting each other. One network, known as the generator, is responsible for generating images. The other network, the discriminator, receives an image at a time from the generator along with a real image from the training data set. The discriminator then has to guess: which image is the fake?
\n\nThe generator is constantly training to create images which are trickier for the discriminator to identify, while the discriminator raises the bar for the generator every time it correctly detects a fake. As the networks engage in this competitive (adversarial!) relationship, the images that get generated improve to the point where they become indistinguishable to human eyes!
\n\nFor a more in-depth look at GANs, you can take a look at this excellent post on Analytics Vidhya or this PyTorch tutorial. For now, though, we'll dive into a demo!
\n\nTo generate new images with a GAN, you only need the generator model. There are many different architectures that the generator could use, but for this demo we'll use a pretrained GAN generator model with the following architecture:
\n\nfrom torch import nn\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n
We're taking the generator from this repo by @teddykoker, where you can also see the original discriminator model structure.
\n\nAfter instantiating the model, we'll load in the weights from the Hugging Face Hub, stored at nateraw/cryptopunks-gan:
\n\nfrom huggingface_hub import hf_hub_download\nimport torch\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n
predict
functionThe predict
function is the key to making Gradio work! Whatever inputs we choose through the Gradio interface will get passed through our predict
function, which should operate on the inputs and generate outputs that we can display with Gradio output components. For GANs it's common to pass random noise into our model as the input, so we'll generate a tensor of random numbers and pass that through the model. We can then use torchvision
's save_image
function to save the output of the model as a png
file, and return the file name:
from torchvision.utils import save_image\n\ndef predict(seed):\n num_punks = 4\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
We're giving our predict
function a seed
parameter, so that we can fix the random tensor generation with a seed. We'll then be able to reproduce punks if we want to see them again by passing in the same seed.
Note! Our model needs an input tensor of dimensions 100x1x1 to do a single inference, or (BatchSize)x100x1x1 for generating a batch of images. In this demo we'll start by generating 4 punks at a time.
\n\nAt this point you can even run the code you have with predict(<SOME_NUMBER>)
, and you'll find your freshly generated punks in your file system at ./punks.png
. To make a truly interactive demo, though, we'll build out a simple interface with Gradio. Our goals here are to:
predict()
to take the seed and generate the imagesWith gr.Interface()
, we can define all of that with a single function call:
import gradio as gr\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n ],\n outputs=\"image\",\n).launch()\n
Launching the interface should present you with something like this:
\n\n\n\nGenerating 4 punks at a time is a good start, but maybe we'd like to control how many we want to make each time. Adding more inputs to our Gradio interface is as simple as adding another item to the inputs
list that we pass to gr.Interface
:
gr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10), # Adding another slider!\n ],\n outputs=\"image\",\n).launch()\n
The new input will be passed to our predict()
function, so we have to make some changes to that function to accept a new parameter:
def predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
When you relaunch your interface, you should see a second slider that'll let you control the number of punks!
\n\nYour Gradio app is pretty much good to go, but you can add a few extra things to really make it ready for the spotlight \u2728
\n\nWe can add some examples that users can easily try out by adding this to the gr.Interface
:
gr.Interface(\n # ...\n # keep everything as it is, and then add\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True) # cache_examples is optional\n
The examples
parameter takes a list of lists, where each item in the sublists is ordered in the same order that we've listed the inputs
. So in our case, [seed, num_punks]
. Give it a try!
You can also try adding a title
, description
, and article
to the gr.Interface
. Each of those parameters accepts a string, so try it out and see what happens \ud83d\udc40 article
will also accept HTML, as explored in a previous guide!
When you're all done, you may end up with something like this:
\n\n\n\nFor reference, here is our full code:
\n\nimport torch\nfrom torch import nn\nfrom huggingface_hub import hf_hub_download\nfrom torchvision.utils import save_image\nimport gradio as gr\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n\ndef predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10),\n ],\n outputs=\"image\",\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True)\n
Congratulations! You've built out your very own GAN-powered CryptoPunks generator, with a fancy Gradio interface that makes it easy for anyone to use. Now you can scour the Hub for more GANs (or train your own) and continue making even more awesome demos \ud83e\udd17
\n", "tags": ["GAN", "IMAGE", "HUB"], "spaces": ["https://huggingface.co/spaces/NimaBoscarino/cryptopunks", "https://huggingface.co/spaces/nateraw/cryptopunks-generator"], "url": "/guides/create-your-own-friends-with-a-gan/", "contributor": "Nima Boscarino and Nate Raw"}], "preprocessing": "passes slider value as a float into the function.", "postprocessing": "expects an int or float returned from function and sets slider value to it as long as it is within range.", "examples-format": "A float or int representing the slider's value.", "parent": "gradio", "prev_obj": "ScatterPlot", "next_obj": "State"}, "state": {"class": null, "name": "State", "description": "Special hidden component that stores session state across runs of the demo by the same user. The value of the State variable is cleared when the user refreshes the page.Automatic speech recognition (ASR), the conversion of spoken speech to text, is a very important and thriving area of machine learning. ASR algorithms run on practically every smartphone, and are becoming increasingly embedded in professional workflows, such as digital assistants for nurses and doctors. Because ASR algorithms are designed to be used directly by customers and end users, it is important to validate that they are behaving as expected when confronted with a wide variety of speech patterns (different accents, pitches, and background audio conditions).
\n\nUsing gradio
, you can easily build a demo of your ASR model and share that with a testing team, or test it yourself by speaking through the microphone on your device.
This tutorial will show how to take a pretrained speech-to-text model and deploy it with a Gradio interface. We will start with a full-context model, in which the user speaks the entire audio before the prediction runs. Then we will adapt the demo to make it streaming, meaning that the audio model will convert speech as you speak. The streaming demo that we create will look something like this (try it below or in a new tab!):
\n\n\n\nReal-time ASR is inherently stateful, meaning that the model's predictions change depending on what words the user previously spoke. So, in this tutorial, we will also cover how to use state with Gradio demos.
\n\nMake sure you have the gradio
Python package already installed. You will also need a pretrained speech recognition model. In this tutorial, we will build demos from 2 ASR libraries:
pip install transformers
and pip install torch
) pip install deepspeech==0.8.2
)Make sure you have at least one of these installed so that you can follow along the tutorial. You will also need ffmpeg
installed on your system, if you do not already have it, to process files from the microphone.
Here's how to build a real time speech recognition (ASR) app:
\n\nFirst, you will need to have an ASR model that you have either trained yourself or you will need to download a pretrained model. In this tutorial, we will start by using a pretrained ASR model from the Hugging Face model, Wav2Vec2
.
Here is the code to load Wav2Vec2
from Hugging Face transformers
.
from transformers import pipeline\n\np = pipeline(\"automatic-speech-recognition\")\n
That's it! By default, the automatic speech recognition model pipeline loads Facebook's facebook/wav2vec2-base-960h
model.
We will start by creating a full-context ASR demo, in which the user speaks the full audio before using the ASR model to run inference. This is very easy with Gradio -- we simply create a function around the pipeline
object above.
We will use gradio
's built in Audio
component, configured to take input from the user's microphone and return a filepath for the recorded audio. The output component will be a plain Textbox
.
import gradio as gr\n\ndef transcribe(audio):\n text = p(audio)[\"text\"]\n return text\n\ngr.Interface(\n fn=transcribe, \n inputs=gr.Audio(source=\"microphone\", type=\"filepath\"), \n outputs=\"text\").launch()\n
So what's happening here? The transcribe
function takes a single parameter, audio
, which is a filepath to the audio file that the user has recorded. The pipeline
object expects a filepath and converts it to text, which is returned to the frontend and displayed in a textbox.
Let's see it in action! (Record a short audio clip and then click submit, or open in a new tab):
\n\n\n\nOk great! We've built an ASR model that works well for short audio clips. However, if you are recording longer audio clips, you probably want a streaming interface, one that transcribes audio as the user speaks instead of just all-at-once at the end.
\n\nThe good news is that it's not too difficult to adapt the demo we just made to make it streaming, using the same Wav2Vec2
model.
The biggest change is that we must now introduce a state
parameter, which holds the audio that has been transcribed so far. This allows us to only the latest chunk of audio and simply append it to the audio we previously transcribed.
When adding state to a Gradio demo, you need to do a total of 3 things:
\n\nstate
parameter to the functionstate
at the end of the function\"state\"
components to the inputs
and outputs
in Interface
Here's what the code looks like:
\n\ndef transcribe(audio, state=\"\"):\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\n# Set the starting state to an empty string\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\" \n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Notice that we've also made one other change, which is that we've set live=True
. This keeps the Gradio interface running constantly, so it automatically transcribes audio without the user having to repeatedly hit the submit button.
Let's see how it does (try below or in a new tab)!
\n\n\n\nOne thing that you may notice is that the transcription quality has dropped since the chunks of audio are so small, they lack the context to properly be transcribed. A \"hacky\" fix to this is to simply increase the runtime of the transcribe()
function so that longer audio chunks are processed. We can do this by adding a time.sleep()
inside the function, as shown below (we'll see a proper fix next)
from transformers import pipeline\nimport gradio as gr\nimport time\n\np = pipeline(\"automatic-speech-recognition\")\n\ndef transcribe(audio, state=\"\"):\n time.sleep(2)\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\"\n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Try the demo below to see the difference (or open in a new tab)!
\n\n\n\nYou're not restricted to ASR models from the transformers
library -- you can use your own models or models from other libraries. The DeepSpeech
library contains models that are specifically designed to handle streaming audio data. These models perform really well with streaming data as they are able to account for previous chunks of audio data when making predictions.
Going through the DeepSpeech library is beyond the scope of this Guide (check out their excellent documentation here), but you can use Gradio very similarly with a DeepSpeech ASR model as with a Transformers ASR model.
\n\nHere's a complete example (on Linux):
\n\nFirst install the DeepSpeech library and download the pretrained models from the terminal:
\n\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.pbmm\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer\napt install libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 ffmpeg\npip install deepspeech==0.8.2\n
Then, create a similar transcribe()
function as before:
from deepspeech import Model\nimport numpy as np\n\nmodel_file_path = \"deepspeech-0.8.2-models.pbmm\"\nlm_file_path = \"deepspeech-0.8.2-models.scorer\"\nbeam_width = 100\nlm_alpha = 0.93\nlm_beta = 1.18\n\nmodel = Model(model_file_path)\nmodel.enableExternalScorer(lm_file_path)\nmodel.setScorerAlphaBeta(lm_alpha, lm_beta)\nmodel.setBeamWidth(beam_width)\n\n\ndef reformat_freq(sr, y):\n if sr not in (\n 48000,\n 16000,\n ): # Deepspeech only supports 16k, (we convert 48k -> 16k)\n raise ValueError(\"Unsupported rate\", sr)\n if sr == 48000:\n y = (\n ((y / max(np.max(y), 1)) * 32767)\n .reshape((-1, 3))\n .mean(axis=1)\n .astype(\"int16\")\n )\n sr = 16000\n return sr, y\n\n\ndef transcribe(speech, stream):\n _, y = reformat_freq(*speech)\n if stream is None:\n stream = model.createStream()\n stream.feedAudioContent(y)\n text = stream.intermediateDecode()\n return text, stream\n\n
Then, create a Gradio Interface as before (the only difference being that the return type should be numpy
instead of a filepath
to be compatible with the DeepSpeech models)
import gradio as gr\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"numpy\"), \n \"state\" \n ], \n outputs= [\n \"text\", \n \"state\"\n ], \n live=True).launch()\n
Running all of this should allow you to deploy your realtime ASR model with a nice GUI. Try it out and see how well it works for you.
\n\nAnd you're done! That's all the code you need to build a web-based GUI for your ASR model.
\n\nFun tip: you can share your ASR model instantly with others simply by setting share=True
in launch()
.
Automatic speech recognition (ASR), the conversion of spoken speech to text, is a very important and thriving area of machine learning. ASR algorithms run on practically every smartphone, and are becoming increasingly embedded in professional workflows, such as digital assistants for nurses and doctors. Because ASR algorithms are designed to be used directly by customers and end users, it is important to validate that they are behaving as expected when confronted with a wide variety of speech patterns (different accents, pitches, and background audio conditions).
\n\nUsing gradio
, you can easily build a demo of your ASR model and share that with a testing team, or test it yourself by speaking through the microphone on your device.
This tutorial will show how to take a pretrained speech-to-text model and deploy it with a Gradio interface. We will start with a full-context model, in which the user speaks the entire audio before the prediction runs. Then we will adapt the demo to make it streaming, meaning that the audio model will convert speech as you speak. The streaming demo that we create will look something like this (try it below or in a new tab!):
\n\n\n\nReal-time ASR is inherently stateful, meaning that the model's predictions change depending on what words the user previously spoke. So, in this tutorial, we will also cover how to use state with Gradio demos.
\n\nMake sure you have the gradio
Python package already installed. You will also need a pretrained speech recognition model. In this tutorial, we will build demos from 2 ASR libraries:
pip install transformers
and pip install torch
) pip install deepspeech==0.8.2
)Make sure you have at least one of these installed so that you can follow along the tutorial. You will also need ffmpeg
installed on your system, if you do not already have it, to process files from the microphone.
Here's how to build a real time speech recognition (ASR) app:
\n\nFirst, you will need to have an ASR model that you have either trained yourself or you will need to download a pretrained model. In this tutorial, we will start by using a pretrained ASR model from the Hugging Face model, Wav2Vec2
.
Here is the code to load Wav2Vec2
from Hugging Face transformers
.
from transformers import pipeline\n\np = pipeline(\"automatic-speech-recognition\")\n
That's it! By default, the automatic speech recognition model pipeline loads Facebook's facebook/wav2vec2-base-960h
model.
We will start by creating a full-context ASR demo, in which the user speaks the full audio before using the ASR model to run inference. This is very easy with Gradio -- we simply create a function around the pipeline
object above.
We will use gradio
's built in Audio
component, configured to take input from the user's microphone and return a filepath for the recorded audio. The output component will be a plain Textbox
.
import gradio as gr\n\ndef transcribe(audio):\n text = p(audio)[\"text\"]\n return text\n\ngr.Interface(\n fn=transcribe, \n inputs=gr.Audio(source=\"microphone\", type=\"filepath\"), \n outputs=\"text\").launch()\n
So what's happening here? The transcribe
function takes a single parameter, audio
, which is a filepath to the audio file that the user has recorded. The pipeline
object expects a filepath and converts it to text, which is returned to the frontend and displayed in a textbox.
Let's see it in action! (Record a short audio clip and then click submit, or open in a new tab):
\n\n\n\nOk great! We've built an ASR model that works well for short audio clips. However, if you are recording longer audio clips, you probably want a streaming interface, one that transcribes audio as the user speaks instead of just all-at-once at the end.
\n\nThe good news is that it's not too difficult to adapt the demo we just made to make it streaming, using the same Wav2Vec2
model.
The biggest change is that we must now introduce a state
parameter, which holds the audio that has been transcribed so far. This allows us to only the latest chunk of audio and simply append it to the audio we previously transcribed.
When adding state to a Gradio demo, you need to do a total of 3 things:
\n\nstate
parameter to the functionstate
at the end of the function\"state\"
components to the inputs
and outputs
in Interface
Here's what the code looks like:
\n\ndef transcribe(audio, state=\"\"):\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\n# Set the starting state to an empty string\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\" \n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Notice that we've also made one other change, which is that we've set live=True
. This keeps the Gradio interface running constantly, so it automatically transcribes audio without the user having to repeatedly hit the submit button.
Let's see how it does (try below or in a new tab)!
\n\n\n\nOne thing that you may notice is that the transcription quality has dropped since the chunks of audio are so small, they lack the context to properly be transcribed. A \"hacky\" fix to this is to simply increase the runtime of the transcribe()
function so that longer audio chunks are processed. We can do this by adding a time.sleep()
inside the function, as shown below (we'll see a proper fix next)
from transformers import pipeline\nimport gradio as gr\nimport time\n\np = pipeline(\"automatic-speech-recognition\")\n\ndef transcribe(audio, state=\"\"):\n time.sleep(2)\n text = p(audio)[\"text\"]\n state += text + \" \"\n return state, state\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"filepath\", streaming=True), \n \"state\"\n ],\n outputs=[\n \"textbox\",\n \"state\"\n ],\n live=True).launch()\n
Try the demo below to see the difference (or open in a new tab)!
\n\n\n\nYou're not restricted to ASR models from the transformers
library -- you can use your own models or models from other libraries. The DeepSpeech
library contains models that are specifically designed to handle streaming audio data. These models perform really well with streaming data as they are able to account for previous chunks of audio data when making predictions.
Going through the DeepSpeech library is beyond the scope of this Guide (check out their excellent documentation here), but you can use Gradio very similarly with a DeepSpeech ASR model as with a Transformers ASR model.
\n\nHere's a complete example (on Linux):
\n\nFirst install the DeepSpeech library and download the pretrained models from the terminal:
\n\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.pbmm\nwget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer\napt install libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 ffmpeg\npip install deepspeech==0.8.2\n
Then, create a similar transcribe()
function as before:
from deepspeech import Model\nimport numpy as np\n\nmodel_file_path = \"deepspeech-0.8.2-models.pbmm\"\nlm_file_path = \"deepspeech-0.8.2-models.scorer\"\nbeam_width = 100\nlm_alpha = 0.93\nlm_beta = 1.18\n\nmodel = Model(model_file_path)\nmodel.enableExternalScorer(lm_file_path)\nmodel.setScorerAlphaBeta(lm_alpha, lm_beta)\nmodel.setBeamWidth(beam_width)\n\n\ndef reformat_freq(sr, y):\n if sr not in (\n 48000,\n 16000,\n ): # Deepspeech only supports 16k, (we convert 48k -> 16k)\n raise ValueError(\"Unsupported rate\", sr)\n if sr == 48000:\n y = (\n ((y / max(np.max(y), 1)) * 32767)\n .reshape((-1, 3))\n .mean(axis=1)\n .astype(\"int16\")\n )\n sr = 16000\n return sr, y\n\n\ndef transcribe(speech, stream):\n _, y = reformat_freq(*speech)\n if stream is None:\n stream = model.createStream()\n stream.feedAudioContent(y)\n text = stream.intermediateDecode()\n return text, stream\n\n
Then, create a Gradio Interface as before (the only difference being that the return type should be numpy
instead of a filepath
to be compatible with the DeepSpeech models)
import gradio as gr\n\ngr.Interface(\n fn=transcribe, \n inputs=[\n gr.Audio(source=\"microphone\", type=\"numpy\"), \n \"state\" \n ], \n outputs= [\n \"text\", \n \"state\"\n ], \n live=True).launch()\n
Running all of this should allow you to deploy your realtime ASR model with a nice GUI. Try it out and see how well it works for you.
\n\nAnd you're done! That's all the code you need to build a web-based GUI for your ASR model.
\n\nFun tip: you can share your ASR model instantly with others simply by setting share=True
in launch()
.
The Hugging Face Hub is a central platform that has over 190,000 models, 32,000 datasets and 40,000 demos, also known as Spaces. Although Hugging Face is famous for its \ud83e\udd17 transformers and diffusers libraries, the Hub also supports dozens of ML libraries, such as PyTorch, TensorFlow, spaCy, and many others across a variety of domains, from computer vision to reinforcement learning.
\n\nGradio has multiple features that make it extremely easy to leverage existing models and Spaces on the Hub. This guide walks through these features.
\n\npipeline
First, let's build a simple interface that translates text from English to Spanish. Between the over a thousand models shared by the University of Helsinki, there is an existing model, opus-mt-en-es
, that does precisely this!
The \ud83e\udd17 transformers library has a very easy-to-use abstraction, pipeline()
that handles most of the complex code to offer a simple API for common tasks. By specifying the task and an (optional) model, you can use an existing model with few lines:
import gradio as gr\n\nfrom transformers import pipeline\n\npipe = pipeline(\"translation\", model=\"Helsinki-NLP/opus-mt-en-es\")\n\ndef predict(text):\n return pipe(text)[0][\"translation_text\"]\n\ndemo = gr.Interface(\n fn=predict, \n inputs='text',\n outputs='text',\n)\n\ndemo.launch()\n
But gradio
actually makes it even easier to convert a pipeline
to a demo, simply by using the gradio.Interface.from_pipeline
methods, which skips the need to specify the input and output components:
from transformers import pipeline\nimport gradio as gr\n\npipe = pipeline(\"translation\", model=\"Helsinki-NLP/opus-mt-en-es\")\n\ndemo = gr.Interface.from_pipeline(pipe)\ndemo.launch()\n
The previous code produces the following interface, which you can try right here in your browser:
\n\nHugging Face has a free service called the Inference API, which allows you to send HTTP requests to models in the Hub. For transformers or diffusers-based models, the API can be 2 to 10 times faster than running the inference yourself. The API is free (rate limited), and you can switch to dedicated Inference Endpoints when you want to use it in production.
\n\nLet's try the same demo as above but using the Inference API instead of loading the model yourself. Given a Hugging Face model supported in the Inference API, Gradio can automatically infer the expected input and output and make the underlying server calls, so you don't have to worry about defining the prediction function. Here is what the code would look like!
\n\nimport gradio as gr\n\ndemo = gr.load(\"Helsinki-NLP/opus-mt-en-es\", src=\"models\")\n\ndemo.launch()\n
Notice that we just put specify the model name and state that the src
should be models
(Hugging Face's Model Hub). There is no need to install any dependencies (except gradio
) since you are not loading the model on your computer.
You might notice that the first inference takes about 20 seconds. This happens since the Inference API is loading the model in the server. You get some benefits afterward:
\n\nHugging Face Spaces allows anyone to host their Gradio demos freely, and uploading your Gradio demos take a couple of minutes. You can head to hf.co/new-space, select the Gradio SDK, create an app.py
file, and voila! You have a demo you can share with anyone else. To learn more, read this guide how to host on Hugging Face Spaces using the website.
Alternatively, you can create a Space programmatically, making use of the huggingface_hub client library library. Here's an example:
\n\nfrom huggingface_hub import (\n create_repo,\n get_full_repo_name,\n upload_file,\n)\ncreate_repo(name=target_space_name, token=hf_token, repo_type=\"space\", space_sdk=\"gradio\")\nrepo_name = get_full_repo_name(model_id=target_space_name, token=hf_token)\nfile_url = upload_file(\n path_or_fileobj=\"file.txt\",\n path_in_repo=\"app.py\",\n repo_id=repo_name,\n repo_type=\"space\",\n token=hf_token,\n)\n
Here, create_repo
creates a gradio repo with the target name under a specific account using that account's Write Token. repo_name
gets the full repo name of the related repo. Finally upload_file
uploads a file inside the repo with the name app.py
.
Throughout this guide, you've seen many embedded Gradio demos. You can also do this on own website! The first step is to create a Hugging Face Space with the demo you want to showcase. Then, follow the steps here to embed the Space on your website.
\n\nYou can also use and remix existing Gradio demos on Hugging Face Spaces. For example, you could take two existing Gradio demos and put them as separate tabs and create a new demo. You can run this new demo locally, or upload it to Spaces, allowing endless possibilities to remix and create new demos!
\n\nHere's an example that does exactly that:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Tab(\"Translate to Spanish\"):\n gr.load(\"gradio/helsinki_translation_en_es\", src=\"spaces\")\n with gr.Tab(\"Translate to French\"):\n gr.load(\"abidlabs/en2fr\", src=\"spaces\")\n\ndemo.launch()\n
Notice that we use gr.load()
, the same method we used to load models using the Inference API. However, here we specify that the src
is spaces
(Hugging Face Spaces).
That's it! Let's recap the various ways Gradio and Hugging Face work together:
\n\ntransformers
pipeline into a Gradio demo using from_pipeline()
gr.load()
gr.load()
.\ud83e\udd17
\n", "tags": ["HUB", "SPACES", "EMBED"], "spaces": ["https://huggingface.co/spaces/gradio/helsinki_translation_en_es"], "url": "/guides/using-hugging-face-integrations/", "contributor": "Omar Sanseviero \ud83e\udd99 "}, {"name": "image-classification-in-pytorch", "category": "integrating-other-frameworks", "pretty_category": "Integrating Other Frameworks", "guide_index": null, "absolute_index": 20, "pretty_name": "Image Classification In Pytorch", "content": "# Image Classification in PyTorch\n\n\n\n\n## Introduction\n\nImage classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from autonomous vehicles to medical imaging. \n\nSuch models are perfect to use with Gradio's *image* input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):\n\n\n\n\nLet's get started!\n\n### Prerequisites\n\nMake sure you have the `gradio` Python package already [installed](/getting_started). We will be using a pretrained image classification model, so you should also have `torch` installed.\n\n## Step 1 \u2014 Setting up the Image Classification Model\n\nFirst, we will need an image classification model. For this tutorial, we will use a pretrained Resnet-18 model, as it is easily downloadable from [PyTorch Hub](https://pytorch.org/hub/pytorch_vision_resnet/). You can use a different pretrained model or train your own. \n\n```python\nimport torch\n\nmodel = torch.hub.load('pytorch/vision:v0.6.0', 'resnet18', pretrained=True).eval()\n```\n\nBecause we will be using the model for inference, we have called the `.eval()` method.\n\n## Step 2 \u2014 Defining a `predict` function\n\nNext, we will need to define a function that takes in the *user input*, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this [text file](https://git.io/JJkYN).\n\nIn the case of our pretrained model, it will look like this:\n\n```python\nimport requests\nfrom PIL import Image\nfrom torchvision import transforms\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef predict(inp):\n inp = transforms.ToTensor()(inp).unsqueeze(0)\n with torch.no_grad():\n prediction = torch.nn.functional.softmax(model(inp)[0], dim=0)\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)} \n return confidences\n```\n\nLet's break this down. The function takes one parameter:\n\n* `inp`: the input image as a `PIL` image\n\nThen, the function converts the image to a PIL Image and then eventually a PyTorch `tensor`, passes it through the model, and returns:\n\n* `confidences`: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilities\n\n## Step 3 \u2014 Creating a Gradio Interface\n\nNow that we have our predictive function set up, we can create a Gradio Interface around it. \n\nIn this case, the input component is a drag-and-drop image component. To create this input, we use `Image(type=\"pil\")` which creates the component and handles the preprocessing to convert that to a `PIL` image. \n\nThe output component will be a `Label`, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images by constructing it as `Label(num_top_classes=3)`.\n\nFinally, we'll add one more parameter, the `examples`, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:\n\n```python\nimport gradio as gr\n\ngr.Interface(fn=predict, \n inputs=gr.Image(type=\"pil\"),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"lion.jpg\", \"cheetah.jpg\"]).launch()\n```\n\nThis produces the following interface, which you can try right here in your browser (try uploading your own examples!):\n\n\n\n----------\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting `share=True` when you `launch()` the Interface!\n\n", "html": "Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from autonomous vehicles to medical imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained image classification model, so you should also have torch
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Resnet-18 model, as it is easily downloadable from PyTorch Hub. You can use a different pretrained model or train your own.
\n\nimport torch\n\nmodel = torch.hub.load('pytorch/vision:v0.6.0', 'resnet18', pretrained=True).eval()\n
Because we will be using the model for inference, we have called the .eval()
method.
predict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\nfrom PIL import Image\nfrom torchvision import transforms\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef predict(inp):\n inp = transforms.ToTensor()(inp).unsqueeze(0)\n with torch.no_grad():\n prediction = torch.nn.functional.softmax(model(inp)[0], dim=0)\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)} \n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a PIL
imageThen, the function converts the image to a PIL Image and then eventually a PyTorch tensor
, passes it through the model, and returns:
confidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we use Image(type=\"pil\")
which creates the component and handles the preprocessing to convert that to a PIL
image.
The output component will be a Label
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images by constructing it as Label(num_top_classes=3)
.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=predict, \n inputs=gr.Image(type=\"pil\"),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"lion.jpg\", \"cheetah.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from traffic control systems to satellite imaging.
\n\nSuch models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed. We will be using a pretrained Keras image classification model, so you should also have tensorflow
installed.
First, we will need an image classification model. For this tutorial, we will use a pretrained Mobile Net model, as it is easily downloadable from Keras. You can use a different pretrained model or train your own.
\n\nimport tensorflow as tf\n\ninception_net = tf.keras.applications.MobileNetV2()\n
This line automatically downloads the MobileNet model and weights using the Keras library.
\n\npredict
functionNext, we will need to define a function that takes in the user input, which in this case is an image, and returns the prediction. The prediction should be returned as a dictionary whose keys are class name and values are confidence probabilities. We will load the class names from this text file.
\n\nIn the case of our pretrained model, it will look like this:
\n\nimport requests\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n confidences = {labels[i]: float(prediction[i]) for i in range(1000)}\n return confidences\n
Let's break this down. The function takes one parameter:
\n\ninp
: the input image as a numpy
arrayThen, the function adds a batch dimension, passes it through the model, and returns:
\n\nconfidences
: the predictions, as a dictionary whose keys are class labels and whose values are confidence probabilitiesNow that we have our predictive function set up, we can create a Gradio Interface around it.
\n\nIn this case, the input component is a drag-and-drop image component. To create this input, we can use the \"gradio.inputs.Image\"
class, which creates the component and handles the preprocessing to convert that to a numpy array. We will instantiate the class with a parameter that automatically preprocesses the input image to be 224 pixels by 224 pixels, which is the size that MobileNet expects.
The output component will be a \"label\"
, which displays the top labels in a nice form. Since we don't want to show all 1,000 class labels, we will customize it to show only the top 3 images.
Finally, we'll add one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples. The code for Gradio looks like this:
import gradio as gr\n\ngr.Interface(fn=classify_image, \n inputs=gr.Image(shape=(224, 224)),\n outputs=gr.Label(num_top_classes=3),\n examples=[\"banana.jpg\", \"car.jpg\"]).launch()\n
This produces the following interface, which you can try right here in your browser (try uploading your own examples!):
\n\n\n\nAnd you're done! That's all the code you need to build a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
Image classification is a central task in computer vision. Building better classifiers to classify what object is present in a picture is an active area of research, as it has applications stretching from facial recognition to manufacturing quality control.
\n\nState-of-the-art image classifiers are based on the transformers architectures, originally popularized for NLP tasks. Such architectures are typically called vision transformers (ViT). Such models are perfect to use with Gradio's image input component, so in this tutorial we will build a web demo to classify images using Gradio. We will be able to build the whole web application in a single line of Python, and it will look like this (try one of the examples!):
\n\n\n\nLet's get started!
\n\nMake sure you have the gradio
Python package already installed.
First, we will need an image classification model. For this tutorial, we will use a model from the Hugging Face Model Hub. The Hub contains thousands of models covering dozens of different machine learning tasks.
\n\nExpand the Tasks category on the left sidebar and select \"Image Classification\" as our task of interest. You will then see all of the models on the Hub that are designed to classify images.
\n\nAt the time of writing, the most popular one is google/vit-base-patch16-224
, which has been trained on ImageNet images at a resolution of 224x224 pixels. We will use this model for our demo.
When using a model from the Hugging Face Hub, we do not need to define the input or output components for the demo. Similarly, we do not need to be concerned with the details of preprocessing or postprocessing. \nAll of these are automatically inferred from the model tags.
\n\nBesides the import statement, it only takes a single line of Python to load and launch the demo.
\n\nWe use the gr.Interface.load()
method and pass in the path to the model including the huggingface/
to designate that it is from the Hugging Face Hub.
import gradio as gr\n\ngr.Interface.load(\n \"huggingface/google/vit-base-patch16-224\",\n examples=[\"alligator.jpg\", \"laptop.jpg\"]).launch()\n
Notice that we have added one more parameter, the examples
, which allows us to prepopulate our interfaces with a few predefined examples.
This produces the following interface, which you can try right here in your browser. When you input an image, it is automatically preprocessed and sent to the Hugging Face Hub API, where it is passed through the model and returned as a human-interpretable prediction. Try uploading your own image!
\n\n\n\nAnd you're done! In one line of code, you have built a web demo for an image classifier. If you'd like to share with others, try setting share=True
when you launch()
the Interface!
It seems that cryptocurrencies, NFTs, and the web3 movement are all the rage these days! Digital assets are being listed on marketplaces for astounding amounts of money, and just about every celebrity is debuting their own NFT collection. While your crypto assets may be taxable, such as in Canada, today we'll explore some fun and tax-free ways to generate your own assortment of procedurally generated CryptoPunks.
\n\nGenerative Adversarial Networks, often known just as GANs, are a specific class of deep-learning models that are designed to learn from an input dataset to create (generate!) new material that is convincingly similar to elements of the original training set. Famously, the website thispersondoesnotexist.com went viral with lifelike, yet synthetic, images of people generated with a model called StyleGAN2. GANs have gained traction in the machine learning world, and are now being used to generate all sorts of images, text, and even music!
\n\nToday we'll briefly look at the high-level intuition behind GANs, and then we'll build a small demo around a pre-trained GAN to see what all the fuss is about. Here's a peek at what we're going to be putting together:
\n\n\n\nMake sure you have the gradio
Python package already installed. To use the pretrained model, also install torch
and torchvision
.
Originally proposed in Goodfellow et al. 2014, GANs are made up of neural networks which compete with the intention of outsmarting each other. One network, known as the generator, is responsible for generating images. The other network, the discriminator, receives an image at a time from the generator along with a real image from the training data set. The discriminator then has to guess: which image is the fake?
\n\nThe generator is constantly training to create images which are trickier for the discriminator to identify, while the discriminator raises the bar for the generator every time it correctly detects a fake. As the networks engage in this competitive (adversarial!) relationship, the images that get generated improve to the point where they become indistinguishable to human eyes!
\n\nFor a more in-depth look at GANs, you can take a look at this excellent post on Analytics Vidhya or this PyTorch tutorial. For now, though, we'll dive into a demo!
\n\nTo generate new images with a GAN, you only need the generator model. There are many different architectures that the generator could use, but for this demo we'll use a pretrained GAN generator model with the following architecture:
\n\nfrom torch import nn\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n
We're taking the generator from this repo by @teddykoker, where you can also see the original discriminator model structure.
\n\nAfter instantiating the model, we'll load in the weights from the Hugging Face Hub, stored at nateraw/cryptopunks-gan:
\n\nfrom huggingface_hub import hf_hub_download\nimport torch\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n
predict
functionThe predict
function is the key to making Gradio work! Whatever inputs we choose through the Gradio interface will get passed through our predict
function, which should operate on the inputs and generate outputs that we can display with Gradio output components. For GANs it's common to pass random noise into our model as the input, so we'll generate a tensor of random numbers and pass that through the model. We can then use torchvision
's save_image
function to save the output of the model as a png
file, and return the file name:
from torchvision.utils import save_image\n\ndef predict(seed):\n num_punks = 4\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
We're giving our predict
function a seed
parameter, so that we can fix the random tensor generation with a seed. We'll then be able to reproduce punks if we want to see them again by passing in the same seed.
Note! Our model needs an input tensor of dimensions 100x1x1 to do a single inference, or (BatchSize)x100x1x1 for generating a batch of images. In this demo we'll start by generating 4 punks at a time.
\n\nAt this point you can even run the code you have with predict(<SOME_NUMBER>)
, and you'll find your freshly generated punks in your file system at ./punks.png
. To make a truly interactive demo, though, we'll build out a simple interface with Gradio. Our goals here are to:
predict()
to take the seed and generate the imagesWith gr.Interface()
, we can define all of that with a single function call:
import gradio as gr\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n ],\n outputs=\"image\",\n).launch()\n
Launching the interface should present you with something like this:
\n\n\n\nGenerating 4 punks at a time is a good start, but maybe we'd like to control how many we want to make each time. Adding more inputs to our Gradio interface is as simple as adding another item to the inputs
list that we pass to gr.Interface
:
gr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10), # Adding another slider!\n ],\n outputs=\"image\",\n).launch()\n
The new input will be passed to our predict()
function, so we have to make some changes to that function to accept a new parameter:
def predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n
When you relaunch your interface, you should see a second slider that'll let you control the number of punks!
\n\nYour Gradio app is pretty much good to go, but you can add a few extra things to really make it ready for the spotlight \u2728
\n\nWe can add some examples that users can easily try out by adding this to the gr.Interface
:
gr.Interface(\n # ...\n # keep everything as it is, and then add\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True) # cache_examples is optional\n
The examples
parameter takes a list of lists, where each item in the sublists is ordered in the same order that we've listed the inputs
. So in our case, [seed, num_punks]
. Give it a try!
You can also try adding a title
, description
, and article
to the gr.Interface
. Each of those parameters accepts a string, so try it out and see what happens \ud83d\udc40 article
will also accept HTML, as explored in a previous guide!
When you're all done, you may end up with something like this:
\n\n\n\nFor reference, here is our full code:
\n\nimport torch\nfrom torch import nn\nfrom huggingface_hub import hf_hub_download\nfrom torchvision.utils import save_image\nimport gradio as gr\n\nclass Generator(nn.Module):\n # Refer to the link below for explanations about nc, nz, and ngf\n # https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html#inputs\n def __init__(self, nc=4, nz=100, ngf=64):\n super(Generator, self).__init__()\n self.network = nn.Sequential(\n nn.ConvTranspose2d(nz, ngf * 4, 3, 1, 0, bias=False),\n nn.BatchNorm2d(ngf * 4),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 4, ngf * 2, 3, 2, 1, bias=False),\n nn.BatchNorm2d(ngf * 2),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 0, bias=False),\n nn.BatchNorm2d(ngf),\n nn.ReLU(True),\n nn.ConvTranspose2d(ngf, nc, 4, 2, 1, bias=False),\n nn.Tanh(),\n )\n\n def forward(self, input):\n output = self.network(input)\n return output\n\nmodel = Generator()\nweights_path = hf_hub_download('nateraw/cryptopunks-gan', 'generator.pth')\nmodel.load_state_dict(torch.load(weights_path, map_location=torch.device('cpu'))) # Use 'cuda' if you have a GPU available\n\ndef predict(seed, num_punks):\n torch.manual_seed(seed)\n z = torch.randn(num_punks, 100, 1, 1)\n punks = model(z)\n save_image(punks, \"punks.png\", normalize=True)\n return 'punks.png'\n\ngr.Interface(\n predict,\n inputs=[\n gr.Slider(0, 1000, label='Seed', default=42),\n gr.Slider(4, 64, label='Number of Punks', step=1, default=10),\n ],\n outputs=\"image\",\n examples=[[123, 15], [42, 29], [456, 8], [1337, 35]],\n).launch(cache_examples=True)\n
Congratulations! You've built out your very own GAN-powered CryptoPunks generator, with a fancy Gradio interface that makes it easy for anyone to use. Now you can scour the Hub for more GANs (or train your own) and continue making even more awesome demos \ud83e\udd17
\n", "tags": ["GAN", "IMAGE", "HUB"], "spaces": ["https://huggingface.co/spaces/NimaBoscarino/cryptopunks", "https://huggingface.co/spaces/nateraw/cryptopunks-generator"], "url": "/guides/create-your-own-friends-with-a-gan/", "contributor": "Nima Boscarino and Nate Raw"}], "parent": "gradio", "prev_obj": "load", "next_obj": "Progress"}, "progress": {"class": null, "name": "Progress", "description": "The Progress class provides a custom progress tracker that is used in a function signature. To attach a Progress tracker to a function, simply add a parameter right after the input parameters that has a default value set to a `gradio.Progress()` instance. The Progress tracker can then be updated in the function by calling the Progress object or using the `tqdm` method on an Iterable. The Progress tracker is currently only available with `queue()`.", "tags": {"demos": "progress"}, "parameters": [{"name": "self", "annotation": "The purpose of this guide is to illustrate how to add a new component, which you can use in your Gradio applications. The guide will be complemented by code snippets showing step by step how the ColorPicker component was added.
\n\nMake sure you have followed the CONTRIBUTING.md guide in order to setup your local development environment (both client and server side).
\n\nHere's how to create a new component on Gradio:
\n\n\n\nThe first thing to do is to create a new class within the components.py file. This Python class should inherit from a list of base components and should be placed within the file in the correct section with respect to the type of component you want to add (e.g. input, output or static components).\nIn general, it is advisable to take an existing component as a reference (e.g. TextBox), copy its code as a skeleton and then adapt it to the case at hand.
\n\nLet's take a look at the class added to the components.py file for the ColorPicker component:
\n\n@document()\nclass ColorPicker(Changeable, Submittable, IOComponent):\n \"\"\"\n Creates a color picker for user to select a color as string input.\n Preprocessing: passes selected color value as a {str} into the function.\n Postprocessing: expects a {str} returned from function and sets color picker value to it.\n Examples-format: a {str} with a hexadecimal representation of a color, e.g. \"#ff0000\" for red.\n Demos: color_picker, color_generator\n \"\"\"\n\n def __init__(\n self,\n value: str = None,\n *,\n label: Optional[str] = None,\n show_label: bool = True,\n interactive: Optional[bool] = None,\n visible: bool = True,\n elem_id: Optional[str] = None,\n **kwargs,\n ):\n \"\"\"\n Parameters:\n value: default text to provide in color picker.\n label: component name in interface.\n show_label: if True, will display label.\n interactive: if True, will be rendered as an editable color picker; if False, editing will be disabled. If not provided, this is inferred based on whether the component is used as an input or output.\n visible: If False, component will be hidden.\n elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.\n \"\"\"\n self.value = self.postprocess(value)\n self.cleared_value = \"#000000\"\n self.test_input = value\n IOComponent.__init__(\n self,\n label=label,\n show_label=show_label,\n interactive=interactive,\n visible=visible,\n elem_id=elem_id,\n **kwargs,\n )\n\n def get_config(self):\n return {\n \"value\": self.value,\n **IOComponent.get_config(self),\n }\n\n @staticmethod\n def update(\n value: Optional[Any] = None,\n label: Optional[str] = None,\n show_label: Optional[bool] = None,\n visible: Optional[bool] = None,\n interactive: Optional[bool] = None,\n ):\n return {\n \"value\": value,\n \"label\": label,\n \"show_label\": show_label,\n \"visible\": visible,\n \"interactive\": interactive,\n \"__type__\": \"update\",\n }\n\n # Input Functionalities\n def preprocess(self, x: str | None) -> Any:\n \"\"\"\n Any preprocessing needed to be performed on function input.\n Parameters:\n x (str): text\n Returns:\n (str): text\n \"\"\"\n if x is None:\n return None\n else:\n return str(x)\n\n def preprocess_example(self, x: str | None) -> Any:\n \"\"\"\n Any preprocessing needed to be performed on an example before being passed to the main function.\n \"\"\"\n if x is None:\n return None\n else:\n return str(x)\n\n # Output Functionalities\n def postprocess(self, y: str | None):\n \"\"\"\n Any postprocessing needed to be performed on function output.\n Parameters:\n y (str | None): text\n Returns:\n (str | None): text\n \"\"\"\n if y is None:\n return None\n else:\n return str(y)\n\n def deserialize(self, x):\n \"\"\"\n 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.)\n \"\"\"\n return x\n
Once defined, it is necessary to import the new class inside the __init__ module class in order to make it module visible.
\n\n\nfrom gradio.components import (\n ...\n ColorPicker,\n ...\n)\n\n
When developing new components, you should also write a suite of unit tests for it. The tests should be placed in the gradio/test/test_components.py file. Again, as above, take a cue from the tests of other components (e.g. Textbox) and add as many unit tests as you think are appropriate to test all the different aspects and functionalities of the new component. For example, the following tests were added for the ColorPicker component:
\n\nclass TestColorPicker(unittest.TestCase):\n def test_component_functions(self):\n \"\"\"\n Preprocess, postprocess, serialize, save_flagged, restore_flagged, tokenize, get_config\n \"\"\"\n color_picker_input = gr.ColorPicker()\n self.assertEqual(color_picker_input.preprocess(\"#000000\"), \"#000000\")\n self.assertEqual(color_picker_input.preprocess_example(\"#000000\"), \"#000000\")\n self.assertEqual(color_picker_input.postprocess(None), None)\n self.assertEqual(color_picker_input.postprocess(\"#FFFFFF\"), \"#FFFFFF\")\n self.assertEqual(color_picker_input.serialize(\"#000000\", True), \"#000000\")\n\n color_picker_input.interpretation_replacement = \"unknown\"\n\n self.assertEqual(\n color_picker_input.get_config(),\n {\n \"value\": None,\n \"show_label\": True,\n \"label\": None,\n \"style\": {},\n \"elem_id\": None,\n \"visible\": True,\n \"interactive\": None,\n \"name\": \"colorpicker\",\n },\n )\n\n def test_in_interface_as_input(self):\n \"\"\"\n Interface, process, interpret,\n \"\"\"\n iface = gr.Interface(lambda x: x, \"colorpicker\", \"colorpicker\")\n self.assertEqual(iface.process([\"#000000\"]), [\"#000000\"])\n\n def test_in_interface_as_output(self):\n \"\"\"\n Interface, process\n\n \"\"\"\n iface = gr.Interface(lambda x: x, \"colorpicker\", gr.ColorPicker())\n self.assertEqual(iface.process([\"#000000\"]), [\"#000000\"])\n\n def test_static(self):\n \"\"\"\n postprocess\n \"\"\"\n component = gr.ColorPicker(\"#000000\")\n self.assertEqual(component.get_config().get(\"value\"), \"#000000\")\n
Let's see the steps you need to follow to create the frontend of your new component and to map it to its python code:
\n\n\n\n\n\n
export { default as FileName } from \"./FileName.svelte\"
. The ColorPicker file is exported in the index.ts file and the export is performed by doing: export { default as ColorPicker } from \"./ColorPicker.svelte\";
.Here you will have three files, the first file is for the Svelte application, and it will look like this:
\n\n \n\n\n\nmd5-1c697b7cbe98fa7733fff25acc68363e\n\n\n\n\n \n\n \n \n
The second one contains the tests for the frontend, for example for the ColorPicker component:
\n\nimport { test, describe, assert, afterEach } from \"vitest\";\nimport { cleanup, render } from \"@gradio/tootils\";\n\nimport ColorPicker from \"./ColorPicker.svelte\";\nimport type { LoadingStatus } from \"../StatusTracker/types\";\n\nconst loading_status = {\n eta: 0,\n queue_position: 1,\n status: \"complete\" as LoadingStatus[\"status\"],\n scroll_to_output: false,\n visible: true,\n fn_index: 0\n};\n\ndescribe(\"ColorPicker\", () => {\n afterEach(() => cleanup());\n\n test(\"renders provided value\", () => {\n const { getByDisplayValue } = render(ColorPicker, {\n loading_status,\n show_label: true,\n mode: \"dynamic\",\n value: \"#000000\",\n label: \"ColorPicker\"\n });\n\n const item: HTMLInputElement = getByDisplayValue(\"#000000\");\n assert.equal(item.value, \"#000000\");\n });\n\n test(\"changing the color should update the value\", async () => {\n const { component, getByDisplayValue } = render(ColorPicker, {\n loading_status,\n show_label: true,\n mode: \"dynamic\",\n value: \"#000000\",\n label: \"ColorPicker\"\n });\n\n const item: HTMLInputElement = getByDisplayValue(\"#000000\");\n\n assert.equal(item.value, \"#000000\");\n\n await component.$set({\n value: \"#FFFFFF\"\n });\n\n assert.equal(component.value, \"#FFFFFF\");\n });\n});\n
The third one is the index.ts file:
\n\nexport { default as Component } from \"./ColorPicker.svelte\";\nexport const modes = [\"static\", \"dynamic\"];\n
export const component_map = {\n...\ncolorpicker: () => import(\"./ColorPicker\"),\n...\n}\n
When developing new components, you should also write a suite of unit tests for it. The tests should be placed in the new component's folder in a file named MyAwesomeComponent.test.ts. Again, as above, take a cue from the tests of other components (e.g. Textbox.test.ts) and add as many unit tests as you think are appropriate to test all the different aspects and functionalities of the new component.
\n\nThe last step is to create a demo in the gradio/demo folder, which will use the newly added component. Again, the suggestion is to reference an existing demo. Write the code for the demo in a file called run.py, add the necessary requirements and an image showing the application interface. Finally add a gif showing its usage.\nYou can take a look at the demo created for the ColorPicker, where an icon and a color selected through the new component is taken as input, and the same icon colored with the selected color is returned as output.
\n\nTo test the application:
\n\npython path/demo/run.py
which starts the backend at the address http://localhost:7860;pnpm dev
to start the frontend at http://localhost:9876 with hot reload functionalities.In this guide, we have shown how simple it is to add a new component to Gradio, seeing step by step how the ColorPicker component was added. For further details, you can refer to PR: #1695.
\n", "tags": [], "spaces": [], "url": "/guides/creating-a-new-component/", "contributor": null}} +{"guide": {"name": "creating-a-new-component", "category": "other-tutorials", "pretty_category": "Other Tutorials", "guide_index": null, "absolute_index": 35, "pretty_name": "Creating A New Component", "content": "# How to Create a New Component\n\n## Introduction\n\nThe purpose of this guide is to illustrate how to add a new component, which you can use in your Gradio applications. The guide will be complemented by code snippets showing step by step how the [ColorPicker](https://gradio.app/docs/#colorpicker) component was added.\n\n## Prerequisites\n\nMake sure you have followed the [CONTRIBUTING.md](https://github.com/gradio-app/gradio/blob/main/CONTRIBUTING.md) guide in order to setup your local development environment (both client and server side).\n\nHere's how to create a new component on Gradio:\n\n1. [Create a New Python Class and Import it](#1-create-a-new-python-class-and-import-it)\n2. [Create a New Svelte Component](#2-create-a-new-svelte-component)\n3. [Create a New Demo](#3-create-a-new-demo)\n\n## 1. Create a New Python Class and Import it\n\nThe first thing to do is to create a new class within the [components.py](https://github.com/gradio-app/gradio/blob/main/gradio/components.py) file. This Python class should inherit from a list of base components and should be placed within the file in the correct section with respect to the type of component you want to add (e.g. input, output or static components).\nIn general, it is advisable to take an existing component as a reference (e.g. [TextBox](https://github.com/gradio-app/gradio/blob/main/gradio/components.py#L290)), copy its code as a skeleton and then adapt it to the case at hand.\n\nLet's take a look at the class added to the [components.py](https://github.com/gradio-app/gradio/blob/main/gradio/components.py) file for the ColorPicker component:\n\n```python\n@document()\nclass ColorPicker(Changeable, Submittable, IOComponent):\n \"\"\"\n Creates a color picker for user to select a color as string input.\n Preprocessing: passes selected color value as a {str} into the function.\n Postprocessing: expects a {str} returned from function and sets color picker value to it.\n Examples-format: a {str} with a hexadecimal representation of a color, e.g. \"#ff0000\" for red.\n Demos: color_picker, color_generator\n \"\"\"\n\n def __init__(\n self,\n value: str = None,\n *,\n label: Optional[str] = None,\n show_label: bool = True,\n interactive: Optional[bool] = None,\n visible: bool = True,\n elem_id: Optional[str] = None,\n **kwargs,\n ):\n \"\"\"\n Parameters:\n value: default text to provide in color picker.\n label: component name in interface.\n show_label: if True, will display label.\n interactive: if True, will be rendered as an editable color picker; if False, editing will be disabled. If not provided, this is inferred based on whether the component is used as an input or output.\n visible: If False, component will be hidden.\n elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.\n \"\"\"\n self.value = self.postprocess(value)\n self.cleared_value = \"#000000\"\n self.test_input = value\n IOComponent.__init__(\n self,\n label=label,\n show_label=show_label,\n interactive=interactive,\n visible=visible,\n elem_id=elem_id,\n **kwargs,\n )\n\n def get_config(self):\n return {\n \"value\": self.value,\n **IOComponent.get_config(self),\n }\n\n @staticmethod\n def update(\n value: Optional[Any] = None,\n label: Optional[str] = None,\n show_label: Optional[bool] = None,\n visible: Optional[bool] = None,\n interactive: Optional[bool] = None,\n ):\n return {\n \"value\": value,\n \"label\": label,\n \"show_label\": show_label,\n \"visible\": visible,\n \"interactive\": interactive,\n \"__type__\": \"update\",\n }\n\n # Input Functionalities\n def preprocess(self, x: str | None) -> Any:\n \"\"\"\n Any preprocessing needed to be performed on function input.\n Parameters:\n x (str): text\n Returns:\n (str): text\n \"\"\"\n if x is None:\n return None\n else:\n return str(x)\n\n def preprocess_example(self, x: str | None) -> Any:\n \"\"\"\n Any preprocessing needed to be performed on an example before being passed to the main function.\n \"\"\"\n if x is None:\n return None\n else:\n return str(x)\n\n # Output Functionalities\n def postprocess(self, y: str | None):\n \"\"\"\n Any postprocessing needed to be performed on function output.\n Parameters:\n y (str | None): text\n Returns:\n (str | None): text\n \"\"\"\n if y is None:\n return None\n else:\n return str(y)\n\n def deserialize(self, x):\n \"\"\"\n 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.)\n \"\"\"\n return x\n```\n\nOnce defined, it is necessary to import the new class inside the [\\_\\_init\\_\\_](https://github.com/gradio-app/gradio/blob/main/gradio/__init__.py) module class in order to make it module visible.\n\n```python\n\nfrom gradio.components import (\n ...\n ColorPicker,\n ...\n)\n\n```\n\n### 1.1 Writing Unit Test for Python Class\n\nWhen developing new components, you should also write a suite of unit tests for it. The tests should be placed in the [gradio/test/test_components.py](https://github.com/gradio-app/gradio/blob/main/test/test_components.py) file. Again, as above, take a cue from the tests of other components (e.g. [Textbox](https://github.com/gradio-app/gradio/blob/main/test/test_components.py)) and add as many unit tests as you think are appropriate to test all the different aspects and functionalities of the new component. For example, the following tests were added for the ColorPicker component:\n\n```python\nclass TestColorPicker(unittest.TestCase):\n def test_component_functions(self):\n \"\"\"\n Preprocess, postprocess, serialize, save_flagged, restore_flagged, tokenize, get_config\n \"\"\"\n color_picker_input = gr.ColorPicker()\n self.assertEqual(color_picker_input.preprocess(\"#000000\"), \"#000000\")\n self.assertEqual(color_picker_input.preprocess_example(\"#000000\"), \"#000000\")\n self.assertEqual(color_picker_input.postprocess(None), None)\n self.assertEqual(color_picker_input.postprocess(\"#FFFFFF\"), \"#FFFFFF\")\n self.assertEqual(color_picker_input.serialize(\"#000000\", True), \"#000000\")\n\n color_picker_input.interpretation_replacement = \"unknown\"\n\n self.assertEqual(\n color_picker_input.get_config(),\n {\n \"value\": None,\n \"show_label\": True,\n \"label\": None,\n \"style\": {},\n \"elem_id\": None,\n \"visible\": True,\n \"interactive\": None,\n \"name\": \"colorpicker\",\n },\n )\n\n def test_in_interface_as_input(self):\n \"\"\"\n Interface, process, interpret,\n \"\"\"\n iface = gr.Interface(lambda x: x, \"colorpicker\", \"colorpicker\")\n self.assertEqual(iface.process([\"#000000\"]), [\"#000000\"])\n\n def test_in_interface_as_output(self):\n \"\"\"\n Interface, process\n\n \"\"\"\n iface = gr.Interface(lambda x: x, \"colorpicker\", gr.ColorPicker())\n self.assertEqual(iface.process([\"#000000\"]), [\"#000000\"])\n\n def test_static(self):\n \"\"\"\n postprocess\n \"\"\"\n component = gr.ColorPicker(\"#000000\")\n self.assertEqual(component.get_config().get(\"value\"), \"#000000\")\n```\n\n## 2. Create a New Svelte Component\n\nLet's see the steps you need to follow to create the frontend of your new component and to map it to its python code:\n\n- Create a new UI-side Svelte component and figure out where to place it. The options are: create a package for the new component in the [js folder](https://github.com/gradio-app/gradio/tree/main/js/), if this is completely different from existing components or add the new component to an existing package, such as to the [form package](https://github.com/gradio-app/gradio/tree/main/js/form). The ColorPicker component for example, was included in the form package because it is similar to components that already exist.\n- Create a file with an appropriate name in the src folder of the package where you placed the Svelte component, note: the name must start with a capital letter. This is the 'core' component and it's the generic component that has no knowledge of Gradio specific functionality. Initially add any text/html to this file so that the component renders something. The Svelte application code for the ColorPicker looks like this:\n\n```typescript\n\n\n\n\n```\n\n- Export this file inside the index.ts file of the package where you placed the Svelte component by doing `export { default as FileName } from \"./FileName.svelte\"`. The ColorPicker file is exported in the [index.ts](https://github.com/gradio-app/gradio/blob/main/js/form/src/index.ts) file and the export is performed by doing: `export { default as ColorPicker } from \"./ColorPicker.svelte\";`.\n- Create the Gradio specific component in [js/app/src/components](https://github.com/gradio-app/gradio/tree/main/js/app/src/components). This is a Gradio wrapper that handles the specific logic of the library, passes the necessary data down to the core component and attaches any necessary event listeners. Copy the folder of another component, rename it and edit the code inside it, keeping the structure.\n\nHere you will have three files, the first file is for the Svelte application, and it will look like this:\n\n```typescript\nThe purpose of this guide is to illustrate how to add a new component, which you can use in your Gradio applications. The guide will be complemented by code snippets showing step by step how the ColorPicker component was added.
\n\nMake sure you have followed the CONTRIBUTING.md guide in order to setup your local development environment (both client and server side).
\n\nHere's how to create a new component on Gradio:
\n\n\n\nThe first thing to do is to create a new class within the components.py file. This Python class should inherit from a list of base components and should be placed within the file in the correct section with respect to the type of component you want to add (e.g. input, output or static components).\nIn general, it is advisable to take an existing component as a reference (e.g. TextBox), copy its code as a skeleton and then adapt it to the case at hand.
\n\nLet's take a look at the class added to the components.py file for the ColorPicker component:
\n\n@document()\nclass ColorPicker(Changeable, Submittable, IOComponent):\n \"\"\"\n Creates a color picker for user to select a color as string input.\n Preprocessing: passes selected color value as a {str} into the function.\n Postprocessing: expects a {str} returned from function and sets color picker value to it.\n Examples-format: a {str} with a hexadecimal representation of a color, e.g. \"#ff0000\" for red.\n Demos: color_picker, color_generator\n \"\"\"\n\n def __init__(\n self,\n value: str = None,\n *,\n label: Optional[str] = None,\n show_label: bool = True,\n interactive: Optional[bool] = None,\n visible: bool = True,\n elem_id: Optional[str] = None,\n **kwargs,\n ):\n \"\"\"\n Parameters:\n value: default text to provide in color picker.\n label: component name in interface.\n show_label: if True, will display label.\n interactive: if True, will be rendered as an editable color picker; if False, editing will be disabled. If not provided, this is inferred based on whether the component is used as an input or output.\n visible: If False, component will be hidden.\n elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.\n \"\"\"\n self.value = self.postprocess(value)\n self.cleared_value = \"#000000\"\n self.test_input = value\n IOComponent.__init__(\n self,\n label=label,\n show_label=show_label,\n interactive=interactive,\n visible=visible,\n elem_id=elem_id,\n **kwargs,\n )\n\n def get_config(self):\n return {\n \"value\": self.value,\n **IOComponent.get_config(self),\n }\n\n @staticmethod\n def update(\n value: Optional[Any] = None,\n label: Optional[str] = None,\n show_label: Optional[bool] = None,\n visible: Optional[bool] = None,\n interactive: Optional[bool] = None,\n ):\n return {\n \"value\": value,\n \"label\": label,\n \"show_label\": show_label,\n \"visible\": visible,\n \"interactive\": interactive,\n \"__type__\": \"update\",\n }\n\n # Input Functionalities\n def preprocess(self, x: str | None) -> Any:\n \"\"\"\n Any preprocessing needed to be performed on function input.\n Parameters:\n x (str): text\n Returns:\n (str): text\n \"\"\"\n if x is None:\n return None\n else:\n return str(x)\n\n def preprocess_example(self, x: str | None) -> Any:\n \"\"\"\n Any preprocessing needed to be performed on an example before being passed to the main function.\n \"\"\"\n if x is None:\n return None\n else:\n return str(x)\n\n # Output Functionalities\n def postprocess(self, y: str | None):\n \"\"\"\n Any postprocessing needed to be performed on function output.\n Parameters:\n y (str | None): text\n Returns:\n (str | None): text\n \"\"\"\n if y is None:\n return None\n else:\n return str(y)\n\n def deserialize(self, x):\n \"\"\"\n 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.)\n \"\"\"\n return x\n
Once defined, it is necessary to import the new class inside the __init__ module class in order to make it module visible.
\n\n\nfrom gradio.components import (\n ...\n ColorPicker,\n ...\n)\n\n
When developing new components, you should also write a suite of unit tests for it. The tests should be placed in the gradio/test/test_components.py file. Again, as above, take a cue from the tests of other components (e.g. Textbox) and add as many unit tests as you think are appropriate to test all the different aspects and functionalities of the new component. For example, the following tests were added for the ColorPicker component:
\n\nclass TestColorPicker(unittest.TestCase):\n def test_component_functions(self):\n \"\"\"\n Preprocess, postprocess, serialize, save_flagged, restore_flagged, tokenize, get_config\n \"\"\"\n color_picker_input = gr.ColorPicker()\n self.assertEqual(color_picker_input.preprocess(\"#000000\"), \"#000000\")\n self.assertEqual(color_picker_input.preprocess_example(\"#000000\"), \"#000000\")\n self.assertEqual(color_picker_input.postprocess(None), None)\n self.assertEqual(color_picker_input.postprocess(\"#FFFFFF\"), \"#FFFFFF\")\n self.assertEqual(color_picker_input.serialize(\"#000000\", True), \"#000000\")\n\n color_picker_input.interpretation_replacement = \"unknown\"\n\n self.assertEqual(\n color_picker_input.get_config(),\n {\n \"value\": None,\n \"show_label\": True,\n \"label\": None,\n \"style\": {},\n \"elem_id\": None,\n \"visible\": True,\n \"interactive\": None,\n \"name\": \"colorpicker\",\n },\n )\n\n def test_in_interface_as_input(self):\n \"\"\"\n Interface, process, interpret,\n \"\"\"\n iface = gr.Interface(lambda x: x, \"colorpicker\", \"colorpicker\")\n self.assertEqual(iface.process([\"#000000\"]), [\"#000000\"])\n\n def test_in_interface_as_output(self):\n \"\"\"\n Interface, process\n\n \"\"\"\n iface = gr.Interface(lambda x: x, \"colorpicker\", gr.ColorPicker())\n self.assertEqual(iface.process([\"#000000\"]), [\"#000000\"])\n\n def test_static(self):\n \"\"\"\n postprocess\n \"\"\"\n component = gr.ColorPicker(\"#000000\")\n self.assertEqual(component.get_config().get(\"value\"), \"#000000\")\n
Let's see the steps you need to follow to create the frontend of your new component and to map it to its python code:
\n\n\n\n\n\n
export { default as FileName } from \"./FileName.svelte\"
. The ColorPicker file is exported in the index.ts file and the export is performed by doing: export { default as ColorPicker } from \"./ColorPicker.svelte\";
.Here you will have three files, the first file is for the Svelte application, and it will look like this:
\n\n \n\n\n\nmd5-5bf208f8c1244c0681e3d075472ffa26\n\n\n\n\n \n\n \n \n
The second one contains the tests for the frontend, for example for the ColorPicker component:
\n\nimport { test, describe, assert, afterEach } from \"vitest\";\nimport { cleanup, render } from \"@gradio/tootils\";\n\nimport ColorPicker from \"./ColorPicker.svelte\";\nimport type { LoadingStatus } from \"@gradio/statustracker/types\";\n\nconst loading_status = {\n eta: 0,\n queue_position: 1,\n status: \"complete\" as LoadingStatus[\"status\"],\n scroll_to_output: false,\n visible: true,\n fn_index: 0\n};\n\ndescribe(\"ColorPicker\", () => {\n afterEach(() => cleanup());\n\n test(\"renders provided value\", () => {\n const { getByDisplayValue } = render(ColorPicker, {\n loading_status,\n show_label: true,\n mode: \"dynamic\",\n value: \"#000000\",\n label: \"ColorPicker\"\n });\n\n const item: HTMLInputElement = getByDisplayValue(\"#000000\");\n assert.equal(item.value, \"#000000\");\n });\n\n test(\"changing the color should update the value\", async () => {\n const { component, getByDisplayValue } = render(ColorPicker, {\n loading_status,\n show_label: true,\n mode: \"dynamic\",\n value: \"#000000\",\n label: \"ColorPicker\"\n });\n\n const item: HTMLInputElement = getByDisplayValue(\"#000000\");\n\n assert.equal(item.value, \"#000000\");\n\n await component.$set({\n value: \"#FFFFFF\"\n });\n\n assert.equal(component.value, \"#FFFFFF\");\n });\n});\n
The third one is the index.ts file:
\n\nexport { default as Component } from \"./ColorPicker.svelte\";\nexport const modes = [\"static\", \"dynamic\"];\n
export const component_map = {\n...\ncolorpicker: () => import(\"./ColorPicker\"),\n...\n}\n
When developing new components, you should also write a suite of unit tests for it. The tests should be placed in the new component's folder in a file named MyAwesomeComponent.test.ts. Again, as above, take a cue from the tests of other components (e.g. Textbox.test.ts) and add as many unit tests as you think are appropriate to test all the different aspects and functionalities of the new component.
\n\nThe last step is to create a demo in the gradio/demo folder, which will use the newly added component. Again, the suggestion is to reference an existing demo. Write the code for the demo in a file called run.py, add the necessary requirements and an image showing the application interface. Finally add a gif showing its usage.\nYou can take a look at the demo created for the ColorPicker, where an icon and a color selected through the new component is taken as input, and the same icon colored with the selected color is returned as output.
\n\nTo test the application:
\n\npython path/demo/run.py
which starts the backend at the address http://localhost:7860;pnpm dev
to start the frontend at http://localhost:9876 with hot reload functionalities.In this guide, we have shown how simple it is to add a new component to Gradio, seeing step by step how the ColorPicker component was added. For further details, you can refer to PR: #1695.
\n", "tags": [], "spaces": [], "url": "/guides/creating-a-new-component/", "contributor": null}} \ No newline at end of file diff --git a/js/_website/src/routes/guides/json/guides_by_category.json b/js/_website/src/routes/guides/json/guides_by_category.json index ab7e3fe2a3006..7c77a915ba6ea 100644 --- a/js/_website/src/routes/guides/json/guides_by_category.json +++ b/js/_website/src/routes/guides/json/guides_by_category.json @@ -1 +1 @@ -{"guides_by_category": [{"category": "Getting Started", "guides": [{"name": "quickstart", "category": "getting-started", "pretty_category": "Getting Started", "guide_index": 1, "absolute_index": 0, "pretty_name": "Quickstart", "content": "# Quickstart\n\n**Prerequisite**: Gradio requires Python 3.8 or higher, that's all!\n\n## What Does Gradio Do?\n\nOne of the *best ways to share* your machine learning model, API, or data science workflow with others is to create an **interactive app** that allows your users or colleagues to try out the demo in their browsers.\n\nGradio allows you to **build demos and share them, all in Python.** And usually in just a few lines of code! So let's get started.\n\n## Hello, World\n\nTo get Gradio running with a simple \"Hello, World\" example, follow these three steps:\n\n1\\. Install Gradio using pip:\n\n```bash\npip install gradio\n```\n\n2\\. Run the code below as a Python script or in a Jupyter Notebook (or [Google Colab](https://colab.research.google.com/drive/18ODkJvyxHutTN0P5APWyGFO_xwNcgHDZ?usp=sharing)):\n\n```python\nimport gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\ndemo = gr.Interface(fn=greet, inputs=\"text\", outputs=\"text\")\n \ndemo.launch() \n```\n\nWe shorten the imported name to `gr` for better readability of code using Gradio. This is a widely adopted convention that you should follow so that anyone working with your code can easily understand it.\n\n3\\. The demo below will appear automatically within the Jupyter Notebook, or pop in a browser on [http://localhost:7860](http://localhost:7860) if running from a script:\n\nPrerequisite: Gradio requires Python 3.8 or higher, that's all!
\n\nOne of the best ways to share your machine learning model, API, or data science workflow with others is to create an interactive app that allows your users or colleagues to try out the demo in their browsers.
\n\nGradio allows you to build demos and share them, all in Python. And usually in just a few lines of code! So let's get started.
\n\nTo get Gradio running with a simple \"Hello, World\" example, follow these three steps:
\n\n1. Install Gradio using pip:
\n\npip install gradio\n
2. Run the code below as a Python script or in a Jupyter Notebook (or Google Colab):
\n\nimport gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\ndemo = gr.Interface(fn=greet, inputs=\"text\", outputs=\"text\")\n\ndemo.launch() \n
We shorten the imported name to gr
for better readability of code using Gradio. This is a widely adopted convention that you should follow so that anyone working with your code can easily understand it.
3. The demo below will appear automatically within the Jupyter Notebook, or pop in a browser on http://localhost:7860 if running from a script:
\n\nWhen developing locally, if you want to run the code as a Python script, you can use the Gradio CLI to launch the application in reload mode, which will provide seamless and fast development. Learn more about reloading in the Auto-Reloading Guide.
\n\ngradio app.py\n
Note: you can also do python app.py
, but it won't provide the automatic reload mechanism.
Interface
ClassYou'll notice that in order to make the demo, we created a gr.Interface
. This Interface
class can wrap any Python function with a user interface. In the example above, we saw a simple text-based function, but the function could be anything from music generator to a tax calculator to the prediction function of a pretrained machine learning model.
The core Interface
class is initialized with three required parameters:
fn
: the function to wrap a UI aroundinputs
: which component(s) to use for the input (e.g. \"text\"
, \"image\"
or \"audio\"
)outputs
: which component(s) to use for the output (e.g. \"text\"
, \"image\"
or \"label\"
)Let's take a closer look at these components used to provide input and output.
\n\nWe saw some simple Textbox
components in the previous examples, but what if you want to change how the UI components look or behave?
Let's say you want to customize the input text field \u2014 for example, you wanted it to be larger and have a text placeholder. If we use the actual class for Textbox
instead of using the string shortcut, you have access to much more customizability through component attributes.
import gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\ndemo = gr.Interface(\n fn=greet,\n inputs=gr.Textbox(lines=2, placeholder=\"Name Here...\"),\n outputs=\"text\",\n)\ndemo.launch()\n\n
Suppose you had a more complex function, with multiple inputs and outputs. In the example below, we define a function that takes a string, boolean, and number, and returns a string and number. Take a look how you pass a list of input and output components.
\n\nimport gradio as gr\n\ndef greet(name, is_morning, temperature):\n salutation = \"Good morning\" if is_morning else \"Good evening\"\n greeting = f\"{salutation} {name}. It is {temperature} degrees today\"\n celsius = (temperature - 32) * 5 / 9\n return greeting, round(celsius, 2)\n\ndemo = gr.Interface(\n fn=greet,\n inputs=[\"text\", \"checkbox\", gr.Slider(0, 100)],\n outputs=[\"text\", \"number\"],\n)\ndemo.launch()\n\n
You simply wrap the components in a list. Each component in the inputs
list corresponds to one of the parameters of the function, in order. Each component in the outputs
list corresponds to one of the values returned by the function, again in order.
Gradio supports many types of components, such as Image
, DataFrame
, Video
, or Label
. Let's try an image-to-image function to get a feel for these!
import numpy as np\nimport gradio as gr\n\ndef sepia(input_img):\n sepia_filter = np.array([\n [0.393, 0.769, 0.189], \n [0.349, 0.686, 0.168], \n [0.272, 0.534, 0.131]\n ])\n sepia_img = input_img.dot(sepia_filter.T)\n sepia_img /= sepia_img.max()\n return sepia_img\n\ndemo = gr.Interface(sepia, gr.Image(shape=(200, 200)), \"image\")\ndemo.launch()\n\n
When using the Image
component as input, your function will receive a NumPy array with the shape (height, width, 3)
, where the last dimension represents the RGB values. We'll return an image as well in the form of a NumPy array.
You can also set the datatype used by the component with the type=
keyword argument. For example, if you wanted your function to take a file path to an image instead of a NumPy array, the input Image
component could be written as:
gr.Image(type=\"filepath\", shape=...)\n
Also note that our input Image
component comes with an edit button \ud83d\udd89, which allows for cropping and zooming into images. Manipulating images in this way can help reveal biases or hidden flaws in a machine learning model!
You can read more about the many components and how to use them in the Gradio docs.
\n\nGradio includes a high-level class, gr.ChatInterface
, which is similar to gr.Interface
, but is specifically designed for chatbot UIs. The gr.ChatInterface
class also wraps a function but this function must have a specific signature. The function should take two arguments: message
and then history
(the arguments can be named anything, but must be in this order)
message
: a str
representing the user's inputhistory
: a list
of list
representing the conversations up until that point. Each inner list consists of two str
representing a pair: [user input, bot response]
. Your function should return a single string response, which is the bot's response to the particular user input message
.
Other than that, gr.ChatInterface
has no required parameters (though several are available for customization of the UI).
Here's a toy example:
\n\nimport random\nimport gradio as gr\n\ndef random_response(message, history):\n return random.choice([\"Yes\", \"No\"])\n\ndemo = gr.ChatInterface(random_response)\n\ndemo.launch()\n\n
You can read more about gr.ChatInterface
here.
Gradio offers two approaches to build apps:
\n\n1. Interface and ChatInterface, which provide a high-level abstraction for creating demos that we've been discussing so far.
\n\n2. Blocks, a low-level API for designing web apps with more flexible layouts and data flows. Blocks allows you to do things like feature multiple data flows and demos, control where components appear on the page, handle complex data flows (e.g. outputs can serve as inputs to other functions), and update properties/visibility of components based on user interaction \u2014 still all in Python. If this customizability is what you need, try Blocks
instead!
Let's take a look at a simple example. Note how the API here differs from Interface
.
import gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\nwith gr.Blocks() as demo:\n name = gr.Textbox(label=\"Name\")\n output = gr.Textbox(label=\"Output Box\")\n greet_btn = gr.Button(\"Greet\")\n greet_btn.click(fn=greet, inputs=name, outputs=output, api_name=\"greet\")\n\n\ndemo.launch()\n
Things to note:
\n\nBlocks
are made with a with
clause, and any component created inside this clause is automatically added to the app.Button
was created, and then a click
event-listener was added to this button. The API for this should look familiar! Like an Interface
, the click
method takes a Python function, input components, and output components.Here's an app to give you a taste of what's possible with Blocks
:
import numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
A lot more going on here! We'll cover how to create complex Blocks
apps like this in the building with blocks section for you.
Congrats, you're now familiar with the basics of Gradio! \ud83e\udd73 Go to our next guide to learn more about the key features of Gradio.
\n", "tags": [], "spaces": [], "url": "/guides/quickstart/", "contributor": null}, {"name": "key-features", "category": "getting-started", "pretty_category": "Getting Started", "guide_index": 2, "absolute_index": 1, "pretty_name": "Key Features", "content": "# Key Features\n\nLet's go through some of the most popular features of Gradio! Here are Gradio's key features:\n\n1. [Adding example inputs](#example-inputs)\n2. [Passing custom error messages](#alerts)\n3. [Adding descriptive content](#descriptive-content)\n4. [Setting up flagging](#flagging)\n5. [Preprocessing and postprocessing](#preprocessing-and-postprocessing)\n6. [Styling demos](#styling)\n7. [Queuing users](#queuing)\n8. [Iterative outputs](#iterative-outputs)\n9. [Progress bars](#progress-bars)\n10. [Batch functions](#batch-functions)\n11. [Running on collaborative notebooks](#colab-notebooks)\n\n## Example Inputs\n\nYou can provide example data that a user can easily load into `Interface`. This can be helpful to demonstrate the types of inputs the model expects, as well as to provide a way to explore your dataset in conjunction with your model. To load example data, you can provide a **nested list** to the `examples=` keyword argument of the Interface constructor. Each sublist within the outer list represents a data sample, and each element within the sublist represents an input for each input component. The format of example data for each component is specified in the [Docs](https://gradio.app/docs#components).\n\n```python\nimport gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n if num2 == 0:\n raise gr.Error(\"Cannot divide by zero!\")\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\", \n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n examples=[\n [5, \"add\", 3],\n [4, \"divide\", 2],\n [-4, \"multiply\", 2.5],\n [0, \"subtract\", 1.2],\n ],\n title=\"Toy Calculator\",\n description=\"Here's a sample toy calculator. Allows you to calculate things like $2+2=4$\",\n)\ndemo.launch()\n\n```\nLet's go through some of the most popular features of Gradio! Here are Gradio's key features:
\n\nYou can provide example data that a user can easily load into Interface
. This can be helpful to demonstrate the types of inputs the model expects, as well as to provide a way to explore your dataset in conjunction with your model. To load example data, you can provide a nested list to the examples=
keyword argument of the Interface constructor. Each sublist within the outer list represents a data sample, and each element within the sublist represents an input for each input component. The format of example data for each component is specified in the Docs.
import gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n if num2 == 0:\n raise gr.Error(\"Cannot divide by zero!\")\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\", \n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n examples=[\n [5, \"add\", 3],\n [4, \"divide\", 2],\n [-4, \"multiply\", 2.5],\n [0, \"subtract\", 1.2],\n ],\n title=\"Toy Calculator\",\n description=\"Here's a sample toy calculator. Allows you to calculate things like $2+2=4$\",\n)\ndemo.launch()\n\n
You can load a large dataset into the examples to browse and interact with the dataset through Gradio. The examples will be automatically paginated (you can configure this through the examples_per_page
argument of Interface
).
Continue learning about examples in the More On Examples guide.
\n\nYou wish to pass custom error messages to the user. To do so, raise a gr.Error(\"custom message\")
to display an error message. If you try to divide by zero in the calculator demo above, a popup modal will display the custom error message. Learn more about Error in the docs.
You can also issue gr.Warning(\"message\")
and gr.Info(\"message\")
by having them as standalone lines in your function, which will immediately display modals while continuing the execution of your function. Queueing needs to be enabled for this to work.
Note below how the gr.Error
has to be raised, while the gr.Warning
and gr.Info
are single lines.
def start_process(name):\n gr.Info(\"Starting process\")\n if name is None:\n gr.Warning(\"Name is empty\")\n ...\n if success == False:\n raise gr.Error(\"Process failed\")\n
In the previous example, you may have noticed the title=
and description=
keyword arguments in the Interface
constructor that helps users understand your app.
There are three arguments in the Interface
constructor to specify where this content should go:
title
: which accepts text and can display it at the very top of interface, and also becomes the page title.description
: which accepts text, markdown or HTML and places it right under the title.article
: which also accepts text, markdown or HTML and places it below the interface.If you're using the Blocks
API instead, you can insert text, markdown, or HTML anywhere using the gr.Markdown(...)
or gr.HTML(...)
components, with descriptive content inside the Component
constructor.
Another useful keyword argument is label=
, which is present in every Component
. This modifies the label text at the top of each Component
. You can also add the info=
keyword argument to form elements like Textbox
or Radio
to provide further information on their usage.
gr.Number(label='Age', info='In years, must be greater than 0')\n
By default, an Interface
will have \"Flag\" button. When a user testing your Interface
sees input with interesting output, such as erroneous or unexpected model behaviour, they can flag the input for you to review. Within the directory provided by the flagging_dir=
argument to the Interface
constructor, a CSV file will log the flagged inputs. If the interface involves file data, such as for Image and Audio components, folders will be created to store those flagged data as well.
For example, with the calculator interface shown above, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- calculator.py\n+-- flagged/\n| +-- logs.csv\n
flagged/logs.csv
\n\nnum1,operation,num2,Output\n5,add,7,12\n6,subtract,1.5,4.5\n
With the sepia interface shown earlier, we would have the flagged data stored in the flagged directory shown below:
\n\n+-- sepia.py\n+-- flagged/\n| +-- logs.csv\n| +-- im/\n| | +-- 0.png\n| | +-- 1.png\n| +-- Output/\n| | +-- 0.png\n| | +-- 1.png\n
flagged/logs.csv
\n\nim,Output\nim/0.png,Output/0.png\nim/1.png,Output/1.png\n
If you wish for the user to provide a reason for flagging, you can pass a list of strings to the flagging_options
argument of Interface. Users will have to select one of the strings when flagging, which will be saved as an additional column to the CSV.
As you've seen, Gradio includes components that can handle a variety of different data types, such as images, audio, and video. Most components can be used both as inputs or outputs.
\n\nWhen a component is used as an input, Gradio automatically handles the preprocessing needed to convert the data from a type sent by the user's browser (such as a base64 representation of a webcam snapshot) to a form that can be accepted by your function (such as a numpy
array).
Similarly, when a component is used as an output, Gradio automatically handles the postprocessing needed to convert the data from what is returned by your function (such as a list of image paths) to a form that can be displayed in the user's browser (such as a Gallery
of images in base64 format).
You can control the preprocessing using the parameters when constructing the image component. For example, here if you instantiate the Image
component with the following parameters, it will convert the image to the PIL
type and reshape it to be (100, 100)
no matter the original size that it was submitted as:
img = gr.Image(shape=(100, 100), type=\"pil\")\n
In contrast, here we keep the original size of the image, but invert the colors before converting it to a numpy array:
\n\nimg = gr.Image(invert_colors=True, type=\"numpy\")\n
Postprocessing is a lot easier! Gradio automatically recognizes the format of the returned data (e.g. is the Image
a numpy
array or a str
filepath?) and postprocesses it into a format that can be displayed by the browser.
Take a look at the Docs to see all the preprocessing-related parameters for each Component.
\n\nGradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the theme=
kwarg to the Interface
constructor. For example:
demo = gr.Interface(..., theme=gr.themes.Monochrome())\n
Gradio comes with a set of prebuilt themes which you can load from gr.themes.*
. You can extend these themes or create your own themes from scratch - see the Theming guide for more details.
For additional styling ability, you can pass any CSS to your app using the css=
kwarg.\nThe base class for the Gradio app is gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Interface(css=\".gradio-container {background-color: red}\") as demo:\n ...\n
Some components can be additionally styled through the style()
method. For example:
img = gr.Image(\"lion.jpg\").style(height='24', rounded=False)\n
Take a look at the Docs to see all the styling options for each Component.
\n\nIf your app expects heavy traffic, use the queue()
method to control processing rate. This will queue up calls so only a certain number of requests are processed at a single time. Queueing uses websockets, which also prevent network timeouts, so you should use queueing if the inference time of your function is long (> 1min).
With Interface
:
demo = gr.Interface(...).queue()\ndemo.launch()\n
With Blocks
:
with gr.Blocks() as demo:\n #...\ndemo.queue()\ndemo.launch()\n
You can control the number of requests processed at a single time as such:
\n\ndemo.queue(concurrency_count=3)\n
See the Docs on queueing on configuring other queuing parameters.
\n\nTo specify only certain functions for queueing in Blocks:
\n\nwith gr.Blocks() as demo2:\n num1 = gr.Number()\n num2 = gr.Number()\n output = gr.Number()\n gr.Button(\"Add\").click(\n lambda a, b: a + b, [num1, num2], output)\n gr.Button(\"Multiply\").click(\n lambda a, b: a * b, [num1, num2], output, queue=True)\ndemo2.launch()\n
In some cases, you may want to stream a sequence of outputs rather than show a single output at once. For example, you might have an image generation model and you want to show the image that is generated at each step, leading up to the final image. Or you might have a chatbot which streams its response one word at a time instead of returning it all at once.
\n\nIn such cases, you can supply a generator function into Gradio instead of a regular function. Creating generators in Python is very simple: instead of a single return
value, a function should yield
a series of values instead. Usually the yield
statement is put in some kind of loop. Here's an example of an generator that simply counts up to a given number:
def my_generator(x):\n for i in range(x):\n yield i\n
You supply a generator into Gradio the same way as you would a regular function. For example, here's a a (fake) image generation model that generates noise for several steps before outputting an image:
\n\nimport gradio as gr\nimport numpy as np\nimport time\n\n# define core fn, which returns a generator {steps} times before returning the image\ndef fake_diffusion(steps):\n for _ in range(steps):\n time.sleep(1)\n image = np.random.random((600, 600, 3))\n yield image\n image = \"https://gradio-builds.s3.amazonaws.com/diffusion_image/cute_dog.jpg\"\n yield image\n\n\ndemo = gr.Interface(fake_diffusion, inputs=gr.Slider(1, 10, 3), outputs=\"image\")\n\n# define queue - required for generators\ndemo.queue()\n\ndemo.launch()\n\n
Note that we've added a time.sleep(1)
in the iterator to create an artificial pause between steps so that you are able to observe the steps of the iterator (in a real image generation model, this probably wouldn't be necessary).
Supplying a generator into Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio supports the ability to create a custom Progress Bars so that you have customizability and control over the progress update that you show to the user. In order to enable this, simply add an argument to your method that has a default value of a gr.Progress
instance. Then you can update the progress levels by calling this instance directly with a float between 0 and 1, or using the tqdm()
method of the Progress
instance to track progress over an iterable, as shown below. Queueing must be enabled for progress updates.
import gradio as gr\nimport time\n\ndef slowly_reverse(word, progress=gr.Progress()):\n progress(0, desc=\"Starting\")\n time.sleep(1)\n progress(0.05)\n new_string = \"\"\n for letter in progress.tqdm(word, desc=\"Reversing\"):\n time.sleep(0.25)\n new_string = letter + new_string\n return new_string\n\ndemo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())\n\nif __name__ == \"__main__\":\n demo.queue(concurrency_count=10).launch()\n\n
If you use the tqdm
library, you can even report progress updates automatically from any tqdm.tqdm
that already exists within your function by setting the default argument as gr.Progress(track_tqdm=True)
!
Gradio supports the ability to pass batch functions. Batch functions are just\nfunctions which take in a list of inputs and return a list of predictions.
\n\nFor example, here is a batched function that takes in two lists of inputs (a list of\nwords and a list of ints), and returns a list of trimmed words as output:
\n\nimport time\n\ndef trim_words(words, lens):\n trimmed_words = []\n time.sleep(5)\n for w, l in zip(words, lens):\n trimmed_words.append(w[:int(l)]) \n return [trimmed_words]\n
The advantage of using batched functions is that if you enable queuing, the Gradio\nserver can automatically batch incoming requests and process them in parallel,\npotentially speeding up your demo. Here's what the Gradio code looks like (notice\nthe batch=True
and max_batch_size=16
-- both of these parameters can be passed\ninto event triggers or into the Interface
class)
With Interface
:
demo = gr.Interface(trim_words, [\"textbox\", \"number\"], [\"output\"], \n batch=True, max_batch_size=16)\ndemo.queue()\ndemo.launch()\n
With Blocks
:
import gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n word = gr.Textbox(label=\"word\")\n leng = gr.Number(label=\"leng\")\n output = gr.Textbox(label=\"Output\")\n with gr.Row():\n run = gr.Button()\n\n event = run.click(trim_words, [word, leng], output, batch=True, max_batch_size=16)\n\ndemo.queue()\ndemo.launch()\n
In the example above, 16 requests could be processed in parallel (for a total inference\ntime of 5 seconds), instead of each request being processed separately (for a total\ninference time of 80 seconds). Many Hugging Face transformers
and diffusers
models\nwork very naturally with Gradio's batch mode: here's an example demo using diffusers to\ngenerate images in batches
Note: using batch functions with Gradio requires you to enable queuing in the underlying Interface or Blocks (see the queuing section above).
\n\nGradio is able to run anywhere you run Python, including local jupyter notebooks as well as collaborative notebooks, such as Google Colab. In the case of local jupyter notebooks and Google Colab notbooks, Gradio runs on a local server which you can interact with in your browser. (Note: for Google Colab, this is accomplished by service worker tunneling, which requires cookies to be enabled in your browser.) For other remote notebooks, Gradio will also run on a server, but you will need to use SSH tunneling to view the app in your local browser. Often a simpler options is to use Gradio's built-in public links, discussed in the next Guide.
\n", "tags": [], "spaces": [], "url": "/guides/key-features/", "contributor": null}, {"name": "sharing-your-app", "category": "getting-started", "pretty_category": "Getting Started", "guide_index": 3, "absolute_index": 2, "pretty_name": "Sharing Your App", "content": "# Sharing Your App\n\nHow to share your Gradio app: \n\n1. [Sharing demos with the share parameter](#sharing-demos)\n2. [Hosting on HF Spaces](#hosting-on-hf-spaces)\n3. [Embedding hosted spaces](#embedding-hosted-spaces)\n4. [Embedding with web components](#embedding-with-web-components)\n5. [Using the API page](#api-page)\n6. [Adding authentication to the page](#authentication)\n7. [Accessing Network Requests](#accessing-the-network-request-directly)\n8. [Mounting within FastAPI](#mounting-within-another-fast-api-app)\n9. [Security](#security-and-file-access)\n\n## Sharing Demos\n\nGradio demos can be easily shared publicly by setting `share=True` in the `launch()` method. Like this:\n\n```python\ndemo.launch(share=True)\n```\n\nThis generates a public, shareable link that you can send to anybody! When you send this link, the user on the other side can try out the model in their browser. Because the processing happens on your device (as long as your device stays on!), you don't have to worry about any packaging any dependencies. A share link usually looks something like this: **XXXXX.gradio.app**. Although the link is served through a Gradio URL, we are only a proxy for your local server, and do not store any data sent through your app.\n\nKeep in mind, however, that these links are publicly accessible, meaning that anyone can use your model for prediction! Therefore, make sure not to expose any sensitive information through the functions you write, or allow any critical changes to occur on your device. If you set `share=False` (the default, except in colab notebooks), only a local link is created, which can be shared by [port-forwarding](https://www.ssh.com/ssh/tunneling/example) with specific users. \n\n![sharing](https://github.com/gradio-app/gradio/blob/main/guides/assets/sharing.svg?raw=true)\n\nShare links expire after 72 hours.\n\n## Hosting on HF Spaces\n\nIf you'd like to have a permanent link to your Gradio demo on the internet, use Hugging Face Spaces. [Hugging Face Spaces](http://huggingface.co/spaces/) provides the infrastructure to permanently host your machine learning model for free! \n\nAfter you have [created a free Hugging Face account](https://huggingface.co/join), you have three methods to deploy your Gradio app to Hugging Face Spaces:\n\n1. From terminal: run `gradio deploy` in your app directory. The CLI will gather some basic metadata and then launch your app. To update your space, you can re-run this command or enable the Github Actions option to automatically update the Spaces on `git push`.\n\n2. From your browser: Drag and drop a folder containing your Gradio model and all related files [here](https://huggingface.co/new-space).\n\n3. Connect Spaces with your Git repository and Spaces will pull the Gradio app from there. See [this guide how to host on Hugging Face Spaces](https://huggingface.co/blog/gradio-spaces) for more information. \n\n\n\nNote: Some components, like `gr.Image`, will display a \"Share\" button only on Spaces, so that users can share the generated output to the Discussions page of the Space easily. You can disable this with `show_share_button`, such as `gr.Image(show_share_button=False)`. \n\n![Image with show_share_button=True](https://github.com/gradio-app/gradio/blob/main/guides/assets/share_icon.png?raw=true)\n\n## Embedding Hosted Spaces\n\nOnce you have hosted your app on Hugging Face Spaces (or on your own server), you may want to embed the demo on a different website, such as your blog or your portfolio. Embedding an interactive demo allows people to try out the machine learning model that you have built, without needing to download or install anything \u2014 right in their browser! The best part is that you can embed interactive demos even in static websites, such as GitHub pages.\n\nThere are two ways to embed your Gradio demos. You can find quick links to both options directly on the Hugging Face Space page, in the \"Embed this Space\" dropdown option:\n\n![Embed this Space dropdown option](https://github.com/gradio-app/gradio/blob/main/guides/assets/embed_this_space.png?raw=true)\n\n### Embedding with Web Components\n\nWeb components typically offer a better experience to users than IFrames. Web components load lazily, meaning that they won't slow down the loading time of your website, and they automatically adjust their height based on the size of the Gradio app. \n\nTo embed with Web Components:\n\n1. Import the gradio JS library into into your site by adding the script below in your site (replace {GRADIO_VERSION} in the URL with the library version of Gradio you are using). \n\n```html\n\n```\n\n2. Add \n```html\nHow to share your Gradio app:
\n\nGradio demos can be easily shared publicly by setting share=True
in the launch()
method. Like this:
demo.launch(share=True)\n
This generates a public, shareable link that you can send to anybody! When you send this link, the user on the other side can try out the model in their browser. Because the processing happens on your device (as long as your device stays on!), you don't have to worry about any packaging any dependencies. A share link usually looks something like this: XXXXX.gradio.app. Although the link is served through a Gradio URL, we are only a proxy for your local server, and do not store any data sent through your app.
\n\nKeep in mind, however, that these links are publicly accessible, meaning that anyone can use your model for prediction! Therefore, make sure not to expose any sensitive information through the functions you write, or allow any critical changes to occur on your device. If you set share=False
(the default, except in colab notebooks), only a local link is created, which can be shared by port-forwarding with specific users.
Share links expire after 72 hours.
\n\nIf you'd like to have a permanent link to your Gradio demo on the internet, use Hugging Face Spaces. Hugging Face Spaces provides the infrastructure to permanently host your machine learning model for free!
\n\nAfter you have created a free Hugging Face account, you have three methods to deploy your Gradio app to Hugging Face Spaces:
\n\nFrom terminal: run gradio deploy
in your app directory. The CLI will gather some basic metadata and then launch your app. To update your space, you can re-run this command or enable the Github Actions option to automatically update the Spaces on git push
.
From your browser: Drag and drop a folder containing your Gradio model and all related files here.
Connect Spaces with your Git repository and Spaces will pull the Gradio app from there. See this guide how to host on Hugging Face Spaces for more information.
Note: Some components, like gr.Image
, will display a \"Share\" button only on Spaces, so that users can share the generated output to the Discussions page of the Space easily. You can disable this with show_share_button
, such as gr.Image(show_share_button=False)
.
sharebutton=True\" />
\n\nOnce you have hosted your app on Hugging Face Spaces (or on your own server), you may want to embed the demo on a different website, such as your blog or your portfolio. Embedding an interactive demo allows people to try out the machine learning model that you have built, without needing to download or install anything \u2014 right in their browser! The best part is that you can embed interactive demos even in static websites, such as GitHub pages.
\n\nThere are two ways to embed your Gradio demos. You can find quick links to both options directly on the Hugging Face Space page, in the \"Embed this Space\" dropdown option:
\n\n\n\nWeb components typically offer a better experience to users than IFrames. Web components load lazily, meaning that they won't slow down the loading time of your website, and they automatically adjust their height based on the size of the Gradio app.
\n\nTo embed with Web Components:
\n\n\n
\n
element where you want to place the app. Set the src=
attribute to your Space's embed URL, which you can find in the \"Embed this Space\" button. For example:
\n
You can see examples of how web components look on the Gradio landing page.
\n\nYou can also customize the appearance and behavior of your web component with attributes that you pass into the <gradio-app>
tag:
src
: as we've seen, the src
attributes links to the URL of the hosted Gradio demo that you would like to embedspace
: an optional shorthand if your Gradio demo is hosted on Hugging Face Space. Accepts a username/space_name
instead of a full URL. Example: gradio/Echocardiogram-Segmentation
. If this attribute attribute is provided, then src
does not need to be provided.control_page_title
: a boolean designating whether the html title of the page should be set to the title of the Gradio app (by default \"false\"
)initial_height
: the initial height of the web component while it is loading the Gradio app, (by default \"300px\"
). Note that the final height is set based on the size of the Gradio app.container
: whether to show the border frame and information about where the Space is hosted (by default \"true\"
)info
: whether to show just the information about where the Space is hosted underneath the embedded app (by default \"true\"
)autoscroll
: whether to autoscroll to the output when prediction has finished (by default \"false\"
)eager
: whether to load the Gradio app as soon as the page loads (by default \"false\"
)theme_mode
: whether to use the dark
, light
, or default system
theme mode (by default \"system\"
)Here's an example of how to use these attributes to create a Gradio app that does not lazy load and has an initial height of 0px.
\n\n \n
Note: While Gradio's CSS will never impact the embedding page, the embedding page can affect the style of the embedded Gradio app. Make sure that any CSS in the parent page isn't so general that it could also apply to the embedded Gradio app and cause the styling to break. Element selectors such as header { ... }
and footer { ... }
will be the most likely to cause issues.
To embed with IFrames instead (if you cannot add javascript to your website, for example), add this element:
\n\n\n
Again, you can find the src=
attribute to your Space's embed URL, which you can find in the \"Embed this Space\" button.
Note: if you use IFrames, you'll probably want to add a fixed height
attribute and set style=\"border:0;\"
to remove the boreder. In addition, if your app requires permissions such as access to the webcam or the microphone, you'll need to provide that as well using the allow
attribute.
You can use almost any Gradio app as an API! In the footer of a Gradio app like this one, you'll see a \"Use via API\" link.
\n\n\n\nThis is a page that lists the endpoints that can be used to query the Gradio app, via our supported clients: either the Python client, or the JavaScript client. For each endpoint, Gradio automatically generates the parameters and their types, as well as example inputs.
\n\nThe endpoints are automatically created when you launch a Gradio Interface
. If you are using Gradio Blocks
, you can also set up a Gradio API page, though we recommend that you explicitly name each event listener, such as
btn.click(add, [num1, num2], output, api_name=\"addition\")\n
This will add and document the endpoint /api/addition/
to the automatically generated API page. Otherwise, your API endpoints will appear as \"unnamed\" endpoints.
Note: For Gradio apps in which queueing is enabled, users can bypass the queue if they make a POST request to your API endpoint. To disable this behavior, set api_open=False
in the queue()
method. To disable the API page altogether, set show_api=False
in .launch()
.
You may wish to put an authentication page in front of your app to limit who can open your app. With the auth=
keyword argument in the launch()
method, you can provide a tuple with a username and password, or a list of acceptable username/password tuples; Here's an example that provides password-based authentication for a single user named \"admin\":
demo.launch(auth=(\"admin\", \"pass1234\"))\n
For more complex authentication handling, you can even pass a function that takes a username and password as arguments, and returns True to allow authentication, False otherwise. This can be used for, among other things, making requests to 3rd-party authentication services.
\n\nHere's an example of a function that accepts any login where the username and password are the same:
\n\ndef same_auth(username, password):\n return username == password\ndemo.launch(auth=same_auth)\n
For authentication to work properly, third party cookies must be enabled in your browser.\nThis is not the case by default for Safari, Chrome Incognito Mode.
\n\nWhen a user makes a prediction to your app, you may need the underlying network request, in order to get the request headers (e.g. for advanced authentication), log the client's IP address, or for other reasons. Gradio supports this in a similar manner to FastAPI: simply add a function parameter whose type hint is gr.Request
and Gradio will pass in the network request as that parameter. Here is an example:
import gradio as gr\n\ndef echo(name, request: gr.Request):\n if request:\n print(\"Request headers dictionary:\", request.headers)\n print(\"IP address:\", request.client.host)\n return name\n\nio = gr.Interface(echo, \"textbox\", \"textbox\").launch()\n
Note: if your function is called directly instead of through the UI (this happens, for \nexample, when examples are cached), then request
will be None
. You should handle\nthis case explicitly to ensure that your app does not throw any errors. That is why\nwe have the explicit check if request
.
In some cases, you might have an existing FastAPI app, and you'd like to add a path for a Gradio demo.\nYou can easily do this with gradio.mount_gradio_app()
.
Here's a complete example:
\n\nfrom fastapi import FastAPI\nimport gradio as gr\n\nCUSTOM_PATH = \"/gradio\"\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_main():\n return {\"message\": \"This is your main app\"}\n\n\nio = gr.Interface(lambda x: \"Hello, \" + x + \"!\", \"textbox\", \"textbox\")\napp = gr.mount_gradio_app(app, io, path=CUSTOM_PATH)\n\n\n# Run this from the terminal as you would normally start a FastAPI app: `uvicorn run:app`\n# and navigate to http://localhost:8000/gradio in your browser.\n\n
Note that this approach also allows you run your Gradio apps on custom paths (http://localhost:8000/gradio
in the example above).
Sharing your Gradio app with others (by hosting it on Spaces, on your own server, or through temporary share links) exposes certain files on the host machine to users of your Gradio app.
\n\nIn particular, Gradio apps ALLOW users to access to three kinds of files:
\n\nFiles in the same directory (or a subdirectory) of where the Gradio script is launched from. For example, if the path to your gradio scripts is /home/usr/scripts/project/app.py
and you launch it from /home/usr/scripts/project/
, then users of your shared Gradio app will be able to access any files inside /home/usr/scripts/project/
. This is done so that you can easily reference these files in your Gradio app (e.g. for your app's examples
).
Temporary files created by Gradio. These are files that are created by Gradio as part of running your prediction function. For example, if your prediction function returns a video file, then Gradio will save that video to a temporary file and then send the path to the temporary file to the front end. You can customize the location of temporary files created by Gradio by setting the environment variable GRADIO_TEMP_DIR
to an absolute path, such as /home/usr/scripts/project/temp/
.
Files that you explicitly allow via the allowed_paths
parameter in launch()
. This parameter allows you to pass in a list of additional directories or exact filepaths you'd like to allow users to have access to. (By default, this parameter is an empty list).
Gradio DOES NOT ALLOW access to:
\n\nDotfiles (any files whose name begins with '.'
) or any files that are contained in any directory whose name begins with '.'
Files that you explicitly allow via the blocked_paths
parameter in launch()
. You can pass in a list of additional directories or exact filepaths to the blocked_paths
parameter in launch()
. This parameter takes precedence over the files that Gradio exposes by default or by the allowed_paths
.
Any other paths on the host machine. Users should NOT be able to access other arbitrary paths on the host.
Please make sure you are running the latest version of gradio
for these security settings to apply.
This guide covers how State is handled in Gradio. Learn the difference between Global and Session states, and how to use both.
\n\nYour function may use data that persists beyond a single function call. If the data is something accessible to all function calls and all users, you can create a variable outside the function call and access it inside the function. For example, you may load a large model outside the function and use it inside the function so that every function call does not need to reload the model.
\n\nimport gradio as gr\n\nscores = []\n\ndef track_score(score):\n scores.append(score)\n top_scores = sorted(scores, reverse=True)[:3]\n return top_scores\n\ndemo = gr.Interface(\n track_score, \n gr.Number(label=\"Score\"), \n gr.JSON(label=\"Top Scores\")\n)\ndemo.launch()\n
In the code above, the scores
array is shared between all users. If multiple users are accessing this demo, their scores will all be added to the same list, and the returned top 3 scores will be collected from this shared reference.
Another type of data persistence Gradio supports is session state, where data persists across multiple submits within a page session. However, data is not shared between different users of your model. To store data in a session state, you need to do three things:
\n\n'state'
input and 'state'
output components when creating your Interface
A chatbot is an example where you would need session state - you want access to a users previous submissions, but you cannot store chat history in a global variable, because then chat history would get jumbled between different users.
\n\nimport gradio as gr\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\nimport torch\n\ntokenizer = AutoTokenizer.from_pretrained(\"microsoft/DialoGPT-medium\")\nmodel = AutoModelForCausalLM.from_pretrained(\"microsoft/DialoGPT-medium\")\n\n\ndef user(message, history):\n return \"\", history + [[message, None]]\n\n\ndef bot(history):\n user_message = history[-1][0]\n new_user_input_ids = tokenizer.encode(\n user_message + tokenizer.eos_token, return_tensors=\"pt\"\n )\n\n # append the new user input tokens to the chat history\n bot_input_ids = torch.cat([torch.LongTensor([]), new_user_input_ids], dim=-1)\n\n # generate a response\n response = model.generate(\n bot_input_ids, max_length=1000, pad_token_id=tokenizer.eos_token_id\n ).tolist()\n\n # convert the tokens to text, and then split the responses into lines\n response = tokenizer.decode(response[0]).split(\"<|endoftext|>\")\n response = [\n (response[i], response[i + 1]) for i in range(0, len(response) - 1, 2)\n ] # convert to tuples of list\n history[-1] = response[0]\n return history\n\n\nwith gr.Blocks() as demo:\n chatbot = gr.Chatbot()\n msg = gr.Textbox()\n clear = gr.Button(\"Clear\")\n\n msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(\n bot, chatbot, chatbot\n )\n clear.click(lambda: None, None, chatbot, queue=False)\n\ndemo.launch()\n\n
Notice how the state persists across submits within each page, but if you load this demo in another tab (or refresh the page), the demos will not share chat history.
\n\nThe default value of state
is None. If you pass a default value to the state parameter of the function, it is used as the default value of the state instead. The Interface
class only supports a single input and outputs state variable, though it can be a list with multiple elements. For more complex use cases, you can use Blocks, which supports multiple State
variables.
This guide covers how to get Gradio interfaces to refresh automatically or continuously stream data.
\n\nYou can make interfaces automatically refresh by setting live=True
in the interface. Now the interface will recalculate as soon as the user input changes.
import gradio as gr\n\ndef calculator(num1, operation, num2):\n if operation == \"add\":\n return num1 + num2\n elif operation == \"subtract\":\n return num1 - num2\n elif operation == \"multiply\":\n return num1 * num2\n elif operation == \"divide\":\n return num1 / num2\n\ndemo = gr.Interface(\n calculator,\n [\n \"number\",\n gr.Radio([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n \"number\"\n ],\n \"number\",\n live=True,\n)\ndemo.launch()\n\n
Note there is no submit button, because the interface resubmits automatically on change.
\n\nSome components have a \"streaming\" mode, such as Audio
component in microphone mode, or the Image
component in webcam mode. Streaming means data is sent continuously to the backend and the Interface
function is continuously being rerun.
The difference between gr.Audio(source='microphone')
and gr.Audio(source='microphone', streaming=True)
, when both are used in gr.Interface(live=True)
, is that the first Component
will automatically submit data and run the Interface
function when the user stops recording, whereas the second Component
will continuously send data and run the Interface
function during recording.
Here is example code of streaming images from the webcam.
\n\nimport gradio as gr\nimport numpy as np\n\ndef flip(im):\n return np.flipud(im)\n\ndemo = gr.Interface(\n flip, \n gr.Image(source=\"webcam\", streaming=True), \n \"image\",\n live=True\n)\ndemo.launch()\n\n
This guide covers what more you can do with Examples: Loading examples from a directory, providing partial examples, and caching. If Examples is new to you, check out the intro in the Key Features guide.
\n\nAs covered in the Key Features guide, adding examples to an Interface is as easy as providing a list of lists to the examples
\nkeyword argument. \nEach sublist is a data sample, where each element corresponds to an input of the prediction function.\nThe inputs must be ordered in the same order as the prediction function expects them.
If your interface only has one input component, then you can provide your examples as a regular list instead of a list of lists.
\n\nYou can also specify a path to a directory containing your examples. If your Interface takes only a single file-type input, e.g. an image classifier, you can simply pass a directory filepath to the examples=
argument, and the Interface
will load the images in the directory as examples. \nIn the case of multiple inputs, this directory must\ncontain a log.csv file with the example values.\nIn the context of the calculator demo, we can set examples='/demo/calculator/examples'
and in that directory we include the following log.csv
file:
num,operation,num2\n5,\"add\",3\n4,\"divide\",2\n5,\"multiply\",3\n
This can be helpful when browsing flagged data. Simply point to the flagged directory and the Interface
will load the examples from the flagged data.
Sometimes your app has many input components, but you would only like to provide examples for a subset of them. In order to exclude some inputs from the examples, pass None
for all data samples corresponding to those particular components.
You may wish to provide some cached examples of your model for users to quickly try out, in case your model takes a while to run normally.\nIf cache_examples=True
, the Interface
will run all of your examples through your app and save the outputs when you call the launch()
method. This data will be saved in a directory called gradio_cached_examples
.
Whenever a user clicks on an example, the output will automatically be populated in the app now, using data from this cached directory instead of actually running the function. This is useful so users can quickly try out your model without adding any load!
\n\nKeep in mind once the cache is generated, it will not be updated in future launches. If the examples or function logic change, delete the cache folder to clear the cache and rebuild it with another launch()
.
There's more to cover on the Interface class. This guide covers all the advanced features: Using Interpretation, custom styling, loading from the Hugging Face Hub, and using Parallel and Series.
\n\nMost models are black boxes such that the internal logic of the function is hidden from the end user. To encourage transparency, we've made it very easy to add interpretation to your model by simply setting the interpretation
keyword in the Interface
class to default
. This allows your users to understand what parts of the input are responsible for the output. Take a look at the simple interface below which shows an image classifier that also includes interpretation:
import requests\nimport tensorflow as tf\n\nimport gradio as gr\n\ninception_net = tf.keras.applications.MobileNetV2() # load the model\n\n# Download human-readable labels for ImageNet.\nresponse = requests.get(\"https://git.io/JJkYN\")\nlabels = response.text.split(\"\\n\")\n\n\ndef classify_image(inp):\n inp = inp.reshape((-1, 224, 224, 3))\n inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)\n prediction = inception_net.predict(inp).flatten()\n return {labels[i]: float(prediction[i]) for i in range(1000)}\n\n\nimage = gr.Image(shape=(224, 224))\nlabel = gr.Label(num_top_classes=3)\n\ndemo = gr.Interface(\n fn=classify_image, inputs=image, outputs=label, interpretation=\"default\"\n)\n\ndemo.launch()\n\n
In addition to default
, Gradio also includes Shapley-based interpretation, which provides more accurate interpretations, albeit usually with a slower runtime. To use this, simply set the interpretation
parameter to \"shap\"
(note: also make sure the python package shap
is installed). Optionally, you can modify the num_shap
parameter, which controls the tradeoff between accuracy and runtime (increasing this value generally increases accuracy). Here is an example:
gr.Interface(fn=classify_image,\n inputs=image, \n outputs=label, \n interpretation=\"shap\", \n num_shap=5).launch()\n
This will work for any function, even if internally, the model is a complex neural network or some other black box. If you use Gradio's default
or shap
interpretation, the output component must be a Label
. All common input components are supported. Here is an example with text input.
import gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=\"default\",\n)\n\ndemo.launch()\n\n
So what is happening under the hood? With these interpretation methods, Gradio runs the prediction multiple times with modified versions of the input. Based on the results, you'll see that the interface automatically highlights the parts of the text (or image, etc.) that contributed increased the likelihood of the class as red. The intensity of color corresponds to the importance of that part of the input. The parts that decrease the class confidence are highlighted blue.
\n\nYou can also write your own interpretation function. The demo below adds custom interpretation to the previous demo. This function will take the same inputs as the main wrapped function. The output of this interpretation function will be used to highlight the input of each input component - therefore the function must return a list where the number of elements corresponds to the number of input components. To see the format for interpretation for each input component, check the Docs.
\n\nimport re\n\nimport gradio as gr\n\nmale_words, female_words = [\"he\", \"his\", \"him\"], [\"she\", \"hers\", \"her\"]\n\n\ndef gender_of_sentence(sentence):\n male_count = len([word for word in sentence.split() if word.lower() in male_words])\n female_count = len(\n [word for word in sentence.split() if word.lower() in female_words]\n )\n total = max(male_count + female_count, 1)\n return {\"male\": male_count / total, \"female\": female_count / total}\n\n\n# Number of arguments to interpretation function must\n# match number of inputs to prediction function\ndef interpret_gender(sentence):\n result = gender_of_sentence(sentence)\n is_male = result[\"male\"] > result[\"female\"]\n interpretation = []\n for word in re.split(\"( )\", sentence):\n score = 0\n token = word.lower()\n if (is_male and token in male_words) or (not is_male and token in female_words):\n score = 1\n elif (is_male and token in female_words) or (\n not is_male and token in male_words\n ):\n score = -1\n interpretation.append((word, score))\n # Output must be a list of lists containing the same number of elements as inputs\n # Each element corresponds to the interpretation scores for the given input\n return [interpretation]\n\n\ndemo = gr.Interface(\n fn=gender_of_sentence,\n inputs=gr.Textbox(value=\"She went to his house to get her keys.\"),\n outputs=\"label\",\n interpretation=interpret_gender,\n)\n\ndemo.launch()\n\n
Learn more about Interpretation in the docs.
\n\nIf you'd like to have more fine-grained control over any aspect of your demo, you can also write your own css or pass in a filepath to a css file, with the css
parameter of the Interface
class.
gr.Interface(..., css=\"body {background-color: red}\")\n
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with \"file=\"
, for example:
gr.Interface(..., css=\"body {background-image: url('file=clouds.jpg')}\")\n
Warning: Custom CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using custom CSS sparingly and instead using Themes whenever possible.
\n\nGradio integrates nicely with the Hugging Face Hub, allowing you to load models and Spaces with just one line of code. To use this, simply use the load()
method in the Interface
class. So:
\"model/\"
or \"huggingface/\"
followed by the model name, like these examples:gr.Interface.load(\"huggingface/gpt2\").launch();\n
gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\", \n inputs=gr.Textbox(lines=5, label=\"Input Text\") # customizes the input component\n).launch()\n
\"spaces/\"
followed by the model name:gr.Interface.load(\"spaces/eugenesiow/remove-bg\", \n inputs=\"webcam\", \n title=\"Remove your webcam background!\").launch()\n
One of the great things about loading Hugging Face models or spaces using Gradio is that you can then immediately use the resulting Interface
object just like function in your Python code (this works for every type of model/space: text, images, audio, video, and even multimodal models):
io = gr.Interface.load(\"models/EleutherAI/gpt-neo-2.7B\")\nio(\"It was the best of times\") # outputs model completion\n
Gradio also lets you mix interfaces very easily using the gradio.Parallel
and gradio.Series
classes. Parallel
lets you put two similar models (if they have the same input type) in parallel to compare model predictions:
generator1 = gr.Interface.load(\"huggingface/gpt2\")\ngenerator2 = gr.Interface.load(\"huggingface/EleutherAI/gpt-neo-2.7B\")\ngenerator3 = gr.Interface.load(\"huggingface/EleutherAI/gpt-j-6B\")\n\ngr.Parallel(generator1, generator2, generator3).launch()\n
Series
lets you put models and spaces in series, piping the output of one model into the input of the next model.
generator = gr.Interface.load(\"huggingface/gpt2\")\ntranslator = gr.Interface.load(\"huggingface/t5-small\")\n\ngr.Series(generator, translator).launch() \n# this demo generates text, then translates it to German, and outputs the final result.\n
And of course, you can also mix Parallel
and Series
together whenever that makes sense!
Learn more about Parallel and Series in the docs.
\n", "tags": [], "spaces": [], "url": "/guides/advanced-interface-features/", "contributor": null}, {"name": "four-kinds-of-interfaces", "category": "building-interfaces", "pretty_category": "Building Interfaces", "guide_index": 5, "absolute_index": 7, "pretty_name": "Four Kinds Of Interfaces", "content": "# The 4 Kinds of Gradio Interfaces\n\nSo far, we've always assumed that in order to build an Gradio demo, you need both inputs and outputs. But this isn't always the case for machine learning demos: for example, *unconditional image generation models* don't take any input but produce an image as the output.\n\nIt turns out that the `gradio.Interface` class can actually handle 4 different kinds of demos:\n\n1. **Standard demos**: which have both separate inputs and outputs (e.g. an image classifier or speech-to-text model)\n2. **Output-only demos**: which don't take any input but produce on output (e.g. an unconditional image generation model)\n3. **Input-only demos**: which don't produce any output but do take in some sort of input (e.g. a demo that saves images that you upload to a persistent external database)\n4. **Unified demos**: which have both input and output components, but the input and output components *are the same*. This means that the output produced overrides the input (e.g. a text autocomplete model)\n\nDepending on the kind of demo, the user interface (UI) looks slightly different:\n\n![](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/gradio-guides/interfaces4.png)\n\n\nLet's see how to build each kind of demo using the `Interface` class, along with examples:\n\n\n## Standard demos\n\nTo create a demo that has both the input and the output components, you simply need to set the values of the `inputs` and `outputs` parameter in `Interface()`. Here's an example demo of a simple image filter:\n\n```python\nimport numpy as np\nimport gradio as gr\n\ndef sepia(input_img):\n sepia_filter = np.array([\n [0.393, 0.769, 0.189], \n [0.349, 0.686, 0.168], \n [0.272, 0.534, 0.131]\n ])\n sepia_img = input_img.dot(sepia_filter.T)\n sepia_img /= sepia_img.max()\n return sepia_img\n\ndemo = gr.Interface(sepia, gr.Image(shape=(200, 200)), \"image\")\ndemo.launch()\n\n```\nSo far, we've always assumed that in order to build an Gradio demo, you need both inputs and outputs. But this isn't always the case for machine learning demos: for example, unconditional image generation models don't take any input but produce an image as the output.
\n\nIt turns out that the gradio.Interface
class can actually handle 4 different kinds of demos:
Depending on the kind of demo, the user interface (UI) looks slightly different:
\n\n\n\nLet's see how to build each kind of demo using the Interface
class, along with examples:
To create a demo that has both the input and the output components, you simply need to set the values of the inputs
and outputs
parameter in Interface()
. Here's an example demo of a simple image filter:
import numpy as np\nimport gradio as gr\n\ndef sepia(input_img):\n sepia_filter = np.array([\n [0.393, 0.769, 0.189], \n [0.349, 0.686, 0.168], \n [0.272, 0.534, 0.131]\n ])\n sepia_img = input_img.dot(sepia_filter.T)\n sepia_img /= sepia_img.max()\n return sepia_img\n\ndemo = gr.Interface(sepia, gr.Image(shape=(200, 200)), \"image\")\ndemo.launch()\n\n
What about demos that only contain outputs? In order to build such a demo, you simply set the value of the inputs
parameter in Interface()
to None
. Here's an example demo of a mock image generation model:
import time\n\nimport gradio as gr\n\n\ndef fake_gan():\n time.sleep(1)\n images = [\n \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80\",\n \"https://images.unsplash.com/photo-1554151228-14d9def656e4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=386&q=80\",\n \"https://images.unsplash.com/photo-1542909168-82c3e7fdca5c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MXx8aHVtYW4lMjBmYWNlfGVufDB8fDB8fA%3D%3D&w=1000&q=80\",\n ]\n return images\n\n\ndemo = gr.Interface(\n fn=fake_gan,\n inputs=None,\n outputs=gr.Gallery(label=\"Generated Images\").style(grid=[2]),\n title=\"FD-GAN\",\n description=\"This is a fake demo of a GAN. In reality, the images are randomly chosen from Unsplash.\",\n)\n\ndemo.launch()\n\n
Similarly, to create a demo that only contains inputs, set the value of outputs
parameter in Interface()
to be None
. Here's an example demo that saves any uploaded image to disk:
import random\nimport string\nimport gradio as gr \n\ndef save_image_random_name(image):\n random_string = ''.join(random.choices(string.ascii_letters, k=20)) + '.png'\n image.save(random_string)\n print(f\"Saved image to {random_string}!\")\n\ndemo = gr.Interface(\n fn=save_image_random_name, \n inputs=gr.Image(type=\"pil\"), \n outputs=None,\n)\ndemo.launch()\n
A demo that has a single component as both the input and the output. It can simply be created by setting the values of the inputs
and outputs
parameter as the same component. Here's an example demo of a text generation model:
import gradio as gr\nfrom transformers import pipeline\n\ngenerator = pipeline('text-generation', model = 'gpt2')\n\ndef generate_text(text_prompt):\n response = generator(text_prompt, max_length = 30, num_return_sequences=5)\n return response[0]['generated_text']\n\ntextbox = gr.Textbox()\n\ndemo = gr.Interface(generate_text, textbox, textbox)\n\ndemo.launch()\n\n
We took a quick look at Blocks in the Quickstart. Let's dive deeper. This guide will cover the how Blocks are structured, event listeners and their types, running events continuously, updating configurations, and using dictionaries vs lists.
\n\nTake a look at the demo below.
\n\nimport gradio as gr\n\ndef greet(name):\n return \"Hello \" + name + \"!\"\n\nwith gr.Blocks() as demo:\n name = gr.Textbox(label=\"Name\")\n output = gr.Textbox(label=\"Output Box\")\n greet_btn = gr.Button(\"Greet\")\n greet_btn.click(fn=greet, inputs=name, outputs=output, api_name=\"greet\")\n\n\ndemo.launch()\n
with gr.Blocks() as demo:
clause. The Blocks app code will be contained within this clause.Interface
. However, instead of being passed to some constructor, Components are automatically added to the Blocks as they are created within the with
clause.click()
event listener. Event listeners define the data flow within the app. In the example above, the listener ties the two Textboxes together. The Textbox name
acts as the input and Textbox output
acts as the output to the greet
method. This dataflow is triggered when the Button greet_btn
is clicked. Like an Interface, an event listener can take multiple inputs or outputs.In the example above, you'll notice that you are able to edit Textbox name
, but not Textbox output
. This is because any Component that acts as an input to an event listener is made interactive. However, since Textbox output
acts only as an output, Gradio determines that it should not be made interactive. You can override the default behavior and directly configure the interactivity of a Component with the boolean interactive
keyword argument.
output = gr.Textbox(label=\"Output\", interactive=True)\n
Note: What happens if a Gradio component is neither an input nor an output? If a component is constructed with a default value, then it is presumed to be displaying content and is rendered non-interactive. Otherwise, it is rendered interactive. Again, this behavior can be overridden by specifying a value for the interactive
argument.
Take a look at the demo below:
\n\nimport gradio as gr\n\ndef welcome(name):\n return f\"Welcome to Gradio, {name}!\"\n\nwith gr.Blocks() as demo:\n gr.Markdown(\n \"\"\"\n # Hello World!\n Start typing below to see the output.\n \"\"\")\n inp = gr.Textbox(placeholder=\"What is your name?\")\n out = gr.Textbox()\n inp.change(welcome, inp, out)\n\ndemo.launch()\n
Instead of being triggered by a click, the welcome
function is triggered by typing in the Textbox inp
. This is due to the change()
event listener. Different Components support different event listeners. For example, the Video
Component supports a play()
event listener, triggered when a user presses play. See the Docs for the event listeners for each Component.
A Blocks app is not limited to a single data flow the way Interfaces are. Take a look at the demo below:
\n\nimport gradio as gr\n\ndef increase(num):\n return num + 1\n\nwith gr.Blocks() as demo:\n a = gr.Number(label=\"a\")\n b = gr.Number(label=\"b\")\n btoa = gr.Button(\"a > b\")\n atob = gr.Button(\"b > a\")\n atob.click(increase, a, b)\n btoa.click(increase, b, a)\n\ndemo.launch()\n
Note that num1
can act as input to num2
, and also vice-versa! As your apps get more complex, you will have many data flows connecting various Components.
Here's an example of a \"multi-step\" demo, where the output of one model (a speech-to-text model) gets fed into the next model (a sentiment classifier).
\n\nfrom transformers import pipeline\n\nimport gradio as gr\n\nasr = pipeline(\"automatic-speech-recognition\", \"facebook/wav2vec2-base-960h\")\nclassifier = pipeline(\"text-classification\")\n\n\ndef speech_to_text(speech):\n text = asr(speech)[\"text\"]\n return text\n\n\ndef text_to_sentiment(text):\n return classifier(text)[0][\"label\"]\n\n\ndemo = gr.Blocks()\n\nwith demo:\n audio_file = gr.Audio(type=\"filepath\")\n text = gr.Textbox()\n label = gr.Label()\n\n b1 = gr.Button(\"Recognize Speech\")\n b2 = gr.Button(\"Classify Sentiment\")\n\n b1.click(speech_to_text, inputs=audio_file, outputs=text)\n b2.click(text_to_sentiment, inputs=text, outputs=label)\n\ndemo.launch()\n\n
The event listeners you've seen so far have a single input component. If you'd like to have multiple input components pass data to the function, you have two options on how the function can accept input component values:
\n\nLet's see an example of each:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n a = gr.Number(label=\"a\")\n b = gr.Number(label=\"b\")\n with gr.Row():\n add_btn = gr.Button(\"Add\")\n sub_btn = gr.Button(\"Subtract\")\n c = gr.Number(label=\"sum\")\n\n def add(num1, num2):\n return num1 + num2\n add_btn.click(add, inputs=[a, b], outputs=c)\n\n def sub(data):\n return data[a] - data[b]\n sub_btn.click(sub, inputs={a, b}, outputs=c)\n\n\ndemo.launch()\n
Both add()
and sub()
take a
and b
as inputs. However, the syntax is different between these listeners.
add_btn
listener, we pass the inputs as a list. The function add()
takes each of these inputs as arguments. The value of a
maps to the argument num1
, and the value of b
maps to the argument num2
.sub_btn
listener, we pass the inputs as a set (note the curly brackets!). The function sub()
takes a single dictionary argument data
, where the keys are the input components, and the values are the values of those components.It is a matter of preference which syntax you prefer! For functions with many input components, option 2 may be easier to manage.
\n\nSimilarly, you may return values for multiple output components either as:
\n\nLet's first see an example of (1), where we set the values of two output components by returning two values:
\n\nwith gr.Blocks() as demo:\n food_box = gr.Number(value=10, label=\"Food Count\")\n status_box = gr.Textbox()\n def eat(food):\n if food > 0:\n return food - 1, \"full\"\n else:\n return 0, \"hungry\"\n gr.Button(\"EAT\").click(\n fn=eat, \n inputs=food_box,\n outputs=[food_box, status_box]\n )\n
Above, each return statement returns two values corresponding to food_box
and status_box
, respectively.
Instead of returning a list of values corresponding to each output component in order, you can also return a dictionary, with the key corresponding to the output component and the value as the new value. This also allows you to skip updating some output components.
\n\nwith gr.Blocks() as demo:\n food_box = gr.Number(value=10, label=\"Food Count\")\n status_box = gr.Textbox()\n def eat(food):\n if food > 0:\n return {food_box: food - 1, status_box: \"full\"}\n else:\n return {status_box: \"hungry\"}\n gr.Button(\"EAT\").click(\n fn=eat, \n inputs=food_box,\n outputs=[food_box, status_box]\n )\n
Notice how when there is no food, we only update the status_box
element. We skipped updating the food_box
component.
Dictionary returns are helpful when an event listener affects many components on return, or conditionally affects outputs and not others.
\n\nKeep in mind that with dictionary returns, we still need to specify the possible outputs in the event listener.
\n\nThe return value of an event listener function is usually the updated value of the corresponding output Component. Sometimes we want to update the configuration of the Component as well, such as the visibility. In this case, we return a gr.update()
object instead of just the update Component value.
import gradio as gr\n\ndef change_textbox(choice):\n if choice == \"short\":\n return gr.update(lines=2, visible=True, value=\"Short story: \")\n elif choice == \"long\":\n return gr.update(lines=8, visible=True, value=\"Long story...\")\n else:\n return gr.update(visible=False)\n\nwith gr.Blocks() as demo:\n radio = gr.Radio(\n [\"short\", \"long\", \"none\"], label=\"Essay Length to Write?\"\n )\n text = gr.Textbox(lines=2, interactive=True)\n radio.change(fn=change_textbox, inputs=radio, outputs=text)\n\ndemo.launch()\n
See how we can configure the Textbox itself through the gr.update()
method. The value=
argument can still be used to update the value along with Component configuration.
You can also run events consecutively by using the then
method of an event listener. This will run an event after the previous event has finished running. This is useful for running events that update components in multiple steps.
For example, in the chatbot example below, we first update the chatbot with the user message immediately, and then update the chatbot with the computer response after a simulated delay.
\n\nimport gradio as gr\nimport random\nimport time\n\nwith gr.Blocks() as demo:\n chatbot = gr.Chatbot()\n msg = gr.Textbox()\n clear = gr.Button(\"Clear\")\n\n def user(user_message, history):\n return \"\", history + [[user_message, None]]\n\n def bot(history):\n bot_message = random.choice([\"How are you?\", \"I love you\", \"I'm very hungry\"])\n time.sleep(2)\n history[-1][1] = bot_message\n return history\n\n msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(\n bot, chatbot, chatbot\n )\n clear.click(lambda: None, None, chatbot, queue=False)\n\ndemo.queue()\ndemo.launch()\n\n
The .then()
method of an event listener executes the subsequent event regardless of whether the previous event raised any errors. If you'd like to only run subsequent events if the previous event executed successfully, use the .success()
method, which takes the same arguments as .then()
.
You can run events on a fixed schedule using the every
parameter of the event listener. This will run the event\nevery
number of seconds while the client connection is open. If the connection is closed, the event will stop running after the following iteration.\nNote that this does not take into account the runtime of the event itself. So a function\nwith a 1 second runtime running with every=5
, would actually run every 6 seconds.
Here is an example of a sine curve that updates every second!
\n\nimport math\nimport gradio as gr\nimport plotly.express as px\nimport numpy as np\n\n\nplot_end = 2 * math.pi\n\n\ndef get_plot(period=1):\n global plot_end\n x = np.arange(plot_end - 2 * math.pi, plot_end, 0.02)\n y = np.sin(2*math.pi*period * x)\n fig = px.line(x=x, y=y)\n plot_end += 2 * math.pi\n if plot_end > 1000:\n plot_end = 2 * math.pi\n return fig\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n gr.Markdown(\"Change the value of the slider to automatically update the plot\")\n period = gr.Slider(label=\"Period of plot\", value=1, minimum=0, maximum=10, step=1)\n plot = gr.Plot(label=\"Plot (updates every half second)\")\n\n dep = demo.load(get_plot, None, plot, every=1)\n period.change(get_plot, period, plot, every=1, cancels=[dep])\n\n\nif __name__ == \"__main__\":\n demo.queue().launch()\n\n
You can gather specific data about an event by adding the associated event data class as a type hint to an argument in the event listener function.
\n\nFor example, event data for .select()
can be type hinted by a gradio.SelectData
argument. This event is triggered when a user selects some part of the triggering component, and the event data includes information about what the user specifically selected. If a user selected a specific word in a Textbox
, a specific image in a Gallery
, or a specific cell in a DataFrame
, the event data argument would contain information about the specific selection.
In the 2 player tic-tac-toe demo below, a user can select a cell in the DataFrame
to make a move. The event data argument contains information about the specific cell that was selected. We can first check to see if the cell is empty, and then update the cell with the user's move.
import gradio as gr\n\nwith gr.Blocks() as demo:\n turn = gr.Textbox(\"X\", interactive=False, label=\"Turn\")\n board = gr.Dataframe(value=[[\"\", \"\", \"\"]] * 3, interactive=False, type=\"array\")\n\n def place(board, turn, evt: gr.SelectData):\n if evt.value:\n return board, turn\n board[evt.index[0]][evt.index[1]] = turn\n turn = \"O\" if turn == \"X\" else \"X\"\n return board, turn\n\n board.select(place, [board, turn], [board, turn])\n\ndemo.launch()\n
By default, Components in Blocks are arranged vertically. Let's take a look at how we can rearrange Components. Under the hood, this layout structure uses the flexbox model of web development.
\n\nElements within a with gr.Row
clause will all be displayed horizontally. For example, to display two Buttons side by side:
with gr.Blocks() as demo:\n with gr.Row():\n btn1 = gr.Button(\"Button 1\")\n btn2 = gr.Button(\"Button 2\")\n
To make every element in a Row have the same height, use the equal_height
argument of the style
method.
with gr.Blocks() as demo:\n with gr.Row().style(equal_height=True):\n textbox = gr.Textbox()\n btn2 = gr.Button(\"Button 2\")\n
The widths of elements in a Row can be controlled via a combination of scale
and min_width
arguments that are present in every Component.
scale
is an integer that defines how an element will take up space in a Row. If scale is set to 0
, and element will not expand to take up space. If scale is set to 1
or greater, the element well expand. Multiple elements in a row will expand proportional to their scale. Below, btn1
will expand twice as much as btn2
, while btn0
will not expand at all:with gr.Blocks() as demo:\n with gr.Row():\n btn0 = gr.Button(\"Button 0\", scale=0)\n btn1 = gr.Button(\"Button 1\", scale=1)\n btn2 = gr.Button(\"Button 2\", scale=2)\n
min_width
will set the minimum width the element will take. The Row will wrap if there isn't sufficient space to satisfy all min_width
values.Learn more about Rows in the docs.
\n\nComponents within a Column will be placed vertically atop each other. Since the vertical layout is the default layout for Blocks apps anyway, to be useful, Columns are usually nested within Rows. For example:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Row():\n text1 = gr.Textbox(label=\"t1\")\n slider2 = gr.Textbox(label=\"s2\")\n drop3 = gr.Dropdown([\"a\", \"b\", \"c\"], label=\"d3\")\n with gr.Row():\n with gr.Column(scale=1, min_width=600):\n text1 = gr.Textbox(label=\"prompt 1\")\n text2 = gr.Textbox(label=\"prompt 2\")\n inbtw = gr.Button(\"Between\")\n text4 = gr.Textbox(label=\"prompt 1\")\n text5 = gr.Textbox(label=\"prompt 2\")\n with gr.Column(scale=2, min_width=600):\n img1 = gr.Image(\"images/cheetah.jpg\")\n btn = gr.Button(\"Go\").style(full_width=True)\n\ndemo.launch()\n
See how the first column has two Textboxes arranged vertically. The second column has an Image and Button arranged vertically. Notice how the relative widths of the two columns is set by the scale
parameter. The column with twice the scale
value takes up twice the width.
Learn more about Columns in the docs.
\n\nYou can also create Tabs using the with gr.Tab('tab_name'):
clause. Any component created inside of a with gr.Tab('tab_name'):
context appears in that tab. Consecutive Tab clauses are grouped together so that a single tab can be selected at one time, and only the components within that Tab's context are shown.
For example:
\n\nimport numpy as np\nimport gradio as gr\n\n\ndef flip_text(x):\n return x[::-1]\n\n\ndef flip_image(x):\n return np.fliplr(x)\n\n\nwith gr.Blocks() as demo:\n gr.Markdown(\"Flip text or image files using this demo.\")\n with gr.Tab(\"Flip Text\"):\n text_input = gr.Textbox()\n text_output = gr.Textbox()\n text_button = gr.Button(\"Flip\")\n with gr.Tab(\"Flip Image\"):\n with gr.Row():\n image_input = gr.Image()\n image_output = gr.Image()\n image_button = gr.Button(\"Flip\")\n\n with gr.Accordion(\"Open for More!\"):\n gr.Markdown(\"Look at me...\")\n\n text_button.click(flip_text, inputs=text_input, outputs=text_output)\n image_button.click(flip_image, inputs=image_input, outputs=image_output)\n\ndemo.launch()\n\n
Also note the gr.Accordion('label')
in this example. The Accordion is a layout that can be toggled open or closed. Like Tabs
, it is a layout element that can selectively hide or show content. Any components that are defined inside of a with gr.Accordion('label'):
will be hidden or shown when the accordion's toggle icon is clicked.
Learn more about Tabs and Accordions in the docs.
\n\nBoth Components and Layout elements have a visible
argument that can set initially and also updated using gr.update()
. Setting gr.update(visible=...)
on a Column can be used to show or hide a set of Components.
import gradio as gr\n\nwith gr.Blocks() as demo:\n error_box = gr.Textbox(label=\"Error\", visible=False)\n\n name_box = gr.Textbox(label=\"Name\")\n age_box = gr.Number(label=\"Age\", minimum=0, maximum=100)\n symptoms_box = gr.CheckboxGroup([\"Cough\", \"Fever\", \"Runny Nose\"])\n submit_btn = gr.Button(\"Submit\")\n\n with gr.Column(visible=False) as output_col:\n diagnosis_box = gr.Textbox(label=\"Diagnosis\")\n patient_summary_box = gr.Textbox(label=\"Patient Summary\")\n\n def submit(name, age, symptoms):\n if len(name) == 0:\n return {error_box: gr.update(value=\"Enter name\", visible=True)}\n return {\n output_col: gr.update(visible=True),\n diagnosis_box: \"covid\" if \"Cough\" in symptoms else \"flu\",\n patient_summary_box: f\"{name}, {age} y/o\",\n }\n\n submit_btn.click(\n submit,\n [name_box, age_box, symptoms_box],\n [error_box, diagnosis_box, patient_summary_box, output_col],\n )\n\ndemo.launch()\n\n
By adjusting the visibility of components in a dynamic way, it is possible to create\ndemos with Gradio that support a variable numbers of outputs. Here's a very simple example\nwhere the number of output textboxes is controlled by an input slider:
\n\nimport gradio as gr\n\nmax_textboxes = 10\n\ndef variable_outputs(k):\n k = int(k)\n return [gr.Textbox.update(visible=True)]*k + [gr.Textbox.update(visible=False)]*(max_textboxes-k)\n\nwith gr.Blocks() as demo:\n s = gr.Slider(1, max_textboxes, value=max_textboxes, step=1, label=\"How many textboxes to show:\")\n textboxes = []\n for i in range(max_textboxes):\n t = gr.Textbox(f\"Textbox {i}\")\n textboxes.append(t)\n\n s.change(variable_outputs, s, textboxes)\n\nif __name__ == \"__main__\":\n demo.launch()\n\n
In some cases, you might want to define components before you actually render them in your UI. For instance, you might want to show an examples section using gr.Examples
above the corresponding gr.Textbox
input. Since gr.Examples
requires as a parameter the input component object, you will need to first define the input component, but then render it later, after you have defined the gr.Examples
object.
The solution to this is to define the gr.Textbox
outside of the gr.Blocks()
scope and use the component's .render()
method wherever you'd like it placed in the UI.
Here's a full code example:
\n\ninput_textbox = gr.Textbox()\n\nwith gr.Blocks() as demo:\n gr.Examples([\"hello\", \"bonjour\", \"merhaba\"], input_textbox)\n input_textbox.render()\n
We covered State in Interfaces, this guide takes a look at state in Blocks, which works mostly the same.
\n\nGlobal state in Blocks works the same as in Interface. Any variable created outside a function call is a reference shared between all users.
\n\nGradio supports session state, where data persists across multiple submits within a page session, in Blocks apps as well. To reiterate, session data is not shared between different users of your model. To store data in a session state, you need to do three things:
\n\ngr.State()
object. If there is a default value to this stateful object, pass that into the constructor.State
object as an input and output.Let's take a look at a game of hangman.
\n\nimport gradio as gr\n\nsecret_word = \"gradio\"\n\nwith gr.Blocks() as demo: \n used_letters_var = gr.State([])\n with gr.Row() as row:\n with gr.Column():\n input_letter = gr.Textbox(label=\"Enter letter\")\n btn = gr.Button(\"Guess Letter\")\n with gr.Column():\n hangman = gr.Textbox(\n label=\"Hangman\",\n value=\"_\"*len(secret_word)\n )\n used_letters_box = gr.Textbox(label=\"Used Letters\")\n\n def guess_letter(letter, used_letters):\n used_letters.append(letter)\n answer = \"\".join([\n (letter if letter in used_letters else \"_\")\n for letter in secret_word\n ])\n return {\n used_letters_var: used_letters,\n used_letters_box: \", \".join(used_letters),\n hangman: answer\n }\n btn.click(\n guess_letter, \n [input_letter, used_letters_var],\n [used_letters_var, used_letters_box, hangman]\n )\ndemo.launch()\n
Let's see how we do each of the 3 steps listed above in this game:
\n\nused_letters_var
. In the constructor of State
, we set the initial value of this to []
, an empty list. btn.click()
, we have a reference to used_letters_var
in both the inputs and outputs.guess_letter
, we pass the value of this State
to used_letters
, and then return an updated value of this State
in the return statement.With more complex apps, you will likely have many State variables storing session state in a single Blocks app.
\n\nLearn more about State
in the docs.
This guide covers how to style Blocks with more flexibility, as well as adding Javascript code to event listeners.
\n\nWarning: The use of query selectors in custom JS and CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using query selectors sparingly.
\n\nGradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the theme=
kwarg to the Blocks
constructor. For example:
with gr.Blocks(theme=gr.themes.Glass()):\n ...\n
Gradio comes with a set of prebuilt themes which you can load from gr.themes.*
. You can extend these themes or create your own themes from scratch - see the Theming guide for more details.
For additional styling ability, you can pass any CSS to your app using the css=
kwarg.
The base class for the Gradio app is gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Blocks(css=\".gradio-container {background-color: red}\") as demo:\n ...\n
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with \"file=\"
, for example:
with gr.Blocks(css=\".gradio-container {background: url('file=clouds.jpg')}\") as demo:\n ...\n
You can also pass the filepath to a CSS file to the css
argument.
elem_id
and elem_classes
ArgumentsYou can elem_id
to add an HTML element id
to any component, and elem_classes
to add a class or list of classes. This will allow you to select elements more easily with CSS. This approach is also more likely to be stable across Gradio versions as built-in class names or ids may change (however, as mentioned in the warning above, we cannot guarantee complete compatibility between Gradio versions if you use custom CSS as the DOM elements may themselves change).
css = \"\"\"\n#warning {background-color: #FFCCCB} \n.feedback textarea {font-size: 24px !important}\n\"\"\"\n\nwith gr.Blocks(css=css) as demo:\n box1 = gr.Textbox(value=\"Good Job\", elem_classes=\"feedback\")\n box2 = gr.Textbox(value=\"Failure\", elem_id=\"warning\", elem_classes=\"feedback\")\n
The CSS #warning
ruleset will only target the second Textbox, while the .feedback
ruleset will target both. Note that when targeting classes, you might need to put the !important
selector to override the default Gradio styles.
Event listeners have a _js
argument that can take a Javascript function as a string and treat it just like a Python event listener function. You can pass both a Javascript function and a Python function (in which case the Javascript function is run first) or only Javascript (and set the Python fn
to None
). Take a look at the code below:
import gradio as gr\n\nblocks = gr.Blocks()\n\nwith blocks as demo:\n subject = gr.Textbox(placeholder=\"subject\")\n verb = gr.Radio([\"ate\", \"loved\", \"hated\"])\n object = gr.Textbox(placeholder=\"object\")\n\n with gr.Row():\n btn = gr.Button(\"Create sentence.\")\n reverse_btn = gr.Button(\"Reverse sentence.\")\n foo_bar_btn = gr.Button(\"Append foo\")\n reverse_then_to_the_server_btn = gr.Button(\n \"Reverse sentence and send to server.\"\n )\n\n def sentence_maker(w1, w2, w3):\n return f\"{w1} {w2} {w3}\"\n\n output1 = gr.Textbox(label=\"output 1\")\n output2 = gr.Textbox(label=\"verb\")\n output3 = gr.Textbox(label=\"verb reversed\")\n output4 = gr.Textbox(label=\"front end process and then send to backend\")\n\n btn.click(sentence_maker, [subject, verb, object], output1)\n reverse_btn.click(\n None, [subject, verb, object], output2, _js=\"(s, v, o) => o + ' ' + v + ' ' + s\"\n )\n verb.change(lambda x: x, verb, output3, _js=\"(x) => [...x].reverse().join('')\")\n foo_bar_btn.click(None, [], subject, _js=\"(x) => x + ' foo'\")\n\n reverse_then_to_the_server_btn.click(\n sentence_maker,\n [subject, verb, object],\n output4,\n _js=\"(s, v, o) => [s, v, o].map(x => [...x].reverse().join(''))\",\n )\n\ndemo.launch()\n\n
Prerequisite: This Guide builds on the Blocks Introduction. Make sure to read that guide first.
\n\nDid you know that apart from being a full-stack machine learning demo, a Gradio Blocks app is also a regular-old python function!?
\n\nThis means that if you have a gradio Blocks (or Interface) app called demo
, you can use demo
like you would any python function.
So doing something like output = demo(\"Hello\", \"friend\")
will run the first event defined in demo
on the inputs \"Hello\" and \"friend\" and store it\nin the variable output
.
If I put you to sleep \ud83e\udd71, please bear with me! By using apps like functions, you can seamlessly compose Gradio apps.\nThe following section will show how.
\n\nLet's say we have the following demo that translates english text to german text.
\n\nimport gradio as gr\n\nfrom transformers import pipeline\n\npipe = pipeline(\"translation\", model=\"t5-base\")\n\n\ndef translate(text):\n return pipe(text)[0][\"translation_text\"]\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n english = gr.Textbox(label=\"English text\")\n translate_btn = gr.Button(value=\"Translate\")\n with gr.Column():\n german = gr.Textbox(label=\"German Text\")\n\n translate_btn.click(translate, inputs=english, outputs=german, api_name=\"translate-to-german\")\n examples = gr.Examples(examples=[\"I went to the supermarket yesterday.\", \"Helen is a good swimmer.\"],\n inputs=[english])\n\ndemo.launch()\n
I already went ahead and hosted it in Hugging Face spaces at gradio/english_translator.
\n\nYou can see the demo below as well:
\n\nNow, let's say you have an app that generates english text, but you wanted to additionally generate german text.
\n\nYou could either:
\n\nCopy the source code of my english-to-german translation and paste it in your app.
Load my english-to-german translation in your app and treat it like a normal python function.
Option 1 technically always works, but it often introduces unwanted complexity.
\n\nOption 2 lets you borrow the functionality you want without tightly coupling our apps.
\n\nAll you have to do is call the Blocks.load
class method in your source file.\nAfter that, you can use my translation app like a regular python function!
The following code snippet and demo shows how to use Blocks.load
.
Note that the variable english_translator
is my english to german app, but its used in generate_text
like a regular function.
import gradio as gr\n\nfrom transformers import pipeline\n\nenglish_translator = gr.Blocks.load(name=\"spaces/gradio/english_translator\")\nenglish_generator = pipeline(\"text-generation\", model=\"distilgpt2\")\n\n\ndef generate_text(text):\n english_text = english_generator(text)[0][\"generated_text\"]\n german_text = english_translator(english_text)\n return english_text, german_text\n\n\nwith gr.Blocks() as demo:\n with gr.Row():\n with gr.Column():\n seed = gr.Text(label=\"Input Phrase\")\n with gr.Column():\n english = gr.Text(label=\"Generated English Text\")\n german = gr.Text(label=\"Generated German Text\")\n btn = gr.Button(\"Generate\")\n btn.click(generate_text, inputs=[seed], outputs=[english, german])\n gr.Examples([\"My name is Clara and I am\"], inputs=[seed])\n\ndemo.launch()\n
If the app you are loading defines more than one function, you can specify which function to use\nwith the fn_index
and api_name
parameters.
In the code for our english to german demo, you'll see the following line:
\n\ntranslate_btn.click(translate, inputs=english, outputs=german, api_name=\"translate-to-german\")\n
The api_name
gives this function a unique name in our app. You can use this name to tell gradio which\nfunction in the upstream space you want to use:
english_generator(text, api_name=\"translate-to-german\")[0][\"generated_text\"]\n
You can also use the fn_index
parameter.\nImagine my app also defined an english to spanish translation function.\nIn order to use it in our text generation app, we would use the following code:
english_generator(text, fn_index=1)[0][\"generated_text\"]\n
Functions in gradio spaces are zero-indexed, so since the spanish translator would be the second function in my space,\nyou would use index 1.
\n\nWe showed how treating a Blocks app like a regular python helps you compose functionality across different apps.\nAny Blocks app can be treated like a function, but a powerful pattern is to load
an app hosted on \nHugging Face Spaces prior to treating it like a function in your own app.\nYou can also load models hosted on the Hugging Face Model Hub - see the Using Hugging Face Integrations guide for an example.
Chatbots are a popular application of large language models. Using gradio
, you can easily build a demo of your chatbot model and share that with your users, or try it yourself using an intuitive chatbot UI.
This tutorial uses gr.ChatInterface()
, which is a high-level abstraction that allows you to create your chatbot UI fast, often with a single line of code. The chatbot interface that we create will look something like this:
We'll start with a couple of simple examples, and then show how to use gr.ChatInterface()
with real language models from several popular APIs and libraries, including langchain
, openai
, and Hugging Face.
Prerequisites: please make sure you are using the latest version version of Gradio:
\n\n$ pip install --upgrade gradio\n
When working with gr.ChatInterface()
, the first thing you should do is define your chat function. Your chat function should take two arguments: message
and then history
(the arguments can be named anything, but must be in this order).
message
: a str
representing the user's input.history
: a list
of list
representing the conversations up until that point. Each inner list consists of two str
representing a pair: [user input, bot response]
. Your function should return a single string response, which is the bot's response to the particular user input message
. Your function can take into account the history
of messages, as well as the current message.
Let's take a look at a few examples.
\n\nLet's write a chat function that responds Yes
or No
randomly.
Here's our chat function:
\n\nimport random\n\ndef random_response(message, history):\n return random.choice([\"Yes\", \"No\"])\n
Now, we can plug this into gr.ChatInterface()
and call the .launch()
method to create the web interface:
import gradio as gr\n\ngr.ChatInterface(random_response).launch()\n
That's it! Here's our running demo, try it out:
\n\nOf course, the previous example was very simplistic, it didn't even take user input or the previous history into account! Here's another simple example showing how to incorporate a user's input as well as the history.
\n\nimport random\nimport gradio as gr\n\ndef alternatingly_agree(message, history):\n if len(history) % 2 == 0:\n return f\"Yes, I do think that '{message}'\"\n else:\n return \"I don't think so\"\n\ngr.ChatInterface(alternatingly_agree).launch()\n
If in your chat function, you use yield
to generate a sequence of responses, you'll end up with a streaming chatbot. It's that simple!
import time\nimport gradio as gr\n\ndef slow_echo(message, history):\n for i in range(len(message)):\n time.sleep(0.3)\n yield \"You typed: \" + message[: i+1]\n\ngr.ChatInterface(slow_echo).queue().launch()\n
Notice that we've enabled queuing, which is required to use generator functions. While the response is streaming, the \"Submit\" button turns into a \"Stop\" button that can be used to stop the generator function. You can customize the appearance and behavior of the \"Stop\" button using the stop_btn
parameter.
If you're familiar with Gradio's Interface
class, the gr.ChatInterface
includes many of the same arguments that you can use to customize the look and feel of your Chatbot. For example, you can:
title
and description
arguments.theme
and css
arguments respectively.examples
and even enable cache_examples
, which make it easier for users to try it out .submit_btn
, retry_btn
, undo_btn
, clear_btn
.If you want to customize the gr.Chatbot
or gr.Textbox
that compose the ChatInterface
, then you can pass in your own chatbot or textbox as well. Here's an example of how we can use these parameters:
import gradio as gr\n\ndef yes_man(message, history):\n if message.endswith(\"?\"):\n return \"Yes\"\n else:\n return \"Ask me anything!\"\n\ngr.ChatInterface(\n yes_man,\n chatbot=gr.Chatbot(height=300),\n textbox=gr.Textbox(placeholder=\"Ask me a yes or no question\", container=False, scale=7),\n title=\"Yes Man\",\n description=\"Ask Yes Man any question\",\n theme=\"soft\",\n examples=[\"Hello\", \"Am I cool?\", \"Are tomatoes vegetables?\"],\n cache_examples=True,\n retry_btn=None,\n undo_btn=\"Delete Previous\",\n clear_btn=\"Clear\",\n).launch()\n
You may want to add additional parameters to your chatbot and expose them to your users through the Chatbot UI. For example, suppose you want to add a textbox for a system prompt, or a slider that sets the number of tokens in the chatbot's response. The ChatInterface
class supports an additional_inputs
parameter which can be used to add additional input components.
The additional_inputs
parameters accepts a component or a list of components. You can pass the component instances directly, or use their string shortcuts (e.g. \"textbox\"
instead of gr.Textbox()
). If you pass in component instances, and they have not already been rendered, then the components will appear underneath the chatbot (and any examples) within a gr.Accordion()
. You can set the label of this accordion using the additional_inputs_accordion_name
parameter.
Here's a complete example:
\n\nimport gradio as gr\nimport time\n\ndef echo(message, history, system_prompt, tokens):\n response = f\"System prompt: {system_prompt}\\n Message: {message}.\"\n for i in range(min(len(response), int(tokens))):\n time.sleep(0.05)\n yield response[: i+1]\n\ndemo = gr.ChatInterface(echo, \n additional_inputs=[\n gr.Textbox(\"You are helpful AI.\", label=\"System Prompt\"), \n gr.Slider(10, 100)\n ]\n )\n\nif __name__ == \"__main__\":\n demo.queue().launch()\n
If the components you pass into the additional_inputs
have already been rendered in a parent gr.Blocks()
, then they will not be re-rendered in the accordion. This provides flexibility in deciding where to lay out the input components. In the example below, we position the gr.Textbox()
on top of the Chatbot UI, while keeping the slider underneath.
import gradio as gr\nimport time\n\ndef echo(message, history, system_prompt, tokens):\n response = f\"System prompt: {system_prompt}\\n Message: {message}.\"\n for i in range(min(len(response), int(tokens))):\n time.sleep(0.05)\n yield response[: i+1]\n\nwith gr.Blocks() as demo:\n system_prompt = gr.Textbox(\"You are helpful AI.\", label=\"System Prompt\")\n slider = gr.Slider(10, 100, render=False)\n\n gr.ChatInterface(\n echo, additional_inputs=[system_prompt, slider]\n )\n\ndemo.queue().launch()\n
If you need to create something even more custom, then its best to construct the chatbot UI using the low-level gr.Blocks()
API. We have a dedicated guide for that here.
Once you've built your Gradio chatbot and are hosting it on Hugging Face Spaces or somewhere else, then you can query it with a simple API at the /chat
endpoint. The endpoint just expects the user's message (and potentially additional inputs if you have set any using the additional_inputs
parameter), and will return the response, internally keeping track of the messages sent so far.
To use the endpoint, you should use either the Gradio Python Client or the Gradio JS client.
\n\nlangchain
exampleNow, let's actually use the gr.ChatInterface
with some real large language models. We'll start by using langchain
on top of openai
to build a general-purpose streaming chatbot application in 19 lines of code. You'll need to have an OpenAI key for this example (keep reading for the free, open-source equivalent!)
from langchain.chat_models import ChatOpenAI\nfrom langchain.schema import AIMessage, HumanMessage\nimport openai\nimport gradio as gr\n\nos.envrion[\"OPENAI_API_KEY\"] = \"sk-...\" # Replace with your key\n\nllm = ChatOpenAI(temperature=1.0, model='gpt-3.5-turbo-0613')\n\ndef predict(message, history):\n history_langchain_format = []\n for human, ai in history:\n history_langchain_format.append(HumanMessage(content=human))\n history_langchain_format.append(AIMessage(content=ai))\n history_langchain_format.append(HumanMessage(content=message))\n gpt_response = llm(history_langchain_format)\n return gpt_response.content\n\ngr.ChatInterface(predict).launch() \n
openai
Of course, we could also use the openai
library directy. Here a similar example, but this time with streaming results as well:
import openai\nimport gradio as gr\n\nopenai.api_key = \"sk-...\" # Replace with your key\n\ndef predict(message, history):\n history_openai_format = []\n for human, assistant in history:\n history_openai_format.append({\"role\": \"user\", \"content\": human })\n history_openai_format.append({\"role\": \"assistant\", \"content\":assistant})\n history_openai_format.append({\"role\": \"user\", \"content\": message})\n\n response = openai.ChatCompletion.create(\n model='gpt-3.5-turbo',\n messages= history_openai_format, \n temperature=1.0,\n stream=True\n )\n\n partial_message = \"\"\n for chunk in response:\n if len(chunk['choices'][0]['delta']) != 0:\n partial_message = partial_message + chunk['choices'][0]['delta']['content']\n yield partial_message \n\ngr.ChatInterface(predict).queue().launch() \n
Of course, in many cases you want to run a chatbot locally. Here's the equivalent example using Together's RedePajama model, from Hugging Face (this requires you to have a GPU with CUDA).
\n\nimport gradio as gr\nimport torch\nfrom transformers import AutoModelForCausalLM, AutoTokenizer, StoppingCriteria, StoppingCriteriaList, TextIteratorStreamer\nfrom threading import Thread\n\ntokenizer = AutoTokenizer.from_pretrained(\"togethercomputer/RedPajama-INCITE-Chat-3B-v1\")\nmodel = AutoModelForCausalLM.from_pretrained(\"togethercomputer/RedPajama-INCITE-Chat-3B-v1\", torch_dtype=torch.float16)\nmodel = model.to('cuda:0')\n\nclass StopOnTokens(StoppingCriteria):\n def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool:\n stop_ids = [29, 0]\n for stop_id in stop_ids:\n if input_ids[0][-1] == stop_id:\n return True\n return False\n\ndef predict(message, history): \n\n history_transformer_format = history + [[message, \"\"]]\n stop = StopOnTokens()\n\n messages = \"\".join([\"\".join([\"\\n:\"+item[0], \"\\n:\"+item[1]]) #curr_system_message + \n for item in history_transformer_format])\n\n model_inputs = tokenizer([messages], return_tensors=\"pt\").to(\"cuda\")\n streamer = TextIteratorStreamer(tokenizer, timeout=10., skip_prompt=True, skip_special_tokens=True)\n generate_kwargs = dict(\n model_inputs,\n streamer=streamer,\n max_new_tokens=1024,\n do_sample=True,\n top_p=0.95,\n top_k=1000,\n temperature=1.0,\n num_beams=1,\n stopping_criteria=StoppingCriteriaList([stop])\n )\n t = Thread(target=model.generate, kwargs=generate_kwargs)\n t.start()\n\n partial_message = \"\"\n for new_token in streamer:\n if new_token != '<':\n partial_message += new_token\n yield partial_message \n\n\ngr.ChatInterface(predict).queue().launch()\n
With those examples, you should be all set to create your own Gradio Chatbot demos soon! For building even more custom Chatbot applications, check out a dedicated guide using the low-level gr.Blocks()
API.
Important Note: if you are getting started, we recommend using the gr.ChatInterface
to create chatbots -- its a high-level abstraction that makes it possible to create beautiful chatbot applications fast, often with a single line of code. Read more about it here.
This tutorial will show how to make chatbot UIs from scratch with Gradio's low-level Blocks API. This will give you full control over your Chatbot UI. You'll start by first creating a a simple chatbot to display text, a second one to stream text responses, and finally a chatbot that can handle media files as well. The chatbot interface that we create will look something like this:
\n\nPrerequisite: We'll be using the gradio.Blocks
class to build our Chatbot demo.\nYou can read the Guide to Blocks first if you are not already familiar with it. Also please make sure you are using the latest version version of Gradio: pip install --upgrade gradio
.
Let's start with recreating the simple demo above. As you may have noticed, our bot simply randomly responds \"How are you?\", \"I love you\", or \"I'm very hungry\" to any input. Here's the code to create this with Gradio:
\n\nimport gradio as gr\nimport random\nimport time\n\nwith gr.Blocks() as demo:\n chatbot = gr.Chatbot()\n msg = gr.Textbox()\n clear = gr.ClearButton([msg, chatbot])\n\n def respond(message, chat_history):\n bot_message = random.choice([\"How are you?\", \"I love you\", \"I'm very hungry\"])\n chat_history.append((message, bot_message))\n time.sleep(2)\n return \"\", chat_history\n\n msg.submit(respond, [msg, chatbot], [msg, chatbot])\n\ndemo.launch()\n\n
There are three Gradio components here:
\n\nChatbot
, whose value stores the entire history of the conversation, as a list of response pairs between the user and bot.Textbox
where the user can type their message, and then hit enter/submit to trigger the chatbot responseClearButton
button to clear the Textbox and entire Chatbot historyWe have a single function, respond()
, which takes in the entire history of the chatbot, appends a random message, waits 1 second, and then returns the updated chat history. The respond()
function also clears the textbox when it returns.
Of course, in practice, you would replace respond()
with your own more complex function, which might call a pretrained model or an API, to generate a response.
There are several ways we can improve the user experience of the chatbot above. First, we can stream responses so the user doesn't have to wait as long for a message to be generated. Second, we can have the user message appear immediately in the chat history, while the chatbot's response is being generated. Here's the code to achieve that:
\n\nimport gradio as gr\nimport random\nimport time\n\nwith gr.Blocks() as demo:\n chatbot = gr.Chatbot()\n msg = gr.Textbox()\n clear = gr.Button(\"Clear\")\n\n def user(user_message, history):\n return \"\", history + [[user_message, None]]\n\n def bot(history):\n bot_message = random.choice([\"How are you?\", \"I love you\", \"I'm very hungry\"])\n history[-1][1] = \"\"\n for character in bot_message:\n history[-1][1] += character\n time.sleep(0.05)\n yield history\n\n msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(\n bot, chatbot, chatbot\n )\n clear.click(lambda: None, None, chatbot, queue=False)\n\ndemo.queue()\ndemo.launch()\n\n
You'll notice that when a user submits their message, we now chain three event events with .then()
:
The first method user()
updates the chatbot with the user message and clears the input field. This method also makes the input field non interactive so that the user can't send another message while the chatbot is responding. Because we want this to happen instantly, we set queue=False
, which would skip any queue had it been enabled. The chatbot's history is appended with (user_message, None)
, the None
signifying that the bot has not responded.
The second method, bot()
updates the chatbot history with the bot's response. Instead of creating a new message, we just replace the previously-created None
message with the bot's response. Finally, we construct the message character by character and yield
the intermediate outputs as they are being constructed. Gradio automatically turns any function with the yield
keyword into a streaming output interface.
The third method makes the input field interactive again so that users can send another message to the bot.
Of course, in practice, you would replace bot()
with your own more complex function, which might call a pretrained model or an API, to generate a response.
Finally, we enable queuing by running demo.queue()
, which is required for streaming intermediate outputs. You can try the improved chatbot by scrolling to the demo at the top of this page.
The gr.Chatbot
component supports a subset of markdown including bold, italics, and code. For example, we could write a function that responds to a user's message, with a bold That's cool!, like this:
def bot(history):\n response = \"**That's cool!**\"\n history[-1][1] = response\n return history\n
In addition, it can handle media files, such as images, audio, and video. To pass in a media file, we must pass in the file as a tuple of two strings, like this: (filepath, alt_text)
. The alt_text
is optional, so you can also just pass in a tuple with a single element (filepath,)
, like this:
def add_file(history, file):\n history = history + [((file.name,), None)]\n return history\n
Putting this together, we can create a multimodal chatbot with a textbox for a user to submit text and an file upload button to submit images / audio / video files. The rest of the code looks pretty much the same as before:
\n\nimport gradio as gr\nimport random\nimport time\n\n# Chatbot demo with multimodal input (text, markdown, LaTeX, code blocks, image, audio, & video). Plus shows support for streaming text.\n\ndef add_text(history, text):\n history = history + [(text, None)]\n return history, gr.update(value=\"\", interactive=False)\n\n\ndef add_file(history, file):\n history = history + [((file.name,), None)]\n return history\n\n\ndef bot(history):\n response = \"**That's cool!**\"\n history[-1][1] = \"\"\n for character in response:\n history[-1][1] += character\n time.sleep(0.05)\n yield history\n\n\nwith gr.Blocks() as demo:\n chatbot = gr.Chatbot([], elem_id=\"chatbot\").style(height=750)\n\n with gr.Row():\n with gr.Column(scale=0.85):\n txt = gr.Textbox(\n show_label=False,\n placeholder=\"Enter text and press enter, or upload an image\",\n ).style(container=False)\n with gr.Column(scale=0.15, min_width=0):\n btn = gr.UploadButton(\"\ud83d\udcc1\", file_types=[\"image\", \"video\", \"audio\"])\n\n txt_msg = txt.submit(add_text, [chatbot, txt], [chatbot, txt], queue=False).then(\n bot, chatbot, chatbot\n )\n txt_msg.then(lambda: gr.update(interactive=True), None, [txt], queue=False)\n file_msg = btn.upload(add_file, [chatbot, btn], [chatbot], queue=False).then(\n bot, chatbot, chatbot\n )\n\ndemo.queue()\ndemo.launch()\n\n
And you're done! That's all the code you need to build an interface for your chatbot model. Finally, we'll end our Guide with some links to Chatbots that are running on Spaces so that you can get an idea of what else is possible:
\n\nWe're excited to announce that Gradio can now automatically create a discord bot from a deployed app! \ud83e\udd16
\n\nDiscord is a popular communication platform that allows users to chat and interact with each other in real-time. By turning your Gradio app into a Discord bot, you can bring cutting edge AI to your discord server and give your community a whole new way to interact.
\n\nWith gradio_client
version 0.3.0
, any gradio ChatInterface
app on the internet can automatically be deployed as a discord bot via the deploy_discord
method of the Client
class.
Technically, any gradio app that exposes an api route that takes in a single string and outputs a single string can be deployed to discord. In this guide, we will focus on gr.ChatInterface
as those apps naturally lend themselves to discord's chat functionality.
Make sure you have the latest gradio_client
and gradio
versions installed.
pip install gradio_client>=0.3.0 gradio>=3.38.0\n
Also, make sure you have a Hugging Face account and a write access token.
\n\n\u26a0\ufe0f Tip \u26a0\ufe0f: Make sure you login to the Hugging Face Hub by running huggingface-cli login
. This will let you skip passing your token in all subsequent commands in this guide.
Let's build a very simple Chatbot using ChatInterface
that simply repeats the user message. Write the following code into an app.py
import gradio as gr\n\ndef slow_echo(message, history):\n return message\n\ndemo = gr.ChatInterface(slow_echo).queue().launch()\n
In order to create a discord bot for our app, it must be accessible over the internet. In this guide, we will use the gradio deploy
command to deploy our chatbot to Hugging Face spaces from the command line. Run the following command.
gradio deploy --title echo-chatbot --app-file app.py\n
This command will ask you some questions, e.g. requested hardware, requirements, but the default values will suffice for this guide.\nNote the URL of the space that was created. Mine is https://huggingface.co/spaces/freddyaboulton/echo-chatbot
\n\nTurning our space into a discord bot is also a one-liner thanks to the gradio deploy-discord
. Run the following command:
gradio deploy-discord --src freddyaboulton/echo-chatbot\n
\u2757\ufe0f Advanced \u2757\ufe0f: If you already have a discord bot token you can pass it to the deploy-discord
command. Don't worry, if you don't have one yet!
gradio deploy-discord --src freddyaboulton/echo-chatbot --discord-bot-token \n
Note the URL that gets printed out to the console. Mine is https://huggingface.co/spaces/freddyaboulton/echo-chatbot-gradio-discord-bot
\n\nIf you didn't have a discord bot token for step 3, go to the URL that got printed in the console and follow the instructions there.\nOnce you obtain a token, run the command again but this time pass in the token:
\n\ngradio deploy-discord --src freddyaboulton/echo-chatbot --discord-bot-token \n
Visit the space of your discord bot. You should see \"Add this bot to your server by clicking this link:\" followed by a URL. Go to that URL and add the bot to your server!
\n\nBy default the bot can be called by starting a message with /chat
, e.g. /chat <your prompt here>
.
\u26a0\ufe0f Tip \u26a0\ufe0f: If either of the deployed spaces goes to sleep, the bot will stop working. By default, spaces go to sleep after 48 hours of inactivity. You can upgrade the hardware of your space to prevent it from going to sleep. See this guide for more information.
\n\n\n\ngradio_client.Client
ClassYou can also create a discord bot from a deployed gradio app with python.
\n\nimport gradio_client as grc\ngrc.Client(\"freddyaboulton/echo-chatbot\").deploy_discord()\n
We have created an organization on Hugging Face called gradio-discord-bots containing several template spaces that explain how to deploy state of the art LLMs powered by gradio as discord bots.
\n\nThe easiest way to get started is by deploying Meta's Llama 2 LLM with 70 billion parameter. Simply go to this space and follow the instructions.
\n\nThe deployment can be done in one line! \ud83e\udd2f
\n\nimport gradio_client as grc\ngrc.Client(\"ysharma/Explore_llamav2_with_TGI\").deploy_discord(to_id=\"llama2-70b-discord-bot\")\n
In addion to Meta's 70 billion Llama 2 model, we have prepared template spaces for the following LLMs and deployment options:
\n\nTo deploy any of these models to discord, simply follow the instructions in the linked space for that model.
\n\nAs mentioned above, you don't need a gr.ChatInterface
if you want to deploy your gradio app to discord. All that's needed is an api route that takes in a single string and outputs a single string.
The following code will deploy a space that translates english to german as a discord bot.
\n\nimport gradio_client as grc\nclient = grc.Client(\"freddyaboulton/english-to-german\")\nclient.deploy_discord(api_names=['german'])\n
That's it for this guide! We're really excited about this feature. Tag @Gradio on twitter and show us how your discord community interacts with your discord bots.
\n", "tags": ["NLP", "TEXT", "CHAT"], "spaces": [], "url": "/guides/creating-a-discord-bot-from-a-gradio-app/", "contributor": null}]}, {"category": "Integrating Other Frameworks", "guides": [{"name": "using-hugging-face-integrations", "category": "integrating-other-frameworks", "pretty_category": "Integrating Other Frameworks", "guide_index": 1, "absolute_index": 16, "pretty_name": "Using Hugging Face Integrations", "content": "# Using Hugging Face Integrations\n\n\n\n\n\n\n## Introduction\n\nThe Hugging Face Hub is a central platform that has over 190,000 [models](https://huggingface.co/models), 32,000 [datasets](https://huggingface.co/datasets) and 40,000 [demos](https://huggingface.co/spaces), also known as Spaces. Although Hugging Face is famous for its \ud83e\udd17 transformers and diffusers libraries, the Hub also supports dozens of ML libraries, such as PyTorch, TensorFlow, spaCy, and many others across a variety of domains, from computer vision to reinforcement learning.\n\nGradio has multiple features that make it extremely easy to leverage existing models and Spaces on the Hub. This guide walks through these features.\n\n## Using regular inference with `pipeline`\n\nFirst, let's build a simple interface that translates text from English to Spanish. Between the over a thousand models shared by the University of Helsinki, there is an [existing model](https://huggingface.co/Helsinki-NLP/opus-mt-en-es), `opus-mt-en-es`, that does precisely this!\n\nThe \ud83e\udd17 transformers library has a very easy-to-use abstraction, [`pipeline()`](https://huggingface.co/docs/transformers/v4.16.2/en/main_classes/pipelines#transformers.pipeline) that handles most of the complex code to offer a simple API for common tasks. By specifying the task and an (optional) model, you can use an existing model with few lines:\n\n```python\nimport gradio as gr\n\nfrom transformers import pipeline\n\npipe = pipeline(\"translation\", model=\"Helsinki-NLP/opus-mt-en-es\")\n\ndef predict(text):\n return pipe(text)[0][\"translation_text\"]\n \ndemo = gr.Interface(\n fn=predict, \n inputs='text',\n outputs='text',\n)\n\ndemo.launch()\n```\n\nBut `gradio` actually makes it even easier to convert a `pipeline` to a demo, simply by using the `gradio.Interface.from_pipeline` methods, which skips the need to specify the input and output components:\n\n```python\nfrom transformers import pipeline\nimport gradio as gr\n\npipe = pipeline(\"translation\", model=\"Helsinki-NLP/opus-mt-en-es\")\n\ndemo = gr.Interface.from_pipeline(pipe)\ndemo.launch()\n```\n\nThe previous code produces the following interface, which you can try right here in your browser: \n\n\nThe Hugging Face Hub is a central platform that has over 190,000 models, 32,000 datasets and 40,000 demos, also known as Spaces. Although Hugging Face is famous for its \ud83e\udd17 transformers and diffusers libraries, the Hub also supports dozens of ML libraries, such as PyTorch, TensorFlow, spaCy, and many others across a variety of domains, from computer vision to reinforcement learning.
\n\nGradio has multiple features that make it extremely easy to leverage existing models and Spaces on the Hub. This guide walks through these features.
\n\npipeline
First, let's build a simple interface that translates text from English to Spanish. Between the over a thousand models shared by the University of Helsinki, there is an existing model, opus-mt-en-es
, that does precisely this!
The \ud83e\udd17 transformers library has a very easy-to-use abstraction, pipeline()
that handles most of the complex code to offer a simple API for common tasks. By specifying the task and an (optional) model, you can use an existing model with few lines:
import gradio as gr\n\nfrom transformers import pipeline\n\npipe = pipeline(\"translation\", model=\"Helsinki-NLP/opus-mt-en-es\")\n\ndef predict(text):\n return pipe(text)[0][\"translation_text\"]\n\ndemo = gr.Interface(\n fn=predict, \n inputs='text',\n outputs='text',\n)\n\ndemo.launch()\n
But gradio
actually makes it even easier to convert a pipeline
to a demo, simply by using the gradio.Interface.from_pipeline
methods, which skips the need to specify the input and output components:
from transformers import pipeline\nimport gradio as gr\n\npipe = pipeline(\"translation\", model=\"Helsinki-NLP/opus-mt-en-es\")\n\ndemo = gr.Interface.from_pipeline(pipe)\ndemo.launch()\n
The previous code produces the following interface, which you can try right here in your browser:
\n\nHugging Face has a free service called the Inference API, which allows you to send HTTP requests to models in the Hub. For transformers or diffusers-based models, the API can be 2 to 10 times faster than running the inference yourself. The API is free (rate limited), and you can switch to dedicated Inference Endpoints when you want to use it in production.
\n\nLet's try the same demo as above but using the Inference API instead of loading the model yourself. Given a Hugging Face model supported in the Inference API, Gradio can automatically infer the expected input and output and make the underlying server calls, so you don't have to worry about defining the prediction function. Here is what the code would look like!
\n\nimport gradio as gr\n\ndemo = gr.load(\"Helsinki-NLP/opus-mt-en-es\", src=\"models\")\n\ndemo.launch()\n
Notice that we just put specify the model name and state that the src
should be models
(Hugging Face's Model Hub). There is no need to install any dependencies (except gradio
) since you are not loading the model on your computer.
You might notice that the first inference takes about 20 seconds. This happens since the Inference API is loading the model in the server. You get some benefits afterward:
\n\nHugging Face Spaces allows anyone to host their Gradio demos freely, and uploading your Gradio demos take a couple of minutes. You can head to hf.co/new-space, select the Gradio SDK, create an app.py
file, and voila! You have a demo you can share with anyone else. To learn more, read this guide how to host on Hugging Face Spaces using the website.
Alternatively, you can create a Space programmatically, making use of the huggingface_hub client library library. Here's an example:
\n\nfrom huggingface_hub import (\n create_repo,\n get_full_repo_name,\n upload_file,\n)\ncreate_repo(name=target_space_name, token=hf_token, repo_type=\"space\", space_sdk=\"gradio\")\nrepo_name = get_full_repo_name(model_id=target_space_name, token=hf_token)\nfile_url = upload_file(\n path_or_fileobj=\"file.txt\",\n path_in_repo=\"app.py\",\n repo_id=repo_name,\n repo_type=\"space\",\n token=hf_token,\n)\n
Here, create_repo
creates a gradio repo with the target name under a specific account using that account's Write Token. repo_name
gets the full repo name of the related repo. Finally upload_file
uploads a file inside the repo with the name app.py
.
Throughout this guide, you've seen many embedded Gradio demos. You can also do this on own website! The first step is to create a Hugging Face Space with the demo you want to showcase. Then, follow the steps here to embed the Space on your website.
\n\nYou can also use and remix existing Gradio demos on Hugging Face Spaces. For example, you could take two existing Gradio demos and put them as separate tabs and create a new demo. You can run this new demo locally, or upload it to Spaces, allowing endless possibilities to remix and create new demos!
\n\nHere's an example that does exactly that:
\n\nimport gradio as gr\n\nwith gr.Blocks() as demo:\n with gr.Tab(\"Translate to Spanish\"):\n gr.load(\"gradio/helsinki_translation_en_es\", src=\"spaces\")\n with gr.Tab(\"Translate to French\"):\n gr.load(\"abidlabs/en2fr\", src=\"spaces\")\n\ndemo.launch()\n
Notice that we use gr.load()
, the same method we used to load models using the Inference API. However, here we specify that the src
is spaces
(Hugging Face Spaces).
That's it! Let's recap the various ways Gradio and Hugging Face work together:
\n\ntransformers
pipeline into a Gradio demo using from_pipeline()
gr.load()
gr.load()
.\ud83e\udd17
\n", "tags": ["HUB", "SPACES", "EMBED"], "spaces": ["https://huggingface.co/spaces/gradio/helsinki_translation_en_es"], "url": "/guides/using-hugging-face-integrations/", "contributor": "Omar Sanseviero \ud83e\udd99 "}, {"name": "Gradio-and-Comet", "category": "integrating-other-frameworks", "pretty_category": "Integrating Other Frameworks", "guide_index": null, "absolute_index": 17, "pretty_name": "Gradio And Comet", "content": "# Using Gradio and Comet\n\n\n\n\n## Introduction\n\nIn this guide we will demonstrate some of the ways you can use Gradio with Comet. We will cover the basics of using Comet with Gradio and show you some of the ways that you can leverage Gradio's advanced features such as [Embedding with iFrames](https://www.gradio.app/guides/sharing-your-app/#embedding-with-iframes) and [State](https://www.gradio.app/docs/#state) to build some amazing model evaluation workflows.\n\nHere is a list of the topics covered in this guide.\n\n1. Logging Gradio UI's to your Comet Experiments\n2. Embedding Gradio Applications directly into your Comet Projects\n3. Embedding Hugging Face Spaces directly into your Comet Projects\n4. Logging Model Inferences from your Gradio Application to Comet\n\n\n## What is Comet?\n\n[Comet](https://www.comet.com?utm_source=gradio&utm_medium=referral&utm_campaign=gradio-integration&utm_content=gradio-docs) is an MLOps Platform that is designed to help Data Scientists and Teams build better models faster! Comet provides tooling to Track, Explain, Manage, and Monitor your models in a single place! It works with Jupyter Notebooks and Scripts and most importantly it's 100% free!\n\n\n## Setup\n\nFirst, install the dependencies needed to run these examples\n\n```shell\npip install comet_ml torch torchvision transformers gradio shap requests Pillow\n```\n\nNext, you will need to [sign up for a Comet Account](https://www.comet.com/signup?utm_source=gradio&utm_medium=referral&utm_campaign=gradio-integration&utm_content=gradio-docs). Once you have your account set up, [grab your API Key](https://www.comet.com/docs/v2/guides/getting-started/quickstart/#get-an-api-key?utm_source=gradio&utm_medium=referral&utm_campaign=gradio-integration&utm_content=gradio-docs) and configure your Comet credentials\n\nIf you're running these examples as a script, you can either export your credentials as environment variables\n\n```shell\nexport COMET_API_KEY=\"