diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b218b454c..e61f40722a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,7 @@ By [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3165](https://github. * Fixes `gr.utils.delete_none` to only remove props whose values are `None` from the config by [@abidlabs](https://github.com/abidlabs) in [PR 3188](https://github.com/gradio-app/gradio/pull/3188) * Fix bug where embedded demos were not loading files properly by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3177](https://github.com/gradio-app/gradio/pull/3177) * The `change` event is now triggered when users click the 'Clear All' button of the multiselect DropDown component by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3195](https://github.com/gradio-app/gradio/pull/3195) +* Stops File component from freezing when a large file is uploaded by [@aliabid94](https://github.com/aliabid94) in [PR 3191](https://github.com/gradio-app/gradio/pull/3191) * Support Chinese pinyin in Dataframe by [@aliabid94](https://github.com/aliabid94) in [PR 3206](https://github.com/gradio-app/gradio/pull/3206) * The `clear` event is now triggered when images are cleared by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3218](https://github.com/gradio-app/gradio/pull/3218) * Fix bug where auth cookies where not sent when connecting to an app via http by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3223](https://github.com/gradio-app/gradio/pull/3223) diff --git a/demo/zip_files/.gitignore b/demo/zip_files/.gitignore new file mode 100644 index 0000000000..8e9b8f2027 --- /dev/null +++ b/demo/zip_files/.gitignore @@ -0,0 +1 @@ +tmp.zip \ No newline at end of file diff --git a/demo/zip_files/run.ipynb b/demo/zip_files/run.ipynb index f8f70a15cb..21810513c7 100644 --- a/demo/zip_files/run.ipynb +++ b/demo/zip_files/run.ipynb @@ -1 +1 @@ -{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: zip_files"]}, {"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": ["# Downloading files from the demo repo\n", "import os\n", "os.mkdir('files')\n", "!wget -q -O files/titanic.csv https://github.com/gradio-app/gradio/raw/main/demo/zip_files/files/titanic.csv\n", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/zip_files/tmp.zip"]}, {"cell_type": "code", "execution_count": null, "id": 44380577570523278879349135829904343037, "metadata": {}, "outputs": [], "source": ["import os\n", "from zipfile import ZipFile\n", "\n", "import gradio as gr\n", "\n", "\n", "def zip_files(files):\n", " with ZipFile(\"tmp.zip\", \"w\") as zipObj:\n", " for idx, file in enumerate(files):\n", " zipObj.write(file.name, \"file\" + str(idx))\n", " return \"tmp.zip\"\n", "\n", "demo = gr.Interface(\n", " zip_files,\n", " gr.File(file_count=\"multiple\", file_types=[\"text\", \".json\", \".csv\"]),\n", " \"file\",\n", " examples=[[[os.path.join(os.path.abspath(''),\"files/titanic.csv\"), \n", " os.path.join(os.path.abspath(''),\"files/titanic.csv\"), \n", " os.path.join(os.path.abspath(''),\"files/titanic.csv\")]]], \n", " cache_examples=True\n", ")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} \ No newline at end of file +{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: zip_files"]}, {"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": ["# Downloading files from the demo repo\n", "import os\n", "os.mkdir('files')\n", "!wget -q -O files/titanic.csv https://github.com/gradio-app/gradio/raw/main/demo/zip_files/files/titanic.csv"]}, {"cell_type": "code", "execution_count": null, "id": 44380577570523278879349135829904343037, "metadata": {}, "outputs": [], "source": ["import os\n", "from zipfile import ZipFile\n", "\n", "import gradio as gr\n", "\n", "\n", "def zip_files(files):\n", " with ZipFile(\"tmp.zip\", \"w\") as zipObj:\n", " for idx, file in enumerate(files):\n", " zipObj.write(file.name, file.name.split(\"/\")[-1])\n", " return \"tmp.zip\"\n", "\n", "demo = gr.Interface(\n", " zip_files,\n", " gr.File(file_count=\"multiple\", file_types=[\"text\", \".json\", \".csv\"]),\n", " \"file\",\n", " examples=[[[os.path.join(os.path.abspath(''),\"files/titanic.csv\"), \n", " os.path.join(os.path.abspath(''),\"files/titanic.csv\"), \n", " os.path.join(os.path.abspath(''),\"files/titanic.csv\")]]], \n", " cache_examples=True\n", ")\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/zip_files/run.py b/demo/zip_files/run.py index 191bf4aab4..1ae6436c67 100644 --- a/demo/zip_files/run.py +++ b/demo/zip_files/run.py @@ -7,7 +7,7 @@ import gradio as gr def zip_files(files): with ZipFile("tmp.zip", "w") as zipObj: for idx, file in enumerate(files): - zipObj.write(file.name, "file" + str(idx)) + zipObj.write(file.name, file.name.split("/")[-1]) return "tmp.zip" demo = gr.Interface( diff --git a/demo/zip_files/tmp.zip b/demo/zip_files/tmp.zip deleted file mode 100644 index c98df4f931..0000000000 Binary files a/demo/zip_files/tmp.zip and /dev/null differ diff --git a/gradio/processing_utils.py b/gradio/processing_utils.py index e228d96b2f..7837d9628c 100644 --- a/gradio/processing_utils.py +++ b/gradio/processing_utils.py @@ -15,8 +15,10 @@ from io import BytesIO from pathlib import Path from typing import Dict, Set, Tuple +import aiofiles import numpy as np import requests +from fastapi import UploadFile from ffmpy import FFmpeg, FFprobe, FFRuntimeError from PIL import Image, ImageOps, PngImagePlugin @@ -403,6 +405,19 @@ class TempFileManager: self.temp_files.add(full_temp_file_path) return full_temp_file_path + async def save_uploaded_file(self, file: UploadFile, upload_dir: str) -> str: + prefix, extension = self.get_prefix_and_extension(file.filename) + output_file_obj = tempfile.NamedTemporaryFile( + delete=False, dir=upload_dir, suffix=f"{extension}", prefix=f"{prefix}_" + ) + async with aiofiles.open(output_file_obj.name, "wb") as output_file: + while True: + content = await file.read(100 * 1024 * 1024) + if not content: + break + await output_file.write(content) + return str(utils.abspath(output_file_obj.name)) + def download_temp_copy_if_needed(self, url: str) -> str: """Downloads a file and makes a temporary file path for a copy if does not already exist. Otherwise returns the path to the existing temp file.""" diff --git a/gradio/routes.py b/gradio/routes.py index 5d3fe1ad85..ccb1453d0c 100644 --- a/gradio/routes.py +++ b/gradio/routes.py @@ -10,6 +10,7 @@ import mimetypes import os import posixpath import secrets +import tempfile import traceback from collections import defaultdict from copy import deepcopy @@ -21,7 +22,7 @@ import httpx import markupsafe import orjson import pkg_resources -from fastapi import Depends, FastAPI, HTTPException, WebSocket, status +from fastapi import Depends, FastAPI, File, HTTPException, UploadFile, WebSocket, status from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import ( FileResponse, @@ -43,6 +44,7 @@ from gradio.context import Context from gradio.data_classes import PredictBody, ResetBody from gradio.documentation import document, set_documentation_group from gradio.exceptions import Error +from gradio.processing_utils import TempFileManager from gradio.queueing import Estimation, Event from gradio.utils import cancel_tasks, run_coro_in_background, set_task_name @@ -109,6 +111,7 @@ class App(FastAPI): self.lock = asyncio.Lock() self.queue_token = secrets.token_urlsafe(32) self.startup_events_triggered = False + self.uploaded_file_dir = str(utils.abspath(tempfile.mkdtemp())) super().__init__(**kwargs) def configure_app(self, blocks: gradio.Blocks) -> None: @@ -297,17 +300,19 @@ class App(FastAPI): ) abs_path = str(utils.abspath(path_or_url)) in_app_dir = utils.abspath(app.cwd) in utils.abspath(path_or_url).parents - created_by_app = str(utils.abspath(path_or_url)) in set().union( - *blocks.temp_file_sets - ) + created_by_app = abs_path in set().union(*blocks.temp_file_sets) in_file_dir = any( ( utils.abspath(dir) in utils.abspath(path_or_url).parents for dir in blocks.file_directories ) ) + was_uploaded = ( + utils.abspath(app.uploaded_file_dir) + in utils.abspath(path_or_url).parents + ) - if in_app_dir or created_by_app or in_file_dir: + if in_app_dir or created_by_app or in_file_dir or was_uploaded: range_val = request.headers.get("Range", "").strip() if range_val.startswith("bytes=") and "-" in range_val: range_val = range_val[6:] @@ -514,6 +519,20 @@ class App(FastAPI): async def get_queue_status(): return app.get_blocks()._queue.get_estimation() + @app.post("/upload", dependencies=[Depends(login_check)]) + async def upload_file( + files: List[UploadFile] = File(...), + ): + output_files = [] + file_manager = TempFileManager() + for input_file in files: + output_files.append( + await file_manager.save_uploaded_file( + input_file, app.uploaded_file_dir + ) + ) + return output_files + @app.on_event("startup") @app.get("/startup-events") async def startup_events(): diff --git a/test/test_files/alphabet.txt b/test/test_files/alphabet.txt new file mode 100644 index 0000000000..e85d5b4528 --- /dev/null +++ b/test/test_files/alphabet.txt @@ -0,0 +1 @@ +abcdefghijklmnopqrstuvwxyz \ No newline at end of file diff --git a/test/test_routes.py b/test/test_routes.py index 8934113f6e..23858cf07f 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -54,6 +54,17 @@ class TestRoutes: response = test_client.get("/config/") assert response.status_code == 200 + def test_upload_route(self, test_client): + response = test_client.post( + "/upload", files={"files": open("test/test_files/alphabet.txt", "r")} + ) + assert response.status_code == 200 + file = response.json()[0] + assert "alphabet" in file + assert file.endswith(".txt") + with open(file) as saved_file: + assert saved_file.read() == "abcdefghijklmnopqrstuvwxyz" + def test_predict_route(self, test_client): response = test_client.post( "/api/predict/", json={"data": ["test"], "fn_index": 0} diff --git a/ui/packages/app/src/api.ts b/ui/packages/app/src/api.ts index ce7605d900..1d27a28745 100644 --- a/ui/packages/app/src/api.ts +++ b/ui/packages/app/src/api.ts @@ -36,6 +36,10 @@ interface PostResponse { error?: string; [x: string]: any; } +export interface UploadResponse { + error?: string; + files?: Array; +} const QUEUE_FULL_MSG = "This application is too busy. Keep trying!"; const BROKEN_CONNECTION_MSG = "Connection errored out."; @@ -55,6 +59,27 @@ export async function post_data( const output: PostResponse = await response.json(); return [output, response.status]; } + +export async function upload_files( + root: string, + files: Array +): Promise { + const formData = new FormData(); + files.forEach((file) => { + formData.append("files", file); + }); + try { + var response = await fetch(`${root}upload`, { + method: "POST", + body: formData + }); + } catch (e) { + return { error: BROKEN_CONNECTION_MSG }; + } + const output: UploadResponse["files"] = await response.json(); + return { files: output }; +} + interface UpdateOutput { __type__: string; [key: string]: unknown; diff --git a/ui/packages/app/src/components/Dataset/ExampleComponents/File.svelte b/ui/packages/app/src/components/Dataset/ExampleComponents/File.svelte index 4ea8f985cc..79d869a605 100644 --- a/ui/packages/app/src/components/Dataset/ExampleComponents/File.svelte +++ b/ui/packages/app/src/components/Dataset/ExampleComponents/File.svelte @@ -1,5 +1,5 @@ @@ -51,7 +88,12 @@ padding={false} {elem_id} > - + {#if mode === "dynamic"} {:else} - + {/if} diff --git a/ui/packages/app/src/components/File/types.ts b/ui/packages/app/src/components/File/types.ts deleted file mode 100644 index 97f5abcdc2..0000000000 --- a/ui/packages/app/src/components/File/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface FileData { - name: string; - size: number; - data: string; - is_example: false; -} diff --git a/ui/packages/app/src/components/UploadButton/UploadButton.svelte b/ui/packages/app/src/components/UploadButton/UploadButton.svelte index bd6e391070..5b60a04b64 100644 --- a/ui/packages/app/src/components/UploadButton/UploadButton.svelte +++ b/ui/packages/app/src/components/UploadButton/UploadButton.svelte @@ -3,21 +3,34 @@ import type { Styles } from "@gradio/utils"; import type { FileData } from "@gradio/upload"; import { UploadButton } from "@gradio/upload-button"; + import { upload_files } from "../../api"; + import { blobToBase64 } from "@gradio/upload"; import { _ } from "svelte-i18n"; export let style: Styles = {}; export let elem_id: string = ""; export let visible: boolean = true; export let label: string; - export let value: null | FileData | Array; + export let value: null | FileData; export let file_count: string; export let file_types: Array = ["file"]; + export let root: string; async function handle_upload({ detail }: CustomEvent) { value = detail; + console.log(detail); await tick(); - dispatch("change", value); - dispatch("upload", detail); + upload_files(root, [detail.blob!]).then(async (response) => { + if (response.error) { + detail.data = await blobToBase64(detail.blob!); + } else { + detail.orig_name = detail.name; + detail.name = response.files![0]; + detail.is_file = true; + } + dispatch("change", value); + dispatch("upload", detail); + }); } const dispatch = createEventDispatcher<{ diff --git a/ui/packages/file/src/File.svelte b/ui/packages/file/src/File.svelte index fc8440a17f..4befa7a401 100644 --- a/ui/packages/file/src/File.svelte +++ b/ui/packages/file/src/File.svelte @@ -21,6 +21,6 @@ diff --git a/ui/packages/file/src/FilePreview.svelte b/ui/packages/file/src/FilePreview.svelte index 6c0e6edeb8..c3d9a13fd9 100644 --- a/ui/packages/file/src/FilePreview.svelte +++ b/ui/packages/file/src/FilePreview.svelte @@ -2,11 +2,7 @@ import type { FileData } from "@gradio/upload"; import { Download } from "@gradio/icons"; import { IconButton } from "@gradio/atoms"; - import { - display_file_name, - download_files, - display_file_size - } from "./utils"; + import { display_file_name, display_file_size } from "./utils"; export let value: FileData | FileData[]; @@ -24,13 +20,19 @@ - - Download - + {#if file.data} + + Download + + {:else} + Uploading... + {/if} {/each} @@ -52,7 +54,7 @@ margin-bottom: var(--size-7); width: var(--size-full); max-height: var(--size-60); - overflow-y: scroll; + overflow-y: auto; color: var(--color-text-body); } .file { diff --git a/ui/packages/file/src/FileUpload.svelte b/ui/packages/file/src/FileUpload.svelte index 0f195e6c05..2089245444 100644 --- a/ui/packages/file/src/FileUpload.svelte +++ b/ui/packages/file/src/FileUpload.svelte @@ -14,7 +14,9 @@ export let file_count: string = "single"; export let file_types: string[] | null = null; - async function handle_upload({ detail }: CustomEvent) { + async function handle_upload({ + detail + }: CustomEvent>) { value = detail; await tick(); dispatch("change", value); @@ -28,10 +30,10 @@ } const dispatch = createEventDispatcher<{ - change: FileData | null; + change: Array | FileData | null; clear: undefined; drag: boolean; - upload: FileData; + upload: Array | FileData; error: string; }>(); @@ -55,16 +57,17 @@ -{#if value === null} +{#if value} + + +{:else} -{:else} - - {/if} diff --git a/ui/packages/file/src/utils.ts b/ui/packages/file/src/utils.ts index 30401457e3..5fc7753eee 100644 --- a/ui/packages/file/src/utils.ts +++ b/ui/packages/file/src/utils.ts @@ -19,10 +19,6 @@ export const display_file_name = (value: FileData): string => { } else return str; }; -export const download_files = (value: FileData): string => { - return value.data; -}; - export const display_file_size = ( value: FileData | Array ): string => { diff --git a/ui/packages/model3D/src/Model3D.svelte b/ui/packages/model3D/src/Model3D.svelte index 430c04be31..bac77b6b17 100644 --- a/ui/packages/model3D/src/Model3D.svelte +++ b/ui/packages/model3D/src/Model3D.svelte @@ -2,7 +2,6 @@ import type { FileData } from "@gradio/upload"; import { BlockLabel, IconButton } from "@gradio/atoms"; import { File, Download } from "@gradio/icons"; - import { download_files } from "./utils"; export let value: FileData | null; export let clearColor: Array = [0, 0, 0, 0]; @@ -81,7 +80,7 @@
diff --git a/ui/packages/model3D/src/utils.ts b/ui/packages/model3D/src/utils.ts index 30401457e3..5fc7753eee 100644 --- a/ui/packages/model3D/src/utils.ts +++ b/ui/packages/model3D/src/utils.ts @@ -19,10 +19,6 @@ export const display_file_name = (value: FileData): string => { } else return str; }; -export const download_files = (value: FileData): string => { - return value.data; -}; - export const display_file_size = ( value: FileData | Array ): string => { diff --git a/ui/packages/upload-button/package.json b/ui/packages/upload-button/package.json index 75f8271093..57d56835af 100644 --- a/ui/packages/upload-button/package.json +++ b/ui/packages/upload-button/package.json @@ -9,6 +9,7 @@ "private": true, "dependencies": { "@gradio/button": "workspace:^0.0.1", - "@gradio/utils": "workspace:^0.0.1" + "@gradio/utils": "workspace:^0.0.1", + "@gradio/upload": "workspace:^0.0.1" } } diff --git a/ui/packages/upload-button/src/UploadButton.svelte b/ui/packages/upload-button/src/UploadButton.svelte index 664dde7346..f1c060a8d2 100644 --- a/ui/packages/upload-button/src/UploadButton.svelte +++ b/ui/packages/upload-button/src/UploadButton.svelte @@ -2,7 +2,7 @@ import { Button } from "@gradio/button"; import type { Styles } from "@gradio/utils"; import { createEventDispatcher } from "svelte"; - import type { FileData } from "./types"; + import type { FileData } from "@gradio/upload"; import { type } from "@testing-library/user-event/dist/type"; export let style: Styles = {}; @@ -35,33 +35,30 @@ const loadFiles = (files: FileList) => { let _files: Array = Array.from(files); - if (!files.length || !window.FileReader) { + if (!files.length) { return; } if (file_count === "single") { _files = [files[0]]; } - var all_file_data: Array = []; + var all_file_data: Array = []; _files.forEach((f, i) => { - let ReaderObj = new FileReader(); - ReaderObj.readAsDataURL(f); - ReaderObj.onloadend = function () { - all_file_data[i] = include_file_metadata - ? { - name: f.name, - size: f.size, - data: this.result as string - } - : (this.result as string); - if ( - all_file_data.filter((x) => x !== undefined).length === files.length - ) { - dispatch( - "load", - file_count == "single" ? all_file_data[0] : all_file_data - ); - } - }; + all_file_data[i] = include_file_metadata + ? { + name: f.name, + size: f.size, + data: "", + blob: f + } + : f; + if ( + all_file_data.filter((x) => x !== undefined).length === files.length + ) { + dispatch( + "load", + file_count == "single" ? all_file_data[0] : all_file_data + ); + } }); }; diff --git a/ui/packages/upload-button/src/types.ts b/ui/packages/upload-button/src/types.ts deleted file mode 100644 index d747ba8492..0000000000 --- a/ui/packages/upload-button/src/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface FileData { - name: string; - orig_name?: string; - size?: number; - data: string; - is_file?: boolean; -} diff --git a/ui/packages/upload/src/Upload.svelte b/ui/packages/upload/src/Upload.svelte index b2162734f5..1cfab91ae9 100644 --- a/ui/packages/upload/src/Upload.svelte +++ b/ui/packages/upload/src/Upload.svelte @@ -1,6 +1,7 @@ diff --git a/ui/packages/upload/src/types.ts b/ui/packages/upload/src/types.ts index d747ba8492..6c61c6a631 100644 --- a/ui/packages/upload/src/types.ts +++ b/ui/packages/upload/src/types.ts @@ -3,5 +3,6 @@ export interface FileData { orig_name?: string; size?: number; data: string; + blob?: File; is_file?: boolean; } diff --git a/ui/packages/upload/src/utils.ts b/ui/packages/upload/src/utils.ts index 7ed63c225c..5147784b5d 100644 --- a/ui/packages/upload/src/utils.ts +++ b/ui/packages/upload/src/utils.ts @@ -35,3 +35,13 @@ export function normalise_file( } return file; } + +export const blobToBase64 = (blob: File): Promise => { + const reader = new FileReader(); + reader.readAsDataURL(blob); + return new Promise((resolve) => { + reader.onloadend = () => { + resolve(reader.result as string); + }; + }); +}; diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index b45e4bbb8f..9abde11124 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: 5.4 +lockfileVersion: 5.3 importers: @@ -48,7 +48,7 @@ importers: '@tailwindcss/forms': 0.5.0_tailwindcss@3.1.6 '@testing-library/dom': 8.11.3 '@testing-library/svelte': 3.1.0_svelte@3.49.0 - '@testing-library/user-event': 13.5.0_gzufz4q333be4gqfrvipwvqt6a + '@testing-library/user-event': 13.5.0_@testing-library+dom@8.11.3 autoprefixer: 10.4.4_postcss@8.4.6 babylonjs: 5.18.0 babylonjs-loaders: 5.18.0 @@ -65,15 +65,15 @@ importers: postcss-nested: 5.0.6_postcss@8.4.6 postcss-prefix-selector: 1.16.0_postcss@8.4.6 prettier: 2.6.2 - prettier-plugin-css-order: 1.3.0_ob5okuz2s5mlecytbeo2erc43a - prettier-plugin-svelte: 2.7.0_3cyj5wbackxvw67rnaarcmbw7y + prettier-plugin-css-order: 1.3.0_postcss@8.4.6+prettier@2.6.2 + prettier-plugin-svelte: 2.7.0_prettier@2.6.2+svelte@3.49.0 sirv: 2.0.2 sirv-cli: 2.0.2 svelte: 3.49.0 - svelte-check: 2.8.0_mgmdnb6x5rpawk37gozc2sbtta + svelte-check: 2.8.0_postcss@8.4.6+svelte@3.49.0 svelte-i18n: 3.3.13_svelte@3.49.0 - svelte-preprocess: 4.10.6_mlkquajfpxs65rn6bdfntu7nmy - tailwindcss: 3.1.6_postcss@8.4.6 + svelte-preprocess: 4.10.6_62d50a01257de5eec5be08cad9d3ed66 + tailwindcss: 3.1.6 tinyspy: 0.3.0 typescript: 4.7.4 vite: 2.9.9 @@ -373,9 +373,11 @@ importers: packages/upload-button: specifiers: '@gradio/button': workspace:^0.0.1 + '@gradio/upload': workspace:^0.0.1 '@gradio/utils': workspace:^0.0.1 dependencies: '@gradio/button': link:../button + '@gradio/upload': link:../upload '@gradio/utils': link:../utils packages/utils: @@ -725,7 +727,7 @@ packages: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.1.6_postcss@8.4.6 + tailwindcss: 3.1.6 dev: false /@testing-library/dom/7.31.2: @@ -766,7 +768,7 @@ packages: svelte: 3.49.0 dev: false - /@testing-library/user-event/13.5.0_gzufz4q333be4gqfrvipwvqt6a: + /@testing-library/user-event/13.5.0_@testing-library+dom@8.11.3: resolution: {integrity: sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==} engines: {node: '>=10', npm: '>=6'} peerDependencies: @@ -2981,19 +2983,6 @@ packages: postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.1 - dev: true - - /postcss-import/14.1.0_postcss@8.4.6: - resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} - engines: {node: '>=10.0.0'} - peerDependencies: - postcss: ^8.0.0 - dependencies: - postcss: 8.4.6 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.1 - dev: false /postcss-js/4.0.0_postcss@8.4.21: resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} @@ -3003,17 +2992,6 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.21 - dev: true - - /postcss-js/4.0.0_postcss@8.4.6: - resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.3.3 - dependencies: - camelcase-css: 2.0.1 - postcss: 8.4.6 - dev: false /postcss-less/6.0.0_postcss@8.4.6: resolution: {integrity: sha512-FPX16mQLyEjLzEuuJtxA8X3ejDLNGGEG503d2YGZR5Ask1SpDN8KmZUMpzCvyalWRywAn1n1VOA5dcqfCLo5rg==} @@ -3052,24 +3030,6 @@ packages: lilconfig: 2.0.6 postcss: 8.4.21 yaml: 1.10.2 - dev: true - - /postcss-load-config/3.1.4_postcss@8.4.6: - resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} - engines: {node: '>= 10'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - dependencies: - lilconfig: 2.0.6 - postcss: 8.4.6 - yaml: 1.10.2 - dev: false /postcss-nested/5.0.6_postcss@8.4.21: resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} @@ -3079,7 +3039,6 @@ packages: dependencies: postcss: 8.4.21 postcss-selector-parser: 6.0.9 - dev: true /postcss-nested/5.0.6_postcss@8.4.6: resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} @@ -3157,7 +3116,7 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 - /prettier-plugin-css-order/1.3.0_ob5okuz2s5mlecytbeo2erc43a: + /prettier-plugin-css-order/1.3.0_postcss@8.4.6+prettier@2.6.2: resolution: {integrity: sha512-wOS4qlbUARCoiiuOG0TiB/j751soC3+gUnMMva5HVWKvHJdLNYqh+jXK3MvvixR6xkJVPxHSF7rIIhkHIuHTFg==} engines: {node: '>=14'} peerDependencies: @@ -3172,7 +3131,7 @@ packages: - postcss dev: false - /prettier-plugin-svelte/2.7.0_3cyj5wbackxvw67rnaarcmbw7y: + /prettier-plugin-svelte/2.7.0_prettier@2.6.2+svelte@3.49.0: resolution: {integrity: sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA==} peerDependencies: prettier: ^1.16.4 || ^2.0.0 @@ -3659,7 +3618,7 @@ packages: - sugarss dev: true - /svelte-check/2.8.0_mgmdnb6x5rpawk37gozc2sbtta: + /svelte-check/2.8.0_postcss@8.4.6+svelte@3.49.0: resolution: {integrity: sha512-HRL66BxffMAZusqe5I5k26mRWQ+BobGd9Rxm3onh7ZVu0nTk8YTKJ9vu3LVPjUGLU9IX7zS+jmwPVhJYdXJ8vg==} hasBin: true peerDependencies: @@ -3672,7 +3631,7 @@ packages: picocolors: 1.0.0 sade: 1.8.1 svelte: 3.49.0 - svelte-preprocess: 4.10.6_mlkquajfpxs65rn6bdfntu7nmy + svelte-preprocess: 4.10.6_62d50a01257de5eec5be08cad9d3ed66 typescript: 4.7.4 transitivePeerDependencies: - '@babel/core' @@ -3763,7 +3722,7 @@ packages: typescript: 4.5.5 dev: true - /svelte-preprocess/4.10.6_mlkquajfpxs65rn6bdfntu7nmy: + /svelte-preprocess/4.10.6_62d50a01257de5eec5be08cad9d3ed66: resolution: {integrity: sha512-I2SV1w/AveMvgIQlUF/ZOO3PYVnhxfcpNyGt8pxpUVhPfyfL/CZBkkw/KPfuFix5FJ9TnnNYMhACK3DtSaYVVQ==} engines: {node: '>= 9.11.2'} requiresBuild: true @@ -3883,40 +3842,6 @@ packages: resolve: 1.22.1 transitivePeerDependencies: - ts-node - dev: true - - /tailwindcss/3.1.6_postcss@8.4.6: - resolution: {integrity: sha512-7skAOY56erZAFQssT1xkpk+kWt2NrO45kORlxFPXUt3CiGsVPhH1smuH5XoDH6sGPXLyBv+zgCKA2HWBsgCytg==} - engines: {node: '>=12.13.0'} - hasBin: true - peerDependencies: - postcss: ^8.0.9 - dependencies: - arg: 5.0.2 - chokidar: 3.5.3 - color-name: 1.1.4 - detective: 5.2.1 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.2.11 - glob-parent: 6.0.2 - is-glob: 4.0.3 - lilconfig: 2.0.6 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.0.0 - postcss: 8.4.6 - postcss-import: 14.1.0_postcss@8.4.6 - postcss-js: 4.0.0_postcss@8.4.6 - postcss-load-config: 3.1.4_postcss@8.4.6 - postcss-nested: 5.0.6_postcss@8.4.6 - postcss-selector-parser: 6.0.10 - postcss-value-parser: 4.2.0 - quick-lru: 5.1.1 - resolve: 1.22.1 - transitivePeerDependencies: - - ts-node - dev: false /then-request/6.0.2: resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==}