diff --git a/.changeset/beige-badgers-argue.md b/.changeset/beige-badgers-argue.md deleted file mode 100644 index 5a3f6af31a2d5..0000000000000 --- a/.changeset/beige-badgers-argue.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@gradio/accordion": minor -"gradio": minor ---- - -feat:Adds `.expand()` and `.collapse()` events to `gr.Accordion` diff --git a/.changeset/chatty-kings-visit.md b/.changeset/chatty-kings-visit.md deleted file mode 100644 index 6f0411c39f120..0000000000000 --- a/.changeset/chatty-kings-visit.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@gradio/lite": patch -"@gradio/wasm": patch -"gradio": patch ---- - -feat:Lite worker refactoring diff --git a/.changeset/empty-monkeys-do.md b/.changeset/empty-monkeys-do.md deleted file mode 100644 index 64beae5a23e12..0000000000000 --- a/.changeset/empty-monkeys-do.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@gradio/atoms": minor -"@gradio/file": minor -"@gradio/upload": minor -"gradio": minor ---- - -feat:Allow uploading more files in gr.File diff --git a/.changeset/fluffy-cats-drop.md b/.changeset/fluffy-cats-drop.md deleted file mode 100644 index e0a0154ce01f7..0000000000000 --- a/.changeset/fluffy-cats-drop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"gradio": patch ---- - -fix:Fixes for ChatInterface Examples when additional inputs are provided diff --git a/.changeset/giant-baboons-lick.md b/.changeset/giant-baboons-lick.md deleted file mode 100644 index 2a5b1f2581806..0000000000000 --- a/.changeset/giant-baboons-lick.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@gradio/file": minor -"gradio": minor ---- - -feat:Add `.download()` event to `gr.File` diff --git a/.changeset/late-candies-boil.md b/.changeset/late-candies-boil.md deleted file mode 100644 index 698b3e6e58e69..0000000000000 --- a/.changeset/late-candies-boil.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@gradio/core": minor -"gradio": minor ---- - -feat:Fix frontend errors on ApiDocs and RecordingSnippet diff --git a/.changeset/long-wolves-serve.md b/.changeset/long-wolves-serve.md deleted file mode 100644 index 62bebcb235d52..0000000000000 --- a/.changeset/long-wolves-serve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"gradio": patch ---- - -fix:Fix Loading SSR'd apps via gr.load diff --git a/.changeset/moody-crews-pull.md b/.changeset/moody-crews-pull.md deleted file mode 100644 index 5843ed1b40b72..0000000000000 --- a/.changeset/moody-crews-pull.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@gradio/nativeplot": minor -"gradio": minor ---- - -feat:Allow plot tooltip to show extra columns diff --git a/.changeset/silver-planes-guess.md b/.changeset/silver-planes-guess.md deleted file mode 100644 index c9f2278e9a063..0000000000000 --- a/.changeset/silver-planes-guess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"gradio": patch ---- - -fix:Fixes LoginButton for SSR diff --git a/.changeset/slick-crabs-move.md b/.changeset/slick-crabs-move.md deleted file mode 100644 index b34708ff7a7c8..0000000000000 --- a/.changeset/slick-crabs-move.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@gradio/gallery": patch -"gradio": patch ---- - -fix:Ensure gallery share button is positioned correctly diff --git a/.changeset/slow-baboons-report.md b/.changeset/slow-baboons-report.md deleted file mode 100644 index 087e7a0ce9e5b..0000000000000 --- a/.changeset/slow-baboons-report.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@gradio/chatbot": patch -"gradio": patch ---- - -fix:Make sure the Tool accordion is closed if it is not the last message diff --git a/.changeset/tidy-bikes-allow.md b/.changeset/tidy-bikes-allow.md deleted file mode 100644 index b3674cd96aa66..0000000000000 --- a/.changeset/tidy-bikes-allow.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@gradio/textbox": patch -"gradio": patch ---- - -fix:Fix: Resolve copy button visibility issue in Textbox component diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 593027bdc8b84..93ad225b39461 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,9 +10,9 @@ Before your create a PR, please check to see if there is [an existing issue](htt Not adhering to this guideline will result in the PR being closed. -## Tests +## Testing and Formatting Your Code -1. PRs will only be merged if tests pass on CI. To run the tests locally, please set up [your Gradio environment locally](https://github.com/gradio-app/gradio/blob/main/CONTRIBUTING.md) and run the tests: `bash scripts/run_all_tests.sh` +1. PRs will only be merged if tests pass on CI. We recommend at least running the backend tests locally, please set up [your Gradio environment locally](https://github.com/gradio-app/gradio/blob/main/CONTRIBUTING.md) and run the backed tests: `bash scripts/run_backend_tests.sh` -2. You may need to run the linters: `bash scripts/format_backend.sh` and `bash scripts/format_frontend.sh` +2. Please run these bash scripts to automatically format your code: `bash scripts/format_backend.sh`, and (if you made any changes to non-Python files) `bash scripts/format_frontend.sh` diff --git a/CHANGELOG.md b/CHANGELOG.md index b9ab81d080a28..a2581b23fcc4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,54 @@ # gradio +## 5.6.0 + +### Features + +- [#9906](https://github.com/gradio-app/gradio/pull/9906) [`eafe22c`](https://github.com/gradio-app/gradio/commit/eafe22cd9404d536b03d3fa80003acea78599d49) - Clearer error message in CheckboxGroup's preprocess function. Thanks @muhammadyaseen! +- [#9930](https://github.com/gradio-app/gradio/pull/9930) [`eae345e`](https://github.com/gradio-app/gradio/commit/eae345e5fde39aea220b57c6a954cd7d72ff32d5) - Allow settings custom headers in js client. Thanks @elgiano! +- [#9921](https://github.com/gradio-app/gradio/pull/9921) [`a70ba5e`](https://github.com/gradio-app/gradio/commit/a70ba5e0f01f0c376da0d4e45634bc967f5299f4) - Clearer error message in Dropdown's and Radio's preprocess function. Thanks @muhammadyaseen! +- [#9933](https://github.com/gradio-app/gradio/pull/9933) [`66375ac`](https://github.com/gradio-app/gradio/commit/66375acb5c0a3a8eecc4cfa00701b14f21f3ed68) - Fix typo in Exception raised by base.py. Thanks @meg-huggingface! +- [#9950](https://github.com/gradio-app/gradio/pull/9950) [`fc06fe4`](https://github.com/gradio-app/gradio/commit/fc06fe41f015678a0545f4e5c99f6ae2704f0031) - Add ability to read and write from LocalStorage. Thanks @abidlabs! +- [#9966](https://github.com/gradio-app/gradio/pull/9966) [`da6f191`](https://github.com/gradio-app/gradio/commit/da6f1915547b03601d1808b28e57cca62308df71) - Remember token locally with `gr.load()`. Thanks @abidlabs! + +### Fixes + +- [#9949](https://github.com/gradio-app/gradio/pull/9949) [`cfb62bf`](https://github.com/gradio-app/gradio/commit/cfb62bfdb52d88295f27287f788fca977e37ae6d) - Allow dataframe column content to wrap. Thanks @hannahblair! +- [#9897](https://github.com/gradio-app/gradio/pull/9897) [`c0cf80b`](https://github.com/gradio-app/gradio/commit/c0cf80bddd99ad0f836e618cc3d2b13e73cb5611) - Allow datetime value to be null. Thanks @hannahblair! +- [#9958](https://github.com/gradio-app/gradio/pull/9958) [`75ad3e3`](https://github.com/gradio-app/gradio/commit/75ad3e341978a521df3d11d4f97d6e55f784c9a1) - SSR Safari Fix. Thanks @dawoodkhan82! +- [#9905](https://github.com/gradio-app/gradio/pull/9905) [`08f4b8b`](https://github.com/gradio-app/gradio/commit/08f4b8b000702456e04fac70961a4fbe0058f11c) - Add `allow_file_downloads` param to allow downloading image/video/audio media in chatbot. Thanks @hannahblair! +- [#9913](https://github.com/gradio-app/gradio/pull/9913) [`d81f430`](https://github.com/gradio-app/gradio/commit/d81f430fd50546001b76c0ae5fded32c6d3093f7) - fix: Fix filename stripping to preserve extensions. Thanks @TakaSoap! +- [#9946](https://github.com/gradio-app/gradio/pull/9946) [`a966e9f`](https://github.com/gradio-app/gradio/commit/a966e9f753af25eb9d813dfdbce39be6f3014d82) - Hide upload button after upload when `file_count="single"`. Thanks @abidlabs! +- [#9901](https://github.com/gradio-app/gradio/pull/9901) [`74b4ff0`](https://github.com/gradio-app/gradio/commit/74b4ff0e61a2a32e1cd5e3354d3002b369c7ad83) - Ensure radio radius is consistent with checkbox radius. Thanks @hannahblair! +- [#9904](https://github.com/gradio-app/gradio/pull/9904) [`f523c91`](https://github.com/gradio-app/gradio/commit/f523c915d3732859ff4a8019a82cb597b5208ae2) - Ensure dropped files are validated in MultimediaTextbox. Thanks @hannahblair! + +## 5.5.0 + +### Features + +- [#9875](https://github.com/gradio-app/gradio/pull/9875) [`8305ff8`](https://github.com/gradio-app/gradio/commit/8305ff8712183f27174cfb891548ad7cc1c67fed) - Adds `.expand()` and `.collapse()` events to `gr.Accordion`. Thanks @abidlabs! +- [#9424](https://github.com/gradio-app/gradio/pull/9424) [`a1582a6`](https://github.com/gradio-app/gradio/commit/a1582a6dca494618c734208cade87acfdac91004) - Lite worker refactoring. Thanks @whitphx! +- [#9891](https://github.com/gradio-app/gradio/pull/9891) [`fc12496`](https://github.com/gradio-app/gradio/commit/fc124964a1b4922e54a4ca4755f0a536dfae1a21) - Allow uploading more files in gr.File. Thanks @hannahblair! +- [#9898](https://github.com/gradio-app/gradio/pull/9898) [`dcfa7ad`](https://github.com/gradio-app/gradio/commit/dcfa7ad3e819002c0213a592ad726ccfd9e2bf0c) - Enforce `meta` key present during preprocess in FileData payloads. Thanks @freddyaboulton! +- [#9887](https://github.com/gradio-app/gradio/pull/9887) [`d407c00`](https://github.com/gradio-app/gradio/commit/d407c007153705a7f5446f4601c12f208ec32a5b) - Add `.download()` event to `gr.File`. Thanks @abidlabs! +- [#9726](https://github.com/gradio-app/gradio/pull/9726) [`b6725cf`](https://github.com/gradio-app/gradio/commit/b6725cf6c1fe9667dc10e1988976ed36d84d73d3) - Lite auto-load imported modules with `pyodide.loadPackagesFromImports`. Thanks @whitphx! +- [#9786](https://github.com/gradio-app/gradio/pull/9786) [`f109497`](https://github.com/gradio-app/gradio/commit/f109497e8281b3429b58e3f6a293dd63ebcc08af) - Fix frontend errors on ApiDocs and RecordingSnippet. Thanks @whitphx! +- [#9800](https://github.com/gradio-app/gradio/pull/9800) [`d1cfe1e`](https://github.com/gradio-app/gradio/commit/d1cfe1e9defa06f927aec2671656fe77514dd0fa) - Allow plot tooltip to show extra columns. Thanks @aliabid94! + +### Fixes + +- [#9835](https://github.com/gradio-app/gradio/pull/9835) [`4d90883`](https://github.com/gradio-app/gradio/commit/4d9088354df528c8edf981f3e756d8927d3e8805) - Allows selection of directories in File Explorer. Thanks @aliabid94! +- [#9883](https://github.com/gradio-app/gradio/pull/9883) [`e10bbd2`](https://github.com/gradio-app/gradio/commit/e10bbd236f5817698f5e5ac1c14c7ec179a725b6) - Fix live interfaces for audio/image streaming. Thanks @freddyaboulton! +- [#9804](https://github.com/gradio-app/gradio/pull/9804) [`458a38c`](https://github.com/gradio-app/gradio/commit/458a38cabb8e378bb008b1abec8eee8b780fe712) - Fixes for ChatInterface Examples when additional inputs are provided. Thanks @dawoodkhan82! +- [#9827](https://github.com/gradio-app/gradio/pull/9827) [`7ed8d02`](https://github.com/gradio-app/gradio/commit/7ed8d02979e8ad4db6ef62b29ce080f31bcf9a0d) - Fix Loading SSR'd apps via gr.load. Thanks @freddyaboulton! +- [#9882](https://github.com/gradio-app/gradio/pull/9882) [`6c8a064`](https://github.com/gradio-app/gradio/commit/6c8a064feeaa89a2ffc96260032f24f18eb032fa) - Ensure non-form elements are correctly positioned when scale is applied. Thanks @hannahblair! +- [#9880](https://github.com/gradio-app/gradio/pull/9880) [`120198f`](https://github.com/gradio-app/gradio/commit/120198fe2da2ded9e8f27549b9dfd1cd81992ec4) - Fixes LoginButton for SSR. Thanks @dawoodkhan82! +- [#9881](https://github.com/gradio-app/gradio/pull/9881) [`6866a54`](https://github.com/gradio-app/gradio/commit/6866a5433afe7e29ad73bac10ecbc3b44f5867f4) - Ensure gallery share button is positioned correctly. Thanks @hannahblair! +- [#9826](https://github.com/gradio-app/gradio/pull/9826) [`69acfeb`](https://github.com/gradio-app/gradio/commit/69acfebffd0d3479a40352de19c8763863557428) - Make sure the Tool accordion is closed if it is not the last message. Thanks @freddyaboulton! +- [#9892](https://github.com/gradio-app/gradio/pull/9892) [`7d77024`](https://github.com/gradio-app/gradio/commit/7d77024cb8f9cfd39a6468de9534e58dcfa69f49) - Fix dataframe height increasing on scroll. Thanks @abidlabs! +- [#9859](https://github.com/gradio-app/gradio/pull/9859) [`c1cb5be`](https://github.com/gradio-app/gradio/commit/c1cb5be2d79fce5d25032366b5864700ba9d1114) - Fix: Resolve copy button visibility issue in Textbox component. Thanks @rahulsamant37! +- [#9886](https://github.com/gradio-app/gradio/pull/9886) [`fa5d433`](https://github.com/gradio-app/gradio/commit/fa5d4339d6aafda529150d9536b895e2b239c831) - Do not load code in gr.NO_RELOAD in the reload mode watch thread. Thanks @freddyaboulton! + ## 5.4.0 ### Features diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2f502f421823d..5c97432c23ca7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -117,6 +117,9 @@ gradio app.py This will start the backend server in reload mode, which will watch for changes in the `gradio` folder and reload the app if changes are made. By default, Gradio will launch on port 7860. You can also just use `python app.py`, but this won't automatically trigger updates. +Note: if you have `gradio` installed elsewhere in your system, you may need to uninstall it or at least make sure your `PYTHONPATH` includes the directory where the Gradio repository is cloned, e.g., +`export PYTHONPATH="./"` + If you're making frontend changes, start the frontend server: @@ -140,7 +143,7 @@ We use Pytest, Playwright and Vitest to test our code. - The Python tests are located in `/test`. To run these tests: ``` -bash scripts/run_all_tests.sh +bash scripts/run_backend_tests.sh ``` - The frontend unit tests are any defined with the filename `*.test.ts`. To run them: @@ -348,5 +351,18 @@ Run `scripts/build_frontend.sh` with the environment variable `NODE_OPTIONS=--ma --- +In the case of: +- Unexpected exceptions being thrown, or +- The following warning: +`IMPORTANT: You are using gradio version , however version is available, please upgrade.` + +ensure your `PYTHONPATH` includes the directory where the Gradio repository is cloned, e.g.: + +```export PYTHONPATH="./"``` + +This ensures that when `gradio` is imported in a python program, it is this current version from this repository. + +--- + _Could these guidelines be clearer? Feel free to open a PR to help us facilitate open-source contributions!_ diff --git a/client/js/CHANGELOG.md b/client/js/CHANGELOG.md index 8bad859ef48f6..6fbe8b44f2453 100644 --- a/client/js/CHANGELOG.md +++ b/client/js/CHANGELOG.md @@ -1,5 +1,12 @@ # @gradio/client +## 1.8.0 + +### Features + +- [#9930](https://github.com/gradio-app/gradio/pull/9930) [`eae345e`](https://github.com/gradio-app/gradio/commit/eae345e5fde39aea220b57c6a954cd7d72ff32d5) - Allow settings custom headers in js client. Thanks @elgiano! +- [#9950](https://github.com/gradio-app/gradio/pull/9950) [`fc06fe4`](https://github.com/gradio-app/gradio/commit/fc06fe41f015678a0545f4e5c99f6ae2704f0031) - Add ability to read and write from LocalStorage. Thanks @abidlabs! + ## 1.7.1 ### Fixes diff --git a/client/js/package.json b/client/js/package.json index 8ab4cd6d3dfc2..05aa04f5371ef 100644 --- a/client/js/package.json +++ b/client/js/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/client", - "version": "1.7.1", + "version": "1.8.0", "description": "Gradio API client", "type": "module", "main": "dist/index.js", diff --git a/client/js/src/client.ts b/client/js/src/client.ts index 47058adb75522..aef0684d83162 100644 --- a/client/js/src/client.ts +++ b/client/js/src/client.ts @@ -70,6 +70,11 @@ export class Client { if (this && this.cookies) { headers.append("Cookie", this.cookies); } + if (this && this.options.headers) { + for (const name in this.options.headers) { + headers.append(name, this.options.headers[name]); + } + } return fetch(input, { ...init, headers }); } @@ -79,6 +84,11 @@ export class Client { if (this && this.cookies) { headers.append("Cookie", this.cookies); } + if (this && this.options.headers) { + for (const name in this.options.headers) { + headers.append(name, this.options.headers[name]); + } + } this.abort_controller = new AbortController(); diff --git a/client/js/src/types.ts b/client/js/src/types.ts index fa7d5c7f198bb..84baddf2bafe1 100644 --- a/client/js/src/types.ts +++ b/client/js/src/types.ts @@ -299,6 +299,7 @@ export interface ClientOptions { auth?: [string, string] | null; with_null_state?: boolean; events?: EventType[]; + headers?: Record; } export interface FileData { diff --git a/client/python/CHANGELOG.md b/client/python/CHANGELOG.md index 05061b74dbccd..f6a719e72d295 100644 --- a/client/python/CHANGELOG.md +++ b/client/python/CHANGELOG.md @@ -1,5 +1,11 @@ # gradio_client +## 1.4.3 + +### Fixes + +- [#9913](https://github.com/gradio-app/gradio/pull/9913) [`d81f430`](https://github.com/gradio-app/gradio/commit/d81f430fd50546001b76c0ae5fded32c6d3093f7) - fix: Fix filename stripping to preserve extensions. Thanks @TakaSoap! + ## 1.4.2 ### Fixes diff --git a/client/python/gradio_client/CHANGELOG.md b/client/python/gradio_client/CHANGELOG.md index 05061b74dbccd..f6a719e72d295 100644 --- a/client/python/gradio_client/CHANGELOG.md +++ b/client/python/gradio_client/CHANGELOG.md @@ -1,5 +1,11 @@ # gradio_client +## 1.4.3 + +### Fixes + +- [#9913](https://github.com/gradio-app/gradio/pull/9913) [`d81f430`](https://github.com/gradio-app/gradio/commit/d81f430fd50546001b76c0ae5fded32c6d3093f7) - fix: Fix filename stripping to preserve extensions. Thanks @TakaSoap! + ## 1.4.2 ### Fixes diff --git a/client/python/gradio_client/package.json b/client/python/gradio_client/package.json index 49a7ee9079f70..3a825bdcd13d6 100644 --- a/client/python/gradio_client/package.json +++ b/client/python/gradio_client/package.json @@ -1,6 +1,6 @@ { "name": "gradio_client", - "version": "1.4.2", + "version": "1.4.3", "description": "", "python": "true", "main_changeset": true, diff --git a/client/python/gradio_client/utils.py b/client/python/gradio_client/utils.py index 10fe5ffe48bd3..d9f6ed5e90f55 100644 --- a/client/python/gradio_client/utils.py +++ b/client/python/gradio_client/utils.py @@ -750,14 +750,21 @@ def decode_base64_to_binary(encoding: str) -> tuple[bytes, str | None]: def strip_invalid_filename_characters(filename: str, max_bytes: int = 200) -> str: - """Strips invalid characters from a filename and ensures that the file_length is less than `max_bytes` bytes.""" - filename = "".join([char for char in filename if char.isalnum() or char in "._- "]) + """ + Strips invalid characters from a filename and ensures it does not exceed the maximum byte length + Invalid characters are any characters that are not alphanumeric or one of the following: . _ - + The filename may include an extension (in which case it is preserved exactly as is), or could be just a name without an extension. + """ + name, ext = os.path.splitext(filename) + name = "".join([char for char in name if char.isalnum() or char in "._- "]) + filename = name + ext filename_len = len(filename.encode()) if filename_len > max_bytes: while filename_len > max_bytes: - if len(filename) == 0: + if len(name) == 0: break - filename = filename[:-1] + name = name[:-1] + filename = name + ext filename_len = len(filename.encode()) return filename diff --git a/client/python/test/test_utils.py b/client/python/test/test_utils.py index 68272611cfc1a..ee89e16bd754e 100644 --- a/client/python/test/test_utils.py +++ b/client/python/test/test_utils.py @@ -91,13 +91,15 @@ def test_is_valid_file_type(path_or_url, file_types, expected_result): [ ("abc", "abc"), ("$$AAabc&3", "AAabc3"), - ("$$AAabc&3", "AAabc3"), - ("$$AAa..b-c&3_", "AAa..b-c3_"), - ("$$AAa..b-c&3_", "AAa..b-c3_"), + ("$$AAa&..b-c3_", "AAa..b-c3_"), ( "ゆかりです。私、こんなかわいい服は初めて着ました…。なんだかうれしくって、楽しいです。歌いたくなる気分って、初めてです。これがアイドルってことなのかもしれませんね", "ゆかりです私こんなかわいい服は初めて着ましたなんだかうれしくって楽しいです歌いたくなる気分って初めてですこれがアイドルってことなの", ), + ( + "Bringing-computational-thinking-into-classrooms-a-systematic-review-on-supporting-teachers-in-integrating-computational-thinking-into-K12-classrooms_2024_Springer-Science-and-Business-Media-Deutschland-GmbH.pdf", + "Bringing-computational-thinking-into-classrooms-a-systematic-review-on-supporting-teachers-in-integrating-computational-thinking-into-K12-classrooms_2024_Springer-Science-and-Business-Media-Deutsc.pdf", + ), ], ) def test_strip_invalid_filename_characters(orig_filename, new_filename): diff --git a/demo/browser_state_component/run.ipynb b/demo/browser_state_component/run.ipynb new file mode 100644 index 0000000000000..104d4f4118a57 --- /dev/null +++ b/demo/browser_state_component/run.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: browser_state_component"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "with gr.Blocks() as demo:\n", " gr.BrowserState()\n", "\n", "demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} \ No newline at end of file diff --git a/demo/browser_state_component/run.py b/demo/browser_state_component/run.py new file mode 100644 index 0000000000000..20999a495fa4d --- /dev/null +++ b/demo/browser_state_component/run.py @@ -0,0 +1,6 @@ +import gradio as gr + +with gr.Blocks() as demo: + gr.BrowserState() + +demo.launch() diff --git a/demo/browserstate/run.ipynb b/demo/browserstate/run.ipynb new file mode 100644 index 0000000000000..b3fc96115affb --- /dev/null +++ b/demo/browserstate/run.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: browserstate"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import random\n", "import string\n", "import gradio as gr\n", "\n", "with gr.Blocks() as demo:\n", " gr.Markdown(\"Your Username and Password will get saved in the browser's local storage. \"\n", " \"If you refresh the page, the values will be retained.\")\n", " username = gr.Textbox(label=\"Username\")\n", " password = gr.Textbox(label=\"Password\", type=\"password\")\n", " btn = gr.Button(\"Generate Randomly\")\n", " local_storage = gr.BrowserState([\"\", \"\"])\n", "\n", " @btn.click(outputs=[username, password])\n", " def generate_randomly():\n", " u = \"\".join(random.choices(string.ascii_letters + string.digits, k=10))\n", " p = \"\".join(random.choices(string.ascii_letters + string.digits, k=10))\n", " return u, p\n", "\n", " @demo.load(inputs=[local_storage], outputs=[username, password])\n", " def load_from_local_storage(saved_values):\n", " print(\"loading from local storage\", saved_values)\n", " return saved_values[0], saved_values[1]\n", "\n", " @gr.on([username.change, password.change], inputs=[username, password], outputs=[local_storage])\n", " def save_to_local_storage(username, password):\n", " return [username, password]\n", "\n", "demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} \ No newline at end of file diff --git a/demo/browserstate/run.py b/demo/browserstate/run.py new file mode 100644 index 0000000000000..294b56fd58f64 --- /dev/null +++ b/demo/browserstate/run.py @@ -0,0 +1,28 @@ +import random +import string +import gradio as gr + +with gr.Blocks() as demo: + gr.Markdown("Your Username and Password will get saved in the browser's local storage. " + "If you refresh the page, the values will be retained.") + username = gr.Textbox(label="Username") + password = gr.Textbox(label="Password", type="password") + btn = gr.Button("Generate Randomly") + local_storage = gr.BrowserState(["", ""]) + + @btn.click(outputs=[username, password]) + def generate_randomly(): + u = "".join(random.choices(string.ascii_letters + string.digits, k=10)) + p = "".join(random.choices(string.ascii_letters + string.digits, k=10)) + return u, p + + @demo.load(inputs=[local_storage], outputs=[username, password]) + def load_from_local_storage(saved_values): + print("loading from local storage", saved_values) + return saved_values[0], saved_values[1] + + @gr.on([username.change, password.change], inputs=[username, password], outputs=[local_storage]) + def save_to_local_storage(username, password): + return [username, password] + +demo.launch() diff --git a/demo/load_model_with_token/run.ipynb b/demo/load_model_with_token/run.ipynb new file mode 100644 index 0000000000000..7d8b7d257169d --- /dev/null +++ b/demo/load_model_with_token/run.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: load_model_with_token"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "# This demo requires a Hugging Face PRO token.\n", "demo = gr.load(\"meta-llama/Meta-Llama-3-8B-Instruct\", src=\"models\", accept_token=True)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} \ No newline at end of file diff --git a/demo/load_model_with_token/run.py b/demo/load_model_with_token/run.py new file mode 100644 index 0000000000000..9d13b5770a9f7 --- /dev/null +++ b/demo/load_model_with_token/run.py @@ -0,0 +1,7 @@ +import gradio as gr + +# This demo requires a Hugging Face PRO token. +demo = gr.load("meta-llama/Meta-Llama-3-8B-Instruct", src="models", accept_token=True) + +if __name__ == "__main__": + demo.launch() diff --git a/demo/random_demos.py b/demo/random_demos.py index c3cccde454378..c9f54a477d8ea 100644 --- a/demo/random_demos.py +++ b/demo/random_demos.py @@ -2,15 +2,13 @@ Usage: python random_demos.py Example: python random_demos.py 8 - -Assumes: -- This is being run from the gradio/demo/ directory """ from __future__ import annotations import argparse import importlib +import pathlib import os import random @@ -21,12 +19,13 @@ args = parser.parse_args() # get the list of directory names -demos_list = next(os.walk('.'))[1] +demos_list = next(os.walk(pathlib.Path(__file__).parent))[1] # Some demos are just too large or need to be run in a special way, so we'll just skip them -demos_list.remove('streaming_wav2vec') -demos_list.remove('blocks_neural_instrument_coding') -demos_list.remove('.gradio/flagged') +large_demos = ['streaming_wav2vec', 'blocks_neural_instrument_coding', '.gradio/flagged'] +for large_demo in large_demos: + if large_demo in demos_list: + demos_list.remove(large_demo) for d, demo_name in enumerate(random.sample(demos_list, args.num_demos)): print(f"Launching demo {d+1}/{args.num_demos}: {demo_name}") diff --git a/gradio/CHANGELOG.md b/gradio/CHANGELOG.md index b9ab81d080a28..a2581b23fcc4e 100644 --- a/gradio/CHANGELOG.md +++ b/gradio/CHANGELOG.md @@ -1,5 +1,54 @@ # gradio +## 5.6.0 + +### Features + +- [#9906](https://github.com/gradio-app/gradio/pull/9906) [`eafe22c`](https://github.com/gradio-app/gradio/commit/eafe22cd9404d536b03d3fa80003acea78599d49) - Clearer error message in CheckboxGroup's preprocess function. Thanks @muhammadyaseen! +- [#9930](https://github.com/gradio-app/gradio/pull/9930) [`eae345e`](https://github.com/gradio-app/gradio/commit/eae345e5fde39aea220b57c6a954cd7d72ff32d5) - Allow settings custom headers in js client. Thanks @elgiano! +- [#9921](https://github.com/gradio-app/gradio/pull/9921) [`a70ba5e`](https://github.com/gradio-app/gradio/commit/a70ba5e0f01f0c376da0d4e45634bc967f5299f4) - Clearer error message in Dropdown's and Radio's preprocess function. Thanks @muhammadyaseen! +- [#9933](https://github.com/gradio-app/gradio/pull/9933) [`66375ac`](https://github.com/gradio-app/gradio/commit/66375acb5c0a3a8eecc4cfa00701b14f21f3ed68) - Fix typo in Exception raised by base.py. Thanks @meg-huggingface! +- [#9950](https://github.com/gradio-app/gradio/pull/9950) [`fc06fe4`](https://github.com/gradio-app/gradio/commit/fc06fe41f015678a0545f4e5c99f6ae2704f0031) - Add ability to read and write from LocalStorage. Thanks @abidlabs! +- [#9966](https://github.com/gradio-app/gradio/pull/9966) [`da6f191`](https://github.com/gradio-app/gradio/commit/da6f1915547b03601d1808b28e57cca62308df71) - Remember token locally with `gr.load()`. Thanks @abidlabs! + +### Fixes + +- [#9949](https://github.com/gradio-app/gradio/pull/9949) [`cfb62bf`](https://github.com/gradio-app/gradio/commit/cfb62bfdb52d88295f27287f788fca977e37ae6d) - Allow dataframe column content to wrap. Thanks @hannahblair! +- [#9897](https://github.com/gradio-app/gradio/pull/9897) [`c0cf80b`](https://github.com/gradio-app/gradio/commit/c0cf80bddd99ad0f836e618cc3d2b13e73cb5611) - Allow datetime value to be null. Thanks @hannahblair! +- [#9958](https://github.com/gradio-app/gradio/pull/9958) [`75ad3e3`](https://github.com/gradio-app/gradio/commit/75ad3e341978a521df3d11d4f97d6e55f784c9a1) - SSR Safari Fix. Thanks @dawoodkhan82! +- [#9905](https://github.com/gradio-app/gradio/pull/9905) [`08f4b8b`](https://github.com/gradio-app/gradio/commit/08f4b8b000702456e04fac70961a4fbe0058f11c) - Add `allow_file_downloads` param to allow downloading image/video/audio media in chatbot. Thanks @hannahblair! +- [#9913](https://github.com/gradio-app/gradio/pull/9913) [`d81f430`](https://github.com/gradio-app/gradio/commit/d81f430fd50546001b76c0ae5fded32c6d3093f7) - fix: Fix filename stripping to preserve extensions. Thanks @TakaSoap! +- [#9946](https://github.com/gradio-app/gradio/pull/9946) [`a966e9f`](https://github.com/gradio-app/gradio/commit/a966e9f753af25eb9d813dfdbce39be6f3014d82) - Hide upload button after upload when `file_count="single"`. Thanks @abidlabs! +- [#9901](https://github.com/gradio-app/gradio/pull/9901) [`74b4ff0`](https://github.com/gradio-app/gradio/commit/74b4ff0e61a2a32e1cd5e3354d3002b369c7ad83) - Ensure radio radius is consistent with checkbox radius. Thanks @hannahblair! +- [#9904](https://github.com/gradio-app/gradio/pull/9904) [`f523c91`](https://github.com/gradio-app/gradio/commit/f523c915d3732859ff4a8019a82cb597b5208ae2) - Ensure dropped files are validated in MultimediaTextbox. Thanks @hannahblair! + +## 5.5.0 + +### Features + +- [#9875](https://github.com/gradio-app/gradio/pull/9875) [`8305ff8`](https://github.com/gradio-app/gradio/commit/8305ff8712183f27174cfb891548ad7cc1c67fed) - Adds `.expand()` and `.collapse()` events to `gr.Accordion`. Thanks @abidlabs! +- [#9424](https://github.com/gradio-app/gradio/pull/9424) [`a1582a6`](https://github.com/gradio-app/gradio/commit/a1582a6dca494618c734208cade87acfdac91004) - Lite worker refactoring. Thanks @whitphx! +- [#9891](https://github.com/gradio-app/gradio/pull/9891) [`fc12496`](https://github.com/gradio-app/gradio/commit/fc124964a1b4922e54a4ca4755f0a536dfae1a21) - Allow uploading more files in gr.File. Thanks @hannahblair! +- [#9898](https://github.com/gradio-app/gradio/pull/9898) [`dcfa7ad`](https://github.com/gradio-app/gradio/commit/dcfa7ad3e819002c0213a592ad726ccfd9e2bf0c) - Enforce `meta` key present during preprocess in FileData payloads. Thanks @freddyaboulton! +- [#9887](https://github.com/gradio-app/gradio/pull/9887) [`d407c00`](https://github.com/gradio-app/gradio/commit/d407c007153705a7f5446f4601c12f208ec32a5b) - Add `.download()` event to `gr.File`. Thanks @abidlabs! +- [#9726](https://github.com/gradio-app/gradio/pull/9726) [`b6725cf`](https://github.com/gradio-app/gradio/commit/b6725cf6c1fe9667dc10e1988976ed36d84d73d3) - Lite auto-load imported modules with `pyodide.loadPackagesFromImports`. Thanks @whitphx! +- [#9786](https://github.com/gradio-app/gradio/pull/9786) [`f109497`](https://github.com/gradio-app/gradio/commit/f109497e8281b3429b58e3f6a293dd63ebcc08af) - Fix frontend errors on ApiDocs and RecordingSnippet. Thanks @whitphx! +- [#9800](https://github.com/gradio-app/gradio/pull/9800) [`d1cfe1e`](https://github.com/gradio-app/gradio/commit/d1cfe1e9defa06f927aec2671656fe77514dd0fa) - Allow plot tooltip to show extra columns. Thanks @aliabid94! + +### Fixes + +- [#9835](https://github.com/gradio-app/gradio/pull/9835) [`4d90883`](https://github.com/gradio-app/gradio/commit/4d9088354df528c8edf981f3e756d8927d3e8805) - Allows selection of directories in File Explorer. Thanks @aliabid94! +- [#9883](https://github.com/gradio-app/gradio/pull/9883) [`e10bbd2`](https://github.com/gradio-app/gradio/commit/e10bbd236f5817698f5e5ac1c14c7ec179a725b6) - Fix live interfaces for audio/image streaming. Thanks @freddyaboulton! +- [#9804](https://github.com/gradio-app/gradio/pull/9804) [`458a38c`](https://github.com/gradio-app/gradio/commit/458a38cabb8e378bb008b1abec8eee8b780fe712) - Fixes for ChatInterface Examples when additional inputs are provided. Thanks @dawoodkhan82! +- [#9827](https://github.com/gradio-app/gradio/pull/9827) [`7ed8d02`](https://github.com/gradio-app/gradio/commit/7ed8d02979e8ad4db6ef62b29ce080f31bcf9a0d) - Fix Loading SSR'd apps via gr.load. Thanks @freddyaboulton! +- [#9882](https://github.com/gradio-app/gradio/pull/9882) [`6c8a064`](https://github.com/gradio-app/gradio/commit/6c8a064feeaa89a2ffc96260032f24f18eb032fa) - Ensure non-form elements are correctly positioned when scale is applied. Thanks @hannahblair! +- [#9880](https://github.com/gradio-app/gradio/pull/9880) [`120198f`](https://github.com/gradio-app/gradio/commit/120198fe2da2ded9e8f27549b9dfd1cd81992ec4) - Fixes LoginButton for SSR. Thanks @dawoodkhan82! +- [#9881](https://github.com/gradio-app/gradio/pull/9881) [`6866a54`](https://github.com/gradio-app/gradio/commit/6866a5433afe7e29ad73bac10ecbc3b44f5867f4) - Ensure gallery share button is positioned correctly. Thanks @hannahblair! +- [#9826](https://github.com/gradio-app/gradio/pull/9826) [`69acfeb`](https://github.com/gradio-app/gradio/commit/69acfebffd0d3479a40352de19c8763863557428) - Make sure the Tool accordion is closed if it is not the last message. Thanks @freddyaboulton! +- [#9892](https://github.com/gradio-app/gradio/pull/9892) [`7d77024`](https://github.com/gradio-app/gradio/commit/7d77024cb8f9cfd39a6468de9534e58dcfa69f49) - Fix dataframe height increasing on scroll. Thanks @abidlabs! +- [#9859](https://github.com/gradio-app/gradio/pull/9859) [`c1cb5be`](https://github.com/gradio-app/gradio/commit/c1cb5be2d79fce5d25032366b5864700ba9d1114) - Fix: Resolve copy button visibility issue in Textbox component. Thanks @rahulsamant37! +- [#9886](https://github.com/gradio-app/gradio/pull/9886) [`fa5d433`](https://github.com/gradio-app/gradio/commit/fa5d4339d6aafda529150d9536b895e2b239c831) - Do not load code in gr.NO_RELOAD in the reload mode watch thread. Thanks @freddyaboulton! + ## 5.4.0 ### Features diff --git a/gradio/__init__.py b/gradio/__init__.py index e4087f575fb54..2bdbfeb21ad78 100644 --- a/gradio/__init__.py +++ b/gradio/__init__.py @@ -14,6 +14,7 @@ Annotatedimage, Audio, BarPlot, + BrowserState, Button, Chatbot, ChatMessage, diff --git a/gradio/blocks.py b/gradio/blocks.py index e464037eb036e..9b36eb4e39076 100644 --- a/gradio/blocks.py +++ b/gradio/blocks.py @@ -18,12 +18,7 @@ from collections.abc import AsyncIterator, Callable, Coroutine, Sequence, Set from pathlib import Path from types import ModuleType -from typing import ( - TYPE_CHECKING, - Any, - Literal, - cast, -) +from typing import TYPE_CHECKING, Any, Literal, Union, cast from urllib.parse import urlparse, urlunparse import anyio @@ -1702,10 +1697,12 @@ async def preprocess_data( check_in_upload_folder=not explicit_call, ) if getattr(block, "data_model", None) and inputs_cached is not None: - if issubclass(block.data_model, GradioModel): # type: ignore - inputs_cached = block.data_model(**inputs_cached) # type: ignore - elif issubclass(block.data_model, GradioRootModel): # type: ignore - inputs_cached = block.data_model(root=inputs_cached) # type: ignore + data_model = cast( + Union[GradioModel, GradioRootModel], block.data_model + ) + inputs_cached = data_model.model_validate( + inputs_cached, context={"validate_meta": True} + ) processed_input.append(block.preprocess(inputs_cached)) else: processed_input = inputs diff --git a/gradio/components/__init__.py b/gradio/components/__init__.py index 4c2b2c7ba81ed..5e35566d38d56 100644 --- a/gradio/components/__init__.py +++ b/gradio/components/__init__.py @@ -9,6 +9,7 @@ component, get_component_instance, ) +from gradio.components.browser_state import BrowserState from gradio.components.button import Button from gradio.components.chatbot import Chatbot, ChatMessage, MessageDict from gradio.components.checkbox import Checkbox @@ -88,6 +89,7 @@ "Json", "Label", "LinePlot", + "BrowserState", "LoginButton", "Markdown", "MessageDict", diff --git a/gradio/components/base.py b/gradio/components/base.py index 53e634754e1b4..f5a89e14b42ab 100644 --- a/gradio/components/base.py +++ b/gradio/components/base.py @@ -448,7 +448,7 @@ def get_component_instance( component_obj = comp else: raise ValueError( - f"Component must provided as a `str` or `dict` or `Component` but is {comp}" + f"Component must be provided as a `str` or `dict` or `Component` but is {comp}" ) if render and not component_obj.is_rendered: diff --git a/gradio/components/browser_state.py b/gradio/components/browser_state.py new file mode 100644 index 0000000000000..178893d9d53d6 --- /dev/null +++ b/gradio/components/browser_state.py @@ -0,0 +1,69 @@ +"""gr.BrowserState() component.""" + +from __future__ import annotations + +import secrets +import string +from typing import Any + +from gradio_client.documentation import document + +from gradio.components.base import Component + + +@document() +class BrowserState(Component): + """ + Special component that stores state in the browser's localStorage in an encrypted format. + """ + + def __init__( + self, + default_value: Any = None, + *, + storage_key: str | None = None, + secret: str | None = None, + render: bool = True, + ): + """ + Parameters: + default_value: the default value that will be used if no value is found in localStorage. Should be a json-serializable value. + storage_key: the key to use in localStorage. If None, a random key will be generated. + secret: the secret key to use for encryption. If None, a random key will be generated (recommended). + render: should always be True, is included for consistency with other components. + """ + self.default_value = default_value + self.secret = secret or "".join( + secrets.choice(string.ascii_letters + string.digits) for _ in range(16) + ) + self.storage_key = storage_key or "".join( + secrets.choice(string.ascii_letters + string.digits) for _ in range(16) + ) + super().__init__(render=render) + + def preprocess(self, payload: Any) -> Any: + """ + Parameters: + payload: Value from local storage + Returns: + Passes value through unchanged + """ + return payload + + def postprocess(self, value: Any) -> Any: + """ + Parameters: + value: Value to store in local storage + Returns: + Passes value through unchanged + """ + return value + + def api_info(self) -> dict[str, Any]: + return {"type": {}, "description": "any json-serializable value"} + + def example_payload(self) -> Any: + return "test" + + def example_value(self) -> Any: + return "test" diff --git a/gradio/components/chatbot.py b/gradio/components/chatbot.py index 2733a9393298a..43e4a54c83a9f 100644 --- a/gradio/components/chatbot.py +++ b/gradio/components/chatbot.py @@ -184,6 +184,7 @@ def __init__( placeholder: str | None = None, examples: list[ExampleMessage] | None = None, show_copy_all_button=False, + allow_file_downloads=True, ): """ Parameters: @@ -218,6 +219,7 @@ def __init__( placeholder: a placeholder message to display in the chatbot when it is empty. Centered vertically and horizontally in the Chatbot. Supports Markdown and HTML. If None, no placeholder is displayed. examples: A list of example messages to display in the chatbot before any user/assistant messages are shown. Each example should be a dictionary with an optional "text" key representing the message that should be populated in the Chatbot when clicked, an optional "files" key, whose value should be a list of files to populate in the Chatbot, an optional "icon" key, whose value should be a filepath or URL to an image to display in the example box, and an optional "display_text" key, whose value should be the text to display in the example box. If "display_text" is not provided, the value of "text" will be displayed. show_copy_all_button: If True, will show a copy all button that copies all chatbot messages to the clipboard. + allow_file_downloads: If True, will show a download button for chatbot messages that contain media. Defaults to True. """ if type is None: warnings.warn( @@ -259,6 +261,7 @@ def __init__( self.line_breaks = line_breaks self.layout = layout self.show_copy_all_button = show_copy_all_button + self.allow_file_downloads = allow_file_downloads super().__init__( label=label, every=every, diff --git a/gradio/components/checkboxgroup.py b/gradio/components/checkboxgroup.py index c86348becae2e..3aa4d706e2225 100644 --- a/gradio/components/checkboxgroup.py +++ b/gradio/components/checkboxgroup.py @@ -123,7 +123,7 @@ def preprocess( for value in payload: if value not in choice_values: raise Error( - f"Value: {value} is not in the list of choices: {choice_values}" + f"Value: {value!r} (type: {type(value)}) is not in the list of choices: {choice_values}" ) if self.type == "value": return payload diff --git a/gradio/components/dropdown.py b/gradio/components/dropdown.py index b1c1a964db3f5..bea3d5df22c1f 100644 --- a/gradio/components/dropdown.py +++ b/gradio/components/dropdown.py @@ -196,7 +196,7 @@ def preprocess( for value in payload: if value not in choice_values: raise Error( - f"Value: {value} is not in the list of choices: {choice_values}" + f"Value: {value!r} (type: {type(value)}) is not in the list of choices: {choice_values}" ) elif payload not in choice_values: raise Error( diff --git a/gradio/components/radio.py b/gradio/components/radio.py index 2b7d490fb7a56..d97b17391d4e4 100644 --- a/gradio/components/radio.py +++ b/gradio/components/radio.py @@ -117,7 +117,7 @@ def preprocess(self, payload: str | int | float | None) -> str | int | float | N choice_values = [value for _, value in self.choices] if payload not in choice_values: raise Error( - f"Value: {payload} is not in the list of choices: {choice_values}" + f"Value: {payload!r} (type: {type(payload)}) is not in the list of choices: {choice_values}" ) if self.type == "value": diff --git a/gradio/components/state.py b/gradio/components/state.py index 61a8fcddb9ffa..204016096d057 100644 --- a/gradio/components/state.py +++ b/gradio/components/state.py @@ -36,7 +36,7 @@ def __init__( """ Parameters: value: the initial value (of arbitrary type) of the state. The provided argument is deepcopied. If a callable is provided, the function will be called whenever the app loads to set the initial value of the state. - render: has no effect, but is included for consistency with other components. + render: should always be True, is included for consistency with other components. time_to_live: The number of seconds the state should be stored for after it is created or updated. If None, the state will be stored indefinitely. Gradio automatically deletes state variables after a user closes the browser tab or refreshes the page, so this is useful for clearing state for potentially long running sessions. delete_callback: A function that is called when the state is deleted. The function should take the state value as an argument. """ diff --git a/gradio/data_classes.py b/gradio/data_classes.py index 268509e857a66..15c3f3b264753 100644 --- a/gradio/data_classes.py +++ b/gradio/data_classes.py @@ -21,13 +21,15 @@ from fastapi import Request from gradio_client.documentation import document -from gradio_client.utils import traverse +from gradio_client.utils import is_file_obj_with_meta, traverse from pydantic import ( BaseModel, GetCoreSchemaHandler, GetJsonSchemaHandler, RootModel, ValidationError, + ValidationInfo, + model_validator, ) from pydantic.json_schema import JsonSchemaValue from pydantic_core import core_schema @@ -227,6 +229,19 @@ class FileData(GradioModel): is_stream: bool = False meta: dict = {"_type": "gradio.FileData"} + @model_validator(mode="before") + @classmethod + def validate_model(cls, v, info: ValidationInfo): + if ( + info.context + and info.context.get("validate_meta") + and not is_file_obj_with_meta(v) + ): + raise ValueError( + "The 'meta' field must be explicitly provided in the input data and be equal to {'_type': 'gradio.FileData'}." + ) + return v + @property def is_none(self) -> bool: """ diff --git a/gradio/events.py b/gradio/events.py index 24e7085408e69..4bdc7d1e5a485 100644 --- a/gradio/events.py +++ b/gradio/events.py @@ -643,6 +643,17 @@ def inner(*args, **kwargs): event_trigger.event_name = _event_name # type: ignore event_trigger.has_trigger = _has_trigger # type: ignore event_trigger.callback = _callback # type: ignore + event_trigger.connection = _connection # type: ignore + event_specific_args = ( + [ + d["name"] + for d in _event_specific_args + if d.get("component_prop", "true") != "false" + ] + if _event_specific_args + else None + ) + event_trigger.event_specific_args = event_specific_args # type: ignore return event_trigger @@ -675,6 +686,8 @@ def on( concurrency_limit: int | None | Literal["default"] = "default", concurrency_id: str | None = None, show_api: bool = True, + time_limit: int | None = None, + stream_every: float = 0.5, ) -> Dependency: """ Sets up an event listener that triggers a function when the specified event(s) occur. This is especially @@ -700,6 +713,8 @@ def on( concurrency_limit: If set, this is the maximum number of this event that can be running simultaneously. Can be set to None to mean no concurrency_limit (any number of this event can be running simultaneously). Set to "default" to use the default concurrency limit (defined by the `default_concurrency_limit` parameter in `Blocks.queue()`, which itself is 1 by default). concurrency_id: If set, this is the id of the concurrency group. Events with the same concurrency_id will be limited by the lowest set concurrency_limit. show_api: whether to show this event in the "view API" page of the Gradio app, or in the ".view_api()" method of the Gradio clients. Unlike setting api_name to False, setting show_api to False will still allow downstream apps as well as the Clients to use this event. If fn is None, show_api will automatically be set to False. + time_limit: The time limit for the function to run. Parameter only used for the `.stream()` event. + stream_every: The latency (in seconds) at which stream chunks are sent to the backend. Defaults to 0.5 seconds. Parameter only used for the `.stream()` event. Example: import gradio as gr with gr.Blocks() as demo: @@ -746,6 +761,8 @@ def wrapper(func): concurrency_id=concurrency_id, show_api=show_api, trigger_mode=trigger_mode, + time_limit=time_limit, + stream_every=stream_every, ) @wraps(func) @@ -793,6 +810,16 @@ def inner(*args, **kwargs): max_batch_size=max_batch_size, show_api=show_api, trigger_mode=trigger_mode, + connection="stream" + if any(t.connection == "stream" for t in (triggers_typed or [])) + else "sse", + event_specific_args=[ + a + for t in (triggers_typed or []) + for a in cast(list[str], t.event_specific_args or []) + ], + time_limit=time_limit, + stream_every=stream_every, ) set_cancel_events(methods, cancels) return Dependency(None, dep.get_config(), dep_index, fn) diff --git a/gradio/external.py b/gradio/external.py index 1cdb0dc601c6a..d4a73a41f0dfd 100644 --- a/gradio/external.py +++ b/gradio/external.py @@ -89,11 +89,40 @@ def load( import gradio as gr with gr.Blocks(fill_height=True) as demo: - textbox = gr.Textbox( - type="password", - label="Token", - info="Enter your token and press enter.", + with gr.Accordion("Enter your token and press enter") as accordion: + textbox = gr.Textbox( + type="password", + show_label=False, + container=False, + ) + remember_token = gr.Checkbox( + label="Remember me on this device", value=False, container=False + ) + browser_state = gr.BrowserState() + + @gr.on([textbox.submit], outputs=accordion) + def hide_accordion(): + return gr.Accordion("Token settings", open=False) + + @gr.on( + [textbox.submit, remember_token.change], + inputs=[textbox, remember_token], + outputs=[browser_state, remember_token], ) + def save_token(token_value, remember_token_value): + if remember_token_value and token_value: + return token_value, gr.Checkbox( + label="Remember me on this device (saved!)", value=True + ) + else: + return "", gr.Checkbox(label="Remember me on this device") + + @gr.on(demo.load, inputs=[browser_state], outputs=[textbox, remember_token]) + def load_token(token_value): + if token_value: + return token_value, True + else: + return "", False @gr.render(inputs=[textbox], triggers=[textbox.submit]) def create(token_value): diff --git a/gradio/http_server.py b/gradio/http_server.py index 848895d1e686b..1425310c596d8 100644 --- a/gradio/http_server.py +++ b/gradio/http_server.py @@ -2,6 +2,7 @@ import os import socket +import sys import threading import time from functools import partial @@ -144,6 +145,7 @@ def start_server( demo_name=GRADIO_WATCH_DEMO_NAME, stop_event=threading.Event(), demo_file=GRADIO_WATCH_DEMO_PATH, + watch_module=sys.modules["__main__"], ) server = Server(config=config, reloader=reloader) server.run_in_thread() diff --git a/gradio/interface.py b/gradio/interface.py index f3bd7a8ef8c60..677dfac307531 100644 --- a/gradio/interface.py +++ b/gradio/interface.py @@ -142,6 +142,8 @@ def __init__( | Literal["auto"] | Literal["manual"] | None = None, + time_limit: int | None = 30, + stream_every: float = 0.5, **kwargs, ): """ @@ -182,6 +184,8 @@ def __init__( show_progress: how to show the progress animation while event is running: "full" shows a spinner which covers the output component area as well as a runtime display in the upper right corner, "minimal" only shows the runtime display, "hidden" shows no progress animation at all example_labels: a list of labels for each example. If provided, the length of this list should be the same as the number of examples, and these labels will be used in the UI instead of rendering the example values. fill_width: whether to horizontally expand to fill container fully. If False, centers and constrains app to a maximum width. + time_limit: The time limit for the stream to run. Default is 30 seconds. Parameter only used for streaming images or audio if the interface is live and the input components are set to "streaming=True". + stream_every: The latency (in seconds) at which stream chunks are sent to the backend. Defaults to 0.5 seconds. Parameter only used for streaming images or audio if the interface is live and the input components are set to "streaming=True". """ super().__init__( analytics_enabled=analytics_enabled, @@ -197,6 +201,8 @@ def __init__( fill_width=fill_width, **kwargs, ) + self.time_limit = time_limit + self.stream_every = stream_every self.api_name: str | Literal[False] | None = api_name self.interface_type = InterfaceTypes.STANDARD if (inputs is None or inputs == []) and (outputs is None or outputs == []): @@ -702,7 +708,9 @@ def attach_submit_events( preprocess=not (self.api_mode), postprocess=not (self.api_mode), show_progress="hidden" if streaming_event else self.show_progress, - trigger_mode="always_last", + trigger_mode="always_last" if not streaming_event else "multiple", + time_limit=self.time_limit, + stream_every=self.stream_every, ) else: if _submit_btn is None: @@ -716,6 +724,12 @@ def attach_submit_events( if component.has_event(Events.submit) ] + for component in self.input_components: + if getattr(component, "streaming", None): + warnings.warn( + "Streaming components are only supported in live interfaces." + ) + if _stop_btn: extra_output = [_submit_btn, _stop_btn] diff --git a/gradio/package.json b/gradio/package.json index 4227d4b2a6f67..fbc1ac0792e88 100644 --- a/gradio/package.json +++ b/gradio/package.json @@ -1,6 +1,6 @@ { "name": "gradio", - "version": "5.4.0", + "version": "5.6.0", "description": "", "python": "true" } \ No newline at end of file diff --git a/gradio/queueing.py b/gradio/queueing.py index c849c8a0e5156..2d5302305b97c 100644 --- a/gradio/queueing.py +++ b/gradio/queueing.py @@ -666,7 +666,9 @@ async def process_events( else ServerMessage.process_streaming, output=old_response, success=old_response is not None, - time_limit=cast(int, fn.time_limit) - first_iteration + time_limit=None + if not fn.time_limit + else cast(int, fn.time_limit) - first_iteration if event.streaming else None, ), @@ -679,7 +681,11 @@ async def process_events( if awake_events[0].streaming: awake_events, closed_events = await Queue.wait_for_batch( awake_events, - [cast(float, fn.time_limit) - first_iteration] + # We need to wait for all of the events to have the latest input data + # the max time is the time limit of the function or 30 seconds (arbitrary) but should + # never really take that long to make a request from the client to the server unless + # the client disconnected. + [cast(float, fn.time_limit or 30) - first_iteration] * len(awake_events), ) for closed_event in closed_events: diff --git a/gradio/routes.py b/gradio/routes.py index f9beda359c9c4..66272e646bc28 100644 --- a/gradio/routes.py +++ b/gradio/routes.py @@ -274,11 +274,31 @@ async def proxy_to_node( request.method, httpx.URL(url), headers=headers ) node_response = await App.client.send(new_request) + content = node_response.content + user_agent = request.headers.get("user-agent", "").lower() + is_safari = ( + "safari" in user_agent + and "chrome" not in user_agent + and "chromium" not in user_agent + ) + response_headers = {} + if is_safari: + response_headers = { + "Access-Control-Allow-Origin": "*", + "Cross-Origin-Opener-Policy": "same-origin", + "Cross-Origin-Embedder-Policy": "require-corp", + } + if request.url.path.endswith(".js"): + response_headers["Content-Type"] = ( + "application/javascript; charset=utf-8" + ) + elif request.url.path.endswith(".css"): + response_headers["Content-Type"] = "text/css; charset=utf-8" return Response( - content=node_response.content, + content=content, status_code=node_response.status_code, - headers=dict(node_response.headers), + headers=response_headers if is_safari else node_response.headers, ) def configure_app(self, blocks: gradio.Blocks) -> None: diff --git a/gradio/utils.py b/gradio/utils.py index 2778b30385497..e38c21a703d4f 100644 --- a/gradio/utils.py +++ b/gradio/utils.py @@ -136,6 +136,7 @@ def __init__( watch_dirs: list[str], watch_module_name: str, demo_file: str, + watch_module: ModuleType, stop_event: threading.Event, demo_name: str = "demo", ) -> None: @@ -146,6 +147,7 @@ def __init__( self.stop_event = stop_event self.demo_name = demo_name self.demo_file = Path(demo_file) + self.watch_module = watch_module @property def running_app(self) -> App: @@ -195,9 +197,22 @@ def _is_gr_no_reload(expr: ast.AST) -> bool: and expr.test.attr == "NO_RELOAD" ) + def _is_if_name_main(expr: ast.AST) -> bool: + """Find the if __name__ == '__main__': block.""" + return ( + isinstance(expr, ast.If) + and isinstance(expr.test, ast.Compare) + and isinstance(expr.test.left, ast.Name) + and expr.test.left.id == "__name__" + and len(expr.test.ops) == 1 + and isinstance(expr.test.ops[0], ast.Eq) + and isinstance(expr.test.comparators[0], ast.Constant) + and expr.test.comparators[0].s == "__main__" + ) + # Find the positions of the code blocks to load for node in ast.walk(tree): - if _is_gr_no_reload(node): + if _is_gr_no_reload(node) or _is_if_name_main(node): assert isinstance(node, ast.If) # noqa: S101 node.body = [ast.Pass(lineno=node.lineno, col_offset=node.col_offset)] @@ -259,7 +274,11 @@ def iter_py_files() -> Iterator[Path]: mtimes = {} # Need to import the module in this thread so that the # module is available in the namespace of this thread - module = importlib.import_module(reloader.watch_module_name) + module = reloader.watch_module + no_reload_source_code = _remove_no_reload_codeblocks(str(reloader.demo_file)) + exec(no_reload_source_code, module.__dict__) + sys.modules[reloader.watch_module_name] = module + while reloader.should_watch(): changed = get_changes() if changed: diff --git a/guides/03_building-with-blocks/03_state-in-blocks.md b/guides/03_building-with-blocks/03_state-in-blocks.md index 6b56b7041ece4..b24c4ff0b3848 100644 --- a/guides/03_building-with-blocks/03_state-in-blocks.md +++ b/guides/03_building-with-blocks/03_state-in-blocks.md @@ -31,3 +31,15 @@ The `.change` listener for a state variable triggers after any event listener ch The value of a session State variable is cleared when the user refreshes the page. The value is stored on in the app backend for 60 minutes after the user closes the tab (this can be configured by the `delete_cache` parameter in `gr.Blocks`). Learn more about `State` in the [docs](https://gradio.app/docs/gradio/state). + +## Local State + +Gradio also supports **local state**, where data persists in the browser's localStorage even after the page is refreshed or closed. This is useful for storing user preferences, settings, API keys, or other data that should persist across sessions. To use local state: + +1. Create a `gr.BrowserState()` object. You can optionally provide an initial default value and a key to identify the data in the browser's localStorage. +2. Use it like a regular `gr.State` component in event listeners as inputs and outputs. + +Here's a simple example that saves a user's username and password across sessions: + +$code_browserstate + diff --git a/guides/07_streaming/05_real-time-speech-recognition.md b/guides/07_streaming/05_real-time-speech-recognition.md index d0b2816344297..c3bdcbc9441a9 100644 --- a/guides/07_streaming/05_real-time-speech-recognition.md +++ b/guides/07_streaming/05_real-time-speech-recognition.md @@ -57,6 +57,8 @@ To make this a *streaming* demo, we need to make these changes: 2. Set `live=True` in the `Interface` 3. Add a `state` to the interface to store the recorded audio of a user +Tip: You can also set `time_limit` and `stream_every` parameters in the interface. The `time_limit` caps the amount of time each user's stream can take. The default is 30 seconds so users won't be able to stream audio for more than 30 seconds. The `stream_every` parameter controls how frequently data is sent to your function. By default it is 0.5 seconds. + Take a look below. $code_stream_asr diff --git a/guides/07_streaming/06_automatic-voice-detection.md b/guides/07_streaming/06_automatic-voice-detection.md new file mode 100644 index 0000000000000..622fe7e205f7c --- /dev/null +++ b/guides/07_streaming/06_automatic-voice-detection.md @@ -0,0 +1,259 @@ +# Multimodal Gradio App Powered by Groq with Automatic Speech Detection + +Tags: AUDIO, STREAMING, CHATBOTS, VOICE + +## Introduction +Modern voice applications should feel natural and responsive, moving beyond the traditional "click-to-record" pattern. By combining Groq's fast inference capabilities with automatic speech detection, we can create a more intuitive interaction model where users can simply start talking whenever they want to engage with the AI. + +> Credits: VAD and Gradio code inspired by [WillHeld's Diva-audio-chat](https://huggingface.co/spaces/WillHeld/diva-audio-chat/tree/main). + +In this tutorial, you will learn how to create a multimodal Gradio and Groq app that has automatic speech detection. You can also watch the full video tutorial which includes a demo of the application: + + + +## Background + +Many voice apps currently work by the user clicking record, speaking, then stopping the recording. While this can be a powerful demo, the most natural mode of interaction with voice requires the app to dynamically detect when the user is speaking, so they can talk back and forth without having to continually click a record button. + +Creating a natural interaction with voice and text requires a dynamic and low-latency response. Thus, we need both automatic voice detection and fast inference. With @ricky0123/vad-web powering speech detection and Groq powering the LLM, both of these requirements are met. Groq provides a lightning fast response, and Gradio allows for easy creation of impressively functional apps. + +This tutorial shows you how to build a calorie tracking app where you speak to an AI that automatically detects when you start and stop your response, and provides its own text response back to guide you with questions that allow it to give a calorie estimate of your last meal. + +## Key Components + +- **Gradio**: Provides the web interface and audio handling capabilities +- **@ricky0123/vad-web**: Handles voice activity detection +- **Groq**: Powers fast LLM inference for natural conversations +- **Whisper**: Transcribes speech to text + +### Setting Up the Environment + +First, let’s install and import our essential libraries and set up a client for using the Groq API. Here’s how to do it: + +`requirements.txt` +``` +gradio +groq +numpy +soundfile +librosa +spaces +xxhash +datasets +``` + +`app.py` +```python +import groq +import gradio as gr +import soundfile as sf +from dataclasses import dataclass, field +import os + +# Initialize Groq client securely +api_key = os.environ.get("GROQ_API_KEY") +if not api_key: + raise ValueError("Please set the GROQ_API_KEY environment variable.") +client = groq.Client(api_key=api_key) +``` + +Here, we’re pulling in key libraries to interact with the Groq API, build a sleek UI with Gradio, and handle audio data. We’re accessing the Groq API key securely with a key stored in an environment variable, which is a security best practice for avoiding leaking the API key. + +--- + +### State Management for Seamless Conversations + +We need a way to keep track of our conversation history, so the chatbot remembers past interactions, and manage other states like whether recording is currently active. To do this, let’s create an `AppState` class: + +```python +@dataclass +class AppState: + conversation: list = field(default_factory=list) + stopped: bool = False + model_outs: Any = None +``` + +Our `AppState` class is a handy tool for managing conversation history and tracking whether recording is on or off. Each instance will have its own fresh list of conversations, making sure chat history is isolated to each session. + +--- + +### Transcribing Audio with Whisper on Groq + +Next, we’ll create a function to transcribe the user’s audio input into text using Whisper, a powerful transcription model hosted on Groq. This transcription will also help us determine whether there’s meaningful speech in the input. Here’s how: + +```python +def transcribe_audio(client, file_name): + if file_name is None: + return None + + try: + with open(file_name, "rb") as audio_file: + response = client.audio.transcriptions.with_raw_response.create( + model="whisper-large-v3-turbo", + file=("audio.wav", audio_file), + response_format="verbose_json", + ) + completion = process_whisper_response(response.parse()) + return completion + except Exception as e: + print(f"Error in transcription: {e}") + return f"Error in transcription: {str(e)}" +``` + +This function opens the audio file and sends it to Groq’s Whisper model for transcription, requesting detailed JSON output. verbose_json is needed to get information to determine if speech was included in the audio. We also handle any potential errors so our app doesn’t fully crash if there’s an issue with the API request. + +```python +def process_whisper_response(completion): + """ + Process Whisper transcription response and return text or null based on no_speech_prob + + Args: + completion: Whisper transcription response object + + Returns: + str or None: Transcribed text if no_speech_prob <= 0.7, otherwise None + """ + if completion.segments and len(completion.segments) > 0: + no_speech_prob = completion.segments[0].get('no_speech_prob', 0) + print("No speech prob:", no_speech_prob) + + if no_speech_prob > 0.7: + return None + + return completion.text.strip() + + return None +``` + +We also need to interpret the audio data response. The process_whisper_response function takes the resulting completion from Whisper and checks if the audio was just background noise or had actual speaking that was transcribed. It uses a threshold of 0.7 to interpret the no_speech_prob, and will return None if there was no speech. Otherwise, it will return the text transcript of the conversational response from the human. + + +--- + +### Adding Conversational Intelligence with LLM Integration + +Our chatbot needs to provide intelligent, friendly responses that flow naturally. We’ll use a Groq-hosted Llama-3.2 for this: + +```python +def generate_chat_completion(client, history): + messages = [] + messages.append( + { + "role": "system", + "content": "In conversation with the user, ask questions to estimate and provide (1) total calories, (2) protein, carbs, and fat in grams, (3) fiber and sugar content. Only ask *one question at a time*. Be conversational and natural.", + } + ) + + for message in history: + messages.append(message) + + try: + completion = client.chat.completions.create( + model="llama-3.2-11b-vision-preview", + messages=messages, + ) + return completion.choices[0].message.content + except Exception as e: + return f"Error in generating chat completion: {str(e)}" +``` + +We’re defining a system prompt to guide the chatbot’s behavior, ensuring it asks one question at a time and keeps things conversational. This setup also includes error handling to ensure the app gracefully manages any issues. + +--- + +### Voice Activity Detection for Hands-Free Interaction + +To make our chatbot hands-free, we’ll add Voice Activity Detection (VAD) to automatically detect when someone starts or stops speaking. Here’s how to implement it using ONNX in JavaScript: + +```javascript +async function main() { + const script1 = document.createElement("script"); + script1.src = "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.14.0/dist/ort.js"; + document.head.appendChild(script1) + const script2 = document.createElement("script"); + script2.onload = async () => { + console.log("vad loaded"); + var record = document.querySelector('.record-button'); + record.textContent = "Just Start Talking!" + + const myvad = await vad.MicVAD.new({ + onSpeechStart: () => { + var record = document.querySelector('.record-button'); + var player = document.querySelector('#streaming-out') + if (record != null && (player == null || player.paused)) { + record.click(); + } + }, + onSpeechEnd: (audio) => { + var stop = document.querySelector('.stop-button'); + if (stop != null) { + stop.click(); + } + } + }) + myvad.start() + } + script2.src = "https://cdn.jsdelivr.net/npm/@ricky0123/vad-web@0.0.7/dist/bundle.min.js"; +} +``` + +This script loads our VAD model and sets up functions to start and stop recording automatically. When the user starts speaking, it triggers the recording, and when they stop, it ends the recording. + +--- + +### Building a User Interface with Gradio + +Now, let’s create an intuitive and visually appealing user interface with Gradio. This interface will include an audio input for capturing voice, a chat window for displaying responses, and state management to keep things synchronized. + +```python +with gr.Blocks(theme=theme, js=js) as demo: + with gr.Row(): + input_audio = gr.Audio( + label="Input Audio", + sources=["microphone"], + type="numpy", + streaming=False, + waveform_options=gr.WaveformOptions(waveform_color="#B83A4B"), + ) + with gr.Row(): + chatbot = gr.Chatbot(label="Conversation", type="messages") + state = gr.State(value=AppState()) +``` + +In this code block, we’re using Gradio’s `Blocks` API to create an interface with an audio input, a chat display, and an application state manager. The color customization for the waveform adds a nice visual touch. + +--- + +### Handling Recording and Responses + +Finally, let’s link the recording and response components to ensure the app reacts smoothly to user inputs and provides responses in real-time. + +```python + stream = input_audio.start_recording( + process_audio, + [input_audio, state], + [input_audio, state], + ) + respond = input_audio.stop_recording( + response, [state, input_audio], [state, chatbot] + ) +``` + +These lines set up event listeners for starting and stopping the recording, processing the audio input, and generating responses. By linking these events, we create a cohesive experience where users can simply talk, and the chatbot handles the rest. + +--- + +## Summary + +1. When you open the app, the VAD system automatically initializes and starts listening for speech +2. As soon as you start talking, it triggers the recording automatically +3. When you stop speaking, the recording ends and: + - The audio is transcribed using Whisper + - The transcribed text is sent to the LLM + - The LLM generates a response about calorie tracking + - The response is displayed in the chat interface +4. This creates a natural back-and-forth conversation where you can simply talk about your meals and get instant feedback on nutritional content + +This app demonstrates how to create a natural voice interface that feels responsive and intuitive. By combining Groq's fast inference with automatic speech detection, we've eliminated the need for manual recording controls while maintaining high-quality interactions. The result is a practical calorie tracking assistant that users can simply talk to as naturally as they would to a human nutritionist. + +Link to GitHub repository: [Groq Gradio Basics](https://github.com/bklieger-groq/gradio-groq-basics/tree/main/calorie-tracker) \ No newline at end of file diff --git a/js/_spaces-test/CHANGELOG.md b/js/_spaces-test/CHANGELOG.md index 816286f006381..e1930ed479f26 100644 --- a/js/_spaces-test/CHANGELOG.md +++ b/js/_spaces-test/CHANGELOG.md @@ -4,6 +4,12 @@ ### Dependency updates +- @gradio/client@1.8.0 + +## 0.0.1 + +### Dependency updates + - @gradio/client@1.7.1 ## 0.0.1 diff --git a/js/_website/CHANGELOG.md b/js/_website/CHANGELOG.md index 40ca7f0243d7f..ca2f3d17727d9 100644 --- a/js/_website/CHANGELOG.md +++ b/js/_website/CHANGELOG.md @@ -1,5 +1,25 @@ # website +## 0.42.1 + +### Dependency updates + +- @gradio/code@0.10.8 +- @gradio/paramviewer@0.5.7 +- @gradio/tabitem@0.3.4 +- @gradio/tabs@0.3.4 + +## 0.42.0 + +### Features + +- [#9726](https://github.com/gradio-app/gradio/pull/9726) [`b6725cf`](https://github.com/gradio-app/gradio/commit/b6725cf6c1fe9667dc10e1988976ed36d84d73d3) - Lite auto-load imported modules with `pyodide.loadPackagesFromImports`. Thanks @whitphx! + +### Dependency updates + +- @gradio/code@0.10.7 +- @gradio/paramviewer@0.5.6 + ## 0.41.0 ### Features diff --git a/js/_website/package.json b/js/_website/package.json index 66b533d8b7080..a942f66ffc2bd 100644 --- a/js/_website/package.json +++ b/js/_website/package.json @@ -1,6 +1,6 @@ { "name": "website", - "version": "0.41.0", + "version": "0.42.1", "private": true, "scripts": { "dev": "pip install boto3 && python generate_jsons/generate.py && vite dev", diff --git a/js/_website/src/lib/components/DemosLite.svelte b/js/_website/src/lib/components/DemosLite.svelte index a67f5f1d2deda..8b171bc336813 100644 --- a/js/_website/src/lib/components/DemosLite.svelte +++ b/js/_website/src/lib/components/DemosLite.svelte @@ -224,7 +224,7 @@ You only return the content of \`requirements.txt\`, without any other texts or let controller: { run_code: (code: string) => Promise; install: (requirements: string[]) => Promise; - }; + } & EventTarget; function debounce( func: (...args: T) => Promise, @@ -277,6 +277,14 @@ You only return the content of \`requirements.txt\`, without any other texts or debounced_run_code = debounce(controller.run_code, debounce_timeout); debounced_install = debounce(controller.install, debounce_timeout); + controller.addEventListener("modules-auto-loaded", (event) => { + console.debug("Modules auto-loaded", event); + const packages = (event as CustomEvent).detail as { name: string }[]; + const packageNames = packages.map((pkg) => pkg.name); + selected_demo.requirements = + selected_demo.requirements.concat(packageNames); + }); + mounted = true; } catch (error) { console.error("Error loading Gradio Lite:", error); diff --git a/js/accordion/CHANGELOG.md b/js/accordion/CHANGELOG.md index 5ee332b251267..e655b2e7f626d 100644 --- a/js/accordion/CHANGELOG.md +++ b/js/accordion/CHANGELOG.md @@ -1,5 +1,26 @@ # @gradio/accordion +## 0.5.1 + +### Dependency updates + +- @gradio/atoms@0.11.1 +- @gradio/utils@0.8.0 +- @gradio/statustracker@0.9.5 +- @gradio/column@0.2.0 + +## 0.5.0 + +### Features + +- [#9875](https://github.com/gradio-app/gradio/pull/9875) [`8305ff8`](https://github.com/gradio-app/gradio/commit/8305ff8712183f27174cfb891548ad7cc1c67fed) - Adds `.expand()` and `.collapse()` events to `gr.Accordion`. Thanks @abidlabs! + +### Dependency updates + +- @gradio/statustracker@0.9.4 +- @gradio/atoms@0.11.0 +- @gradio/column@0.2.0 + ## 0.4.5 ### Dependency updates diff --git a/js/accordion/package.json b/js/accordion/package.json index 68bd9030a42ea..4766c621f8629 100644 --- a/js/accordion/package.json +++ b/js/accordion/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/accordion", - "version": "0.4.5", + "version": "0.5.1", "description": "Gradio UI packages", "type": "module", "author": "", diff --git a/js/annotatedimage/CHANGELOG.md b/js/annotatedimage/CHANGELOG.md index 75664cfd5dbd9..484a6b1928c00 100644 --- a/js/annotatedimage/CHANGELOG.md +++ b/js/annotatedimage/CHANGELOG.md @@ -1,5 +1,24 @@ # @gradio/annotatedimage +## 0.8.8 + +### Dependency updates + +- @gradio/atoms@0.11.1 +- @gradio/client@1.8.0 +- @gradio/utils@0.8.0 +- @gradio/upload@0.14.1 +- @gradio/statustracker@0.9.5 + +## 0.8.7 + +### Dependency updates + +- @gradio/statustracker@0.9.4 +- @gradio/atoms@0.11.0 +- @gradio/upload@0.14.0 +- @gradio/wasm@0.15.0 + ## 0.8.6 ### Dependency updates diff --git a/js/annotatedimage/package.json b/js/annotatedimage/package.json index a9cb74316d155..bc9c0de79e3da 100644 --- a/js/annotatedimage/package.json +++ b/js/annotatedimage/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/annotatedimage", - "version": "0.8.6", + "version": "0.8.8", "description": "Gradio UI packages", "type": "module", "author": "", diff --git a/js/app/CHANGELOG.md b/js/app/CHANGELOG.md index 1ee4b6702f466..c949f2f1e3b8e 100644 --- a/js/app/CHANGELOG.md +++ b/js/app/CHANGELOG.md @@ -1,5 +1,23 @@ # @self/app +## 1.44.0 + +### Features + +- [#9950](https://github.com/gradio-app/gradio/pull/9950) [`fc06fe4`](https://github.com/gradio-app/gradio/commit/fc06fe41f015678a0545f4e5c99f6ae2704f0031) - Add ability to read and write from LocalStorage. Thanks @abidlabs! + +### Dependency updates + +- @gradio/client@1.8.0 +- @gradio/core@0.4.0 + +## 1.43.1 + +### Dependency updates + +- @gradio/wasm@0.15.0 +- @gradio/core@0.3.0 + ## 1.43.0 ### Features diff --git a/js/app/package.json b/js/app/package.json index 8d16ca65f8bc8..2dbf3d565c86e 100644 --- a/js/app/package.json +++ b/js/app/package.json @@ -1,6 +1,6 @@ { "name": "@self/app", - "version": "1.43.0", + "version": "1.44.0", "private": true, "scripts": { "dev": "vite dev", diff --git a/js/atoms/CHANGELOG.md b/js/atoms/CHANGELOG.md index 49c1835343ff7..39f6c7e43c18b 100644 --- a/js/atoms/CHANGELOG.md +++ b/js/atoms/CHANGELOG.md @@ -1,5 +1,21 @@ # @gradio/atoms +## 0.11.1 + +### Dependency updates + +- @gradio/utils@0.8.0 + +## 0.11.0 + +### Features + +- [#9891](https://github.com/gradio-app/gradio/pull/9891) [`fc12496`](https://github.com/gradio-app/gradio/commit/fc124964a1b4922e54a4ca4755f0a536dfae1a21) - Allow uploading more files in gr.File. Thanks @hannahblair! + +### Fixes + +- [#9882](https://github.com/gradio-app/gradio/pull/9882) [`6c8a064`](https://github.com/gradio-app/gradio/commit/6c8a064feeaa89a2ffc96260032f24f18eb032fa) - Ensure non-form elements are correctly positioned when scale is applied. Thanks @hannahblair! + ## 0.10.1 ### Fixes diff --git a/js/atoms/package.json b/js/atoms/package.json index d4b7dfc890415..4f8b1bb4feca8 100644 --- a/js/atoms/package.json +++ b/js/atoms/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/atoms", - "version": "0.10.1", + "version": "0.11.1", "description": "Gradio UI packages", "type": "module", "main": "src/index.ts", diff --git a/js/atoms/src/Block.svelte b/js/atoms/src/Block.svelte index d77331241f115..2190d033db77f 100644 --- a/js/atoms/src/Block.svelte +++ b/js/atoms/src/Block.svelte @@ -59,6 +59,7 @@ style:flex-grow={scale} style:min-width={`calc(min(${min_width}px, 100%))`} style:border-width="var(--block-border-width)" + class:auto-margin={scale === null} > @@ -74,6 +75,9 @@ background: var(--block-background-fill); width: 100%; line-height: var(--line-sm); + } + + .auto-margin { margin-left: auto; margin-right: auto; } diff --git a/js/audio/CHANGELOG.md b/js/audio/CHANGELOG.md index 632fd13102e83..d6c11554aed89 100644 --- a/js/audio/CHANGELOG.md +++ b/js/audio/CHANGELOG.md @@ -1,5 +1,30 @@ # @gradio/audio +## 0.14.8 + +### Dependency updates + +- @gradio/atoms@0.11.1 +- @gradio/client@1.8.0 +- @gradio/utils@0.8.0 +- @gradio/button@0.3.7 +- @gradio/upload@0.14.1 +- @gradio/statustracker@0.9.5 + +## 0.14.7 + +### Fixes + +- [#9883](https://github.com/gradio-app/gradio/pull/9883) [`e10bbd2`](https://github.com/gradio-app/gradio/commit/e10bbd236f5817698f5e5ac1c14c7ec179a725b6) - Fix live interfaces for audio/image streaming. Thanks @freddyaboulton! + +### Dependency updates + +- @gradio/statustracker@0.9.4 +- @gradio/button@0.3.6 +- @gradio/atoms@0.11.0 +- @gradio/upload@0.14.0 +- @gradio/wasm@0.15.0 + ## 0.14.6 ### Dependency updates diff --git a/js/audio/interactive/InteractiveAudio.svelte b/js/audio/interactive/InteractiveAudio.svelte index 1157e5df96724..4b37e26bed9e5 100644 --- a/js/audio/interactive/InteractiveAudio.svelte +++ b/js/audio/interactive/InteractiveAudio.svelte @@ -201,7 +201,7 @@ dispatch("start_recording"); if (!inited) await prepare_audio(); header = undefined; - if (streaming) { + if (streaming && recorder.state != "recording") { recorder.start(stream_every * 1000); } } diff --git a/js/audio/package.json b/js/audio/package.json index fdf13adf3e745..0723ce07c2957 100644 --- a/js/audio/package.json +++ b/js/audio/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/audio", - "version": "0.14.6", + "version": "0.14.8", "description": "Gradio UI packages", "type": "module", "author": "", diff --git a/js/box/CHANGELOG.md b/js/box/CHANGELOG.md index 6a053709181ef..6e2a20c832318 100644 --- a/js/box/CHANGELOG.md +++ b/js/box/CHANGELOG.md @@ -1,5 +1,17 @@ # @gradio/box +## 0.2.6 + +### Dependency updates + +- @gradio/atoms@0.11.1 + +## 0.2.5 + +### Dependency updates + +- @gradio/atoms@0.11.0 + ## 0.2.4 ### Dependency updates diff --git a/js/box/package.json b/js/box/package.json index e35cb503dace0..ee98c5926fa5b 100644 --- a/js/box/package.json +++ b/js/box/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/box", - "version": "0.2.4", + "version": "0.2.6", "description": "Gradio UI packages", "type": "module", "author": "", diff --git a/js/browserstate/CHANGELOG.md b/js/browserstate/CHANGELOG.md new file mode 100644 index 0000000000000..32c66d9e9b99c --- /dev/null +++ b/js/browserstate/CHANGELOG.md @@ -0,0 +1,7 @@ +# @gradio/browserstate + +## 0.2.0 + +### Features + +- [#9950](https://github.com/gradio-app/gradio/pull/9950) [`fc06fe4`](https://github.com/gradio-app/gradio/commit/fc06fe41f015678a0545f4e5c99f6ae2704f0031) - Add ability to read and write from LocalStorage. Thanks @abidlabs! \ No newline at end of file diff --git a/js/browserstate/Index.svelte b/js/browserstate/Index.svelte new file mode 100644 index 0000000000000..caba0c450d544 --- /dev/null +++ b/js/browserstate/Index.svelte @@ -0,0 +1,51 @@ + + + diff --git a/js/browserstate/crypto.ts b/js/browserstate/crypto.ts new file mode 100644 index 0000000000000..108c8461bd3d8 --- /dev/null +++ b/js/browserstate/crypto.ts @@ -0,0 +1,28 @@ +import CryptoJS from "crypto-js"; + +export function encrypt(data: string, key: string): string { + const hashedKey = CryptoJS.SHA256(key).toString(); + const iv = CryptoJS.lib.WordArray.random(16); + const encrypted = CryptoJS.AES.encrypt(data, hashedKey, { + iv: iv, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7 + }); + + const ivString = CryptoJS.enc.Base64.stringify(iv); + const cipherString = encrypted.toString(); + return ivString + ":" + cipherString; +} + +export function decrypt(encryptedData: string, key: string): string { + const hashedKey = CryptoJS.SHA256(key).toString(); + const [ivString, cipherString] = encryptedData.split(":"); + const iv = CryptoJS.enc.Base64.parse(ivString); + const decrypted = CryptoJS.AES.decrypt(cipherString, hashedKey, { + iv: iv, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7 + }); + + return decrypted.toString(CryptoJS.enc.Utf8); +} diff --git a/js/browserstate/package.json b/js/browserstate/package.json new file mode 100644 index 0000000000000..db249f087ed75 --- /dev/null +++ b/js/browserstate/package.json @@ -0,0 +1,33 @@ +{ + "name": "@gradio/browserstate", + "version": "0.2.0", + "description": "Gradio UI packages", + "type": "module", + "author": "", + "license": "ISC", + "private": false, + "main_changeset": true, + "exports": { + ".": { + "gradio": "./Index.svelte", + "svelte": "./dist/Index.svelte", + "types": "./dist/Index.svelte.d.ts" + }, + "./package.json": "./package.json" + }, + "dependencies": { + "dequal": "^2.0.2", + "crypto-js": "^4.1.1" + }, + "peerDependencies": { + "svelte": "^4.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/gradio-app/gradio.git", + "directory": "js/state" + }, + "devDependencies": { + "@types/crypto-js": "^4.1.1" + } +} diff --git a/js/button/CHANGELOG.md b/js/button/CHANGELOG.md index d7307635fe707..e90df52e92071 100644 --- a/js/button/CHANGELOG.md +++ b/js/button/CHANGELOG.md @@ -1,5 +1,19 @@ # @gradio/button +## 0.3.7 + +### Dependency updates + +- @gradio/client@1.8.0 +- @gradio/utils@0.8.0 +- @gradio/upload@0.14.1 + +## 0.3.6 + +### Dependency updates + +- @gradio/upload@0.14.0 + ## 0.3.5 ### Dependency updates diff --git a/js/button/package.json b/js/button/package.json index c1e3cbf3ff208..b147c1119ee95 100644 --- a/js/button/package.json +++ b/js/button/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/button", - "version": "0.3.5", + "version": "0.3.7", "description": "Gradio UI packages", "type": "module", "author": "", diff --git a/js/chatbot/CHANGELOG.md b/js/chatbot/CHANGELOG.md index dae773fde3110..55af57881a17a 100644 --- a/js/chatbot/CHANGELOG.md +++ b/js/chatbot/CHANGELOG.md @@ -1,5 +1,40 @@ # @gradio/chatbot +## 0.16.3 + +### Fixes + +- [#9905](https://github.com/gradio-app/gradio/pull/9905) [`08f4b8b`](https://github.com/gradio-app/gradio/commit/08f4b8b000702456e04fac70961a4fbe0058f11c) - Add `allow_file_downloads` param to allow downloading image/video/audio media in chatbot. Thanks @hannahblair! + +### Dependency updates + +- @gradio/video@0.11.8 +- @gradio/atoms@0.11.1 +- @gradio/client@1.8.0 +- @gradio/utils@0.8.0 +- @gradio/upload@0.14.1 +- @gradio/statustracker@0.9.5 +- @gradio/gallery@0.13.8 +- @gradio/plot@0.9.2 +- @gradio/image@0.16.8 + +## 0.16.2 + +### Fixes + +- [#9826](https://github.com/gradio-app/gradio/pull/9826) [`69acfeb`](https://github.com/gradio-app/gradio/commit/69acfebffd0d3479a40352de19c8763863557428) - Make sure the Tool accordion is closed if it is not the last message. Thanks @freddyaboulton! + +### Dependency updates + +- @gradio/video@0.11.7 +- @gradio/statustracker@0.9.4 +- @gradio/atoms@0.11.0 +- @gradio/upload@0.14.0 +- @gradio/wasm@0.15.0 +- @gradio/image@0.16.7 +- @gradio/gallery@0.13.7 +- @gradio/plot@0.9.1 + ## 0.16.1 ### Fixes diff --git a/js/chatbot/Chatbot.stories.svelte b/js/chatbot/Chatbot.stories.svelte index 01828fa37724b..df7b6e90b5cf5 100644 --- a/js/chatbot/Chatbot.stories.svelte +++ b/js/chatbot/Chatbot.stories.svelte @@ -58,7 +58,7 @@ - - - - diff --git a/js/chatbot/Index.svelte b/js/chatbot/Index.svelte index c9373fb589a57..1f56d46549cdf 100644 --- a/js/chatbot/Index.svelte +++ b/js/chatbot/Index.svelte @@ -79,6 +79,7 @@ export let placeholder: string | null = null; export let examples: ExampleMessage[] | null = null; export let theme_mode: "system" | "light" | "dark"; + export let allow_file_downloads = true; diff --git a/js/chatbot/package.json b/js/chatbot/package.json index f8595c6583121..6f30a0608b9dc 100644 --- a/js/chatbot/package.json +++ b/js/chatbot/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/chatbot", - "version": "0.16.1", + "version": "0.16.3", "description": "Gradio UI packages", "type": "module", "author": "", diff --git a/js/chatbot/shared/ButtonPanel.svelte b/js/chatbot/shared/ButtonPanel.svelte index d6077ad83e7aa..9e029e2cfd580 100644 --- a/js/chatbot/shared/ButtonPanel.svelte +++ b/js/chatbot/shared/ButtonPanel.svelte @@ -13,7 +13,6 @@ export let show_retry: boolean; export let show_undo: boolean; export let show_copy_button: boolean; - export let show: boolean; export let message: NormalisedMessage | NormalisedMessage[]; export let position: "right" | "left"; export let avatar: FileData | null; @@ -48,7 +47,7 @@ message.content.value?.url; -{#if show} +{#if show_copy || show_retry || show_undo || likeable}
{/if} - {#if show_download && !Array.isArray(message) && is_component_message(message)} - - - - {/if} {#if show_retry} > = {}; @@ -292,6 +300,14 @@ on:click={() => (is_image_preview_open = false)} label={"Clear"} /> + {#if allow_file_downloads} + + + + {/if}
{/if} @@ -326,6 +342,7 @@ {show_copy_button} handle_action={(selected) => handle_like(i, messages[0], selected)} scroll={is_browser ? scroll : () => {}} + {allow_file_downloads} /> {/each} {#if pending_message} diff --git a/js/chatbot/shared/Component.svelte b/js/chatbot/shared/Component.svelte index 31d248fddc4b2..02b4e4f095524 100644 --- a/js/chatbot/shared/Component.svelte +++ b/js/chatbot/shared/Component.svelte @@ -8,6 +8,7 @@ export let i18n; export let upload; export let _fetch; + export let allow_file_downloads: boolean; {#if type === "gallery"} @@ -45,7 +46,7 @@ label="" waveform_settings={{}} waveform_options={{}} - show_download_button={false} + show_download_button={allow_file_downloads} on:load /> {:else if type === "video"} @@ -57,7 +58,7 @@ show_share_button={true} {i18n} {upload} - show_download_button={false} + show_download_button={allow_file_downloads} on:load > @@ -68,7 +69,7 @@ {value} show_label={false} label="chatbot-image" - show_download_button={false} + show_download_button={allow_file_downloads} on:load {i18n} /> diff --git a/js/chatbot/shared/Message.svelte b/js/chatbot/shared/Message.svelte index 8717a773468dc..d52be16e17bc5 100644 --- a/js/chatbot/shared/Message.svelte +++ b/js/chatbot/shared/Message.svelte @@ -44,6 +44,7 @@ export let msg_format: "tuples" | "messages"; export let handle_action: (selected: string | null) => void; export let scroll: () => void; + export let allow_file_downloads: boolean; function handle_select(i: number, message: NormalisedMessage): void { dispatch("select", { @@ -71,7 +72,6 @@ } type ButtonPanelProps = { - show: boolean; handle_action: (selected: string | null) => void; likeable: boolean; show_retry: boolean; @@ -86,7 +86,6 @@ let button_panel_props: ButtonPanelProps; $: button_panel_props = { - show: show_like || show_retry || show_undo || show_copy_button, handle_action, likeable: show_like, show_retry, @@ -147,11 +146,23 @@ aria-label={role + "'s message: " + get_message_label_data(message)} > {#if message.type === "text"} - {#if message.metadata.title} - +
+ {#if message.metadata.title} + + + + {:else} - - {:else} - - {/if} + {/if} +
{:else if message.type === "component" && message.content.component in _components} scroll()} + {allow_file_downloads} /> {:else if message.type === "component" && message.content.component === "file"} import("@gradio/imageeditor"), json: () => import("@gradio/json"), label: () => import("@gradio/label"), + browserstate: () => import("@gradio/browserstate"), markdown: () => import("@gradio/markdown"), model3d: () => import("@gradio/model3d"), multimodaltextbox: () => import("@gradio/multimodaltextbox"), diff --git a/js/core/CHANGELOG.md b/js/core/CHANGELOG.md index b272bee3f23d4..97ad2e8bfebeb 100644 --- a/js/core/CHANGELOG.md +++ b/js/core/CHANGELOG.md @@ -1,5 +1,56 @@ # @gradio/core +## 0.4.0 + +### Features + +- [#9950](https://github.com/gradio-app/gradio/pull/9950) [`fc06fe4`](https://github.com/gradio-app/gradio/commit/fc06fe41f015678a0545f4e5c99f6ae2704f0031) - Add ability to read and write from LocalStorage. Thanks @abidlabs! + +### Dependency updates + +- @gradio/video@0.11.8 +- @gradio/atoms@0.11.1 +- @gradio/code@0.10.8 +- @gradio/paramviewer@0.5.7 +- @gradio/tabitem@0.3.4 +- @gradio/tabs@0.3.4 +- @gradio/client@1.8.0 +- @gradio/utils@0.8.0 +- @gradio/button@0.3.7 +- @gradio/upload@0.14.1 +- @gradio/statustracker@0.9.5 +- @gradio/gallery@0.13.8 +- @gradio/plot@0.9.2 +- @gradio/image@0.16.8 +- @gradio/file@0.11.1 +- @gradio/checkbox@0.4.7 +- @gradio/textbox@0.8.6 +- @gradio/column@0.2.0 + +## 0.3.0 + +### Features + +- [#9786](https://github.com/gradio-app/gradio/pull/9786) [`f109497`](https://github.com/gradio-app/gradio/commit/f109497e8281b3429b58e3f6a293dd63ebcc08af) - Fix frontend errors on ApiDocs and RecordingSnippet. Thanks @whitphx! + +### Dependency updates + +- @gradio/code@0.10.7 +- @gradio/paramviewer@0.5.6 +- @gradio/video@0.11.7 +- @gradio/statustracker@0.9.4 +- @gradio/button@0.3.6 +- @gradio/atoms@0.11.0 +- @gradio/column@0.2.0 +- @gradio/file@0.11.0 +- @gradio/upload@0.14.0 +- @gradio/checkbox@0.4.6 +- @gradio/wasm@0.15.0 +- @gradio/image@0.16.7 +- @gradio/gallery@0.13.7 +- @gradio/plot@0.9.1 +- @gradio/textbox@0.8.5 + ## 0.2.1 ### Dependency updates diff --git a/js/core/package.json b/js/core/package.json index 0e3a0e78c9a8d..1d17b7dfdca9d 100644 --- a/js/core/package.json +++ b/js/core/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/core", - "version": "0.2.1", + "version": "0.4.0", "type": "module", "devDependencies": { "@gradio/accordion": "workspace:^", @@ -34,6 +34,7 @@ "@gradio/imageeditor": "workspace:^", "@gradio/json": "workspace:^", "@gradio/label": "workspace:^", + "@gradio/browserstate": "workspace:^", "@gradio/markdown": "workspace:^", "@gradio/model3d": "workspace:^", "@gradio/multimodaltextbox": "workspace:^", diff --git a/js/dataframe/CHANGELOG.md b/js/dataframe/CHANGELOG.md index 0bb0eeee9e91d..ecd99522ed197 100644 --- a/js/dataframe/CHANGELOG.md +++ b/js/dataframe/CHANGELOG.md @@ -1,5 +1,33 @@ # @gradio/dataframe +## 0.12.3 + +### Fixes + +- [#9949](https://github.com/gradio-app/gradio/pull/9949) [`cfb62bf`](https://github.com/gradio-app/gradio/commit/cfb62bfdb52d88295f27287f788fca977e37ae6d) - Allow dataframe column content to wrap. Thanks @hannahblair! + +### Dependency updates + +- @gradio/atoms@0.11.1 +- @gradio/client@1.8.0 +- @gradio/utils@0.8.0 +- @gradio/button@0.3.7 +- @gradio/upload@0.14.1 +- @gradio/statustracker@0.9.5 + +## 0.12.2 + +### Fixes + +- [#9892](https://github.com/gradio-app/gradio/pull/9892) [`7d77024`](https://github.com/gradio-app/gradio/commit/7d77024cb8f9cfd39a6468de9534e58dcfa69f49) - Fix dataframe height increasing on scroll. Thanks @abidlabs! + +### Dependency updates + +- @gradio/statustracker@0.9.4 +- @gradio/button@0.3.6 +- @gradio/atoms@0.11.0 +- @gradio/upload@0.14.0 + ## 0.12.1 ### Features diff --git a/js/dataframe/package.json b/js/dataframe/package.json index 59170fb957cfe..f65d9bf5deba3 100644 --- a/js/dataframe/package.json +++ b/js/dataframe/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/dataframe", - "version": "0.12.1", + "version": "0.12.3", "description": "Gradio UI packages", "type": "module", "author": "", diff --git a/js/dataframe/shared/Table.svelte b/js/dataframe/shared/Table.svelte index 91c4f6eaad527..4d91634fd6d35 100644 --- a/js/dataframe/shared/Table.svelte +++ b/js/dataframe/shared/Table.svelte @@ -1241,8 +1241,8 @@ } th .header-content { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + white-space: normal; + overflow-wrap: break-word; + word-break: break-word; } diff --git a/js/dataframe/shared/VirtualTable.svelte b/js/dataframe/shared/VirtualTable.svelte index ecc47252ef2bb..714090e791ac9 100644 --- a/js/dataframe/shared/VirtualTable.svelte +++ b/js/dataframe/shared/VirtualTable.svelte @@ -248,7 +248,6 @@ return { index: i + start, data }; }); - $: actual_height = visible.length * average_height + 10; onMount(() => { rows = contents.children as HTMLCollectionOf; mounted = true; diff --git a/js/dataset/CHANGELOG.md b/js/dataset/CHANGELOG.md index e049b47ed12e7..5a716329e2638 100644 --- a/js/dataset/CHANGELOG.md +++ b/js/dataset/CHANGELOG.md @@ -1,5 +1,23 @@ # @gradio/dataset +## 0.3.9 + +### Dependency updates + +- @gradio/atoms@0.11.1 +- @gradio/client@1.8.0 +- @gradio/utils@0.8.0 +- @gradio/upload@0.14.1 +- @gradio/textbox@0.8.6 + +## 0.3.8 + +### Dependency updates + +- @gradio/atoms@0.11.0 +- @gradio/upload@0.14.0 +- @gradio/textbox@0.8.5 + ## 0.3.7 ### Dependency updates diff --git a/js/dataset/package.json b/js/dataset/package.json index 9cd3ddd46861d..dd2f94a8b06b4 100644 --- a/js/dataset/package.json +++ b/js/dataset/package.json @@ -1,6 +1,6 @@ { "name": "@gradio/dataset", - "version": "0.3.7", + "version": "0.3.9", "description": "Gradio UI packages", "type": "module", "author": "", diff --git a/js/datetime/CHANGELOG.md b/js/datetime/CHANGELOG.md index eaddc217e2342..99b11f073245b 100644 --- a/js/datetime/CHANGELOG.md +++ b/js/datetime/CHANGELOG.md @@ -1,5 +1,24 @@ # @gradio/datetime +## 0.2.7 + +### Fixes + +- [#9897](https://github.com/gradio-app/gradio/pull/9897) [`c0cf80b`](https://github.com/gradio-app/gradio/commit/c0cf80bddd99ad0f836e618cc3d2b13e73cb5611) - Allow datetime value to be null. Thanks @hannahblair! + +### Dependency updates + +- @gradio/atoms@0.11.1 +- @gradio/utils@0.8.0 +- @gradio/statustracker@0.9.5 + +## 0.2.6 + +### Dependency updates + +- @gradio/statustracker@0.9.4 +- @gradio/atoms@0.11.0 + ## 0.2.5 ### Fixes diff --git a/js/datetime/Index.svelte b/js/datetime/Index.svelte index 040ab49e27a8f..d4630456c06bc 100644 --- a/js/datetime/Index.svelte +++ b/js/datetime/Index.svelte @@ -5,7 +5,7 @@ @@ -290,28 +315,30 @@ {/if}
- - + {#if !disabled && !(file_count === "single" && value.files.length > 0)} + + + {/if}