From 736046f17db073b56023b5e077b0ae5ae4adeb02 Mon Sep 17 00:00:00 2001 From: Freddy Boulton Date: Thu, 19 Sep 2024 01:51:01 -0400 Subject: [PATCH] Object Detection From Webcam Stream Guide (#9336) * guides * Add demo * guide * Add info about Powershell client (#9343) * clients * add changeset --------- Co-authored-by: gradio-pr-bot * Remove lite/theme.css from the Git-managed file tree (#9335) * Delete js/lite/src/theme.css from the Git managed file tree as it's dynamically generated * Remove lite-related npm scripts from spa/package.json * add changeset --------- Co-authored-by: gradio-pr-bot * 9227 chatinterface retry bug (#9316) * first draft * add code * tip * add changeset * delete dead code * Type check notebook * consolidate like section with guide * Add comments * add value * Lint * lint * guide --------- Co-authored-by: gradio-pr-bot Co-authored-by: Abubakar Abid * Move icons into `IconButtonWrapper` (#9261) * * update icon buttons * add image editor specific icon button * tweak hover * margin tweak * add changeset * improve gr.Video button UI * radius tweak * ensure even spacing * fix typechecks * add changeset * revert irrelevant changes * typefix * fix image editor buttons * fix download link icon * disable undo if no change events dispatched in model3d and video * use icons with iconbuttonwrapper * add iconbuttonwrapper around gallery share btn * Revert "add iconbuttonwrapper around gallery share btn" This reverts commit 4605302df40bc2d1874e80ea79dc9830b0e867f6. * add changeset * design fixes * add changeset * move status tracker progress to bottom of component * add changeset * use iconbutton for like/dislike * fix lint error * fix type errors * type errors * fix test * revert undo icon change * btn spacing --------- Co-authored-by: gradio-pr-bot * Added gradio-in-r (#9340) * Added gradio-in-r * add changeset * section * remove * tweaks * delete changeset * R * Updated using-gradio-in-other-programming-languages.md --------- Co-authored-by: Abubakar Abid Co-authored-by: gradio-pr-bot * Enhance Lite E2E tests and fix a networking problem on Lite (#9333) * Add Lite E2E test to check a matplotlib problem which was fixed in https://github.com/gradio-app/gradio/pull/9312 * Restore js/app/test/image_remote_url.spec.ts, which was deleted in https://github.com/gradio-app/gradio/pull/8716 * Fix tootils import * Format * Fix processing_utils.resolve_with_google_dns to use the HTTPX client instead of urllib so it works on Lite * add changeset * add changeset * Move js/app/test/image_remote_url.spec.ts -> js/spa/test/image_remote_url.spec.ts * Use pyodide.http in resolve_with_google_dns on Lite --------- Co-authored-by: gradio-pr-bot * Do not attach `content_disposition_type = "attachment"` headers for files explicitly allowed by developer (#9348) * changes * add changeset * format * fix type * type * add test --------- Co-authored-by: gradio-pr-bot * Fix overflowing markdown in Chatbot (#9260) * fix markdown overflowing table * add changeset * revert undo icon * add changeset * Revert "revert undo icon" This reverts commit 855b012a2083cc672783d6be1bc098677ab3cbbc. * add changeset --------- Co-authored-by: gradio-pr-bot * demo name * Guide on Streaming Video for Object Detection (#9365) * Add code * notebooks * Suggestions * Add gif * Small tweak to how thoughts are shown in `gr.Chatbot` (#9359) * thiknk chat * add changeset * lint --------- Co-authored-by: gradio-pr-bot * Use `container` param in `gr.Markdown` (#9356) * * add param * add story * add changeset * Use IconButton for copy btn * fix test --------- Co-authored-by: gradio-pr-bot * small fixes (#9347) * Updated Guide: Real Time Speech Recognition (#9349) * Update real-time-speech-recognition.md added necessary dependency * Update run.py updated code to handle cases with stereo microphone * Update real-time-speech-recognition.md improved english * Update run.py updated code for streaming * Update run.py * chunk space uploads (#9360) * chunk space uploads * Update upload_demo_to_space.py Co-authored-by: Lucain * address comments + tweak CI --------- Co-authored-by: Lucain * add find (#9368) * New branch (#9369) * add find * fix syntax * New branch (#9370) * add find * fix syntax * add hidden files * run format * Testing CI (#9379) * remove unnecessary redirects * add changeset * fix * formatting --------- Co-authored-by: gradio-pr-bot * Fixes website build in 5.0-dev (#9382) * changes * add changeset --------- Co-authored-by: gradio-pr-bot * Small tweaks to improve the DX for the "tuples"/"messages" argument in `gr.Chatbot` (#9358) * change format * format * add changeset * revert * revert --------- Co-authored-by: gradio-pr-bot * Update babylon.js to `v7` for `gr.Model3D` (#9377) * update package.json * add changeset * add changeset * update pnpm lock * add changeset --------- Co-authored-by: gradio-pr-bot * Fix `gr.ImageEditor` toolbar cutoff (#9371) * fix wrap alignment * add changeset --------- Co-authored-by: gradio-pr-bot * add lite upload (#9385) * fix sha (#9386) * Fix lite ci (#9387) * fix sha * fix name * fix name * Add code * feedback * link * add changeset * code * check * Update guides/04_additional-features/02_streaming-outputs.md * Update guides/07_streaming/02_object-detection-from-webcam.md --------- Co-authored-by: Abubakar Abid Co-authored-by: gradio-pr-bot Co-authored-by: Yuichiro Tachibana (Tsuchiya) Co-authored-by: Hannah Co-authored-by: Ifeanyi Idiaye <72707830+Ifeanyi55@users.noreply.github.com> Co-authored-by: Julien Chaumond Co-authored-by: Nikita Krasnytskyi Co-authored-by: pngwn Co-authored-by: Lucain Co-authored-by: Ali Abdalla --- .changeset/floppy-nails-grab.md | 5 + demo/rt-detr-object-detection/draw_boxes.py | 45 +++++ .../rt-detr-object-detection/requirements.txt | 4 + demo/rt-detr-object-detection/run.ipynb | 1 + demo/rt-detr-object-detection/run.py | 115 +++++++++++ demo/yolov10_webcam_stream/requirements.txt | 2 + demo/yolov10_webcam_stream/run.ipynb | 1 + demo/yolov10_webcam_stream/run.py | 51 +++++ gradio/route_utils.py | 4 +- .../02_streaming-outputs.md | 8 +- .../03_streaming-inputs.md | 6 +- .../01_streaming-ai-generated-audio.md} | 0 .../02_object-detection-from-webcam.md | 93 +++++++++ .../03_object-detection-from-video.md | 181 ++++++++++++++++++ .../04_real-time-speech-recognition.md} | 0 .../01_custom-components-in-five-minutes.md | 0 .../02_key-component-concepts.md | 0 .../03_configuration.md | 0 .../04_backend.md | 0 .../05_frontend.md | 0 .../06_frequently-asked-questions.md | 0 .../07_pdf-component-example.md | 0 .../08_multimodal-chatbot-part1.md | 0 .../09_documenting-custom-components.md | 0 ..._getting-started-with-the-python-client.md | 0 .../02_getting-started-with-the-js-client.md | 0 .../03_querying-gradio-apps-with-curl.md | 0 .../04_gradio-and-llm-agents.md | 0 .../05_gradio-lite.md | 0 .../06_gradio-lite-and-transformers-js.md | 0 .../07_fastapi-app-with-the-gradio-client.md | 0 .../01_using-hugging-face-integrations.md | 0 .../Gradio-and-Comet.md | 0 .../Gradio-and-ONNX-on-Hugging-Face.md | 0 .../Gradio-and-Wandb-Integration.md | 0 .../create-your-own-friends-with-a-gan.md | 0 ...creating-a-dashboard-from-bigquery-data.md | 0 ...creating-a-dashboard-from-supabase-data.md | 0 ...a-realtime-dashboard-from-google-sheets.md | 0 .../deploying-gradio-with-docker.md | 0 .../developing-faster-with-reload-mode.md | 0 .../how-to-use-3D-model-component.md | 0 .../image-classification-in-pytorch.md | 0 .../image-classification-in-tensorflow.md | 0 ...classification-with-vision-transformers.md | 0 ...talling-gradio-in-a-virtual-environment.md | 0 .../named-entity-recognition.md | 0 .../plot-component-for-maps.md | 0 .../running-background-tasks.md | 0 ...ng-gradio-on-your-web-server-with-nginx.md | 0 ...tting-up-a-demo-for-maximum-performance.md | 0 .../styling-the-gradio-dataframe.md | 0 .../theming-guide.md | 0 .../using-flagging.md | 0 .../using-gradio-for-tabular-workflows.md | 0 ...g-gradio-in-other-programming-languages.md | 0 .../wrapping-layouts.md | 0 57 files changed, 511 insertions(+), 5 deletions(-) create mode 100644 .changeset/floppy-nails-grab.md create mode 100644 demo/rt-detr-object-detection/draw_boxes.py create mode 100644 demo/rt-detr-object-detection/requirements.txt create mode 100644 demo/rt-detr-object-detection/run.ipynb create mode 100644 demo/rt-detr-object-detection/run.py create mode 100644 demo/yolov10_webcam_stream/requirements.txt create mode 100644 demo/yolov10_webcam_stream/run.ipynb create mode 100644 demo/yolov10_webcam_stream/run.py rename guides/{09_other-tutorials/streaming-ai-generated-audio.md => 07_streaming/01_streaming-ai-generated-audio.md} (100%) create mode 100644 guides/07_streaming/02_object-detection-from-webcam.md create mode 100644 guides/07_streaming/03_object-detection-from-video.md rename guides/{09_other-tutorials/real-time-speech-recognition.md => 07_streaming/04_real-time-speech-recognition.md} (100%) rename guides/{07_custom-components => 08_custom-components}/01_custom-components-in-five-minutes.md (100%) rename guides/{07_custom-components => 08_custom-components}/02_key-component-concepts.md (100%) rename guides/{07_custom-components => 08_custom-components}/03_configuration.md (100%) rename guides/{07_custom-components => 08_custom-components}/04_backend.md (100%) rename guides/{07_custom-components => 08_custom-components}/05_frontend.md (100%) rename guides/{07_custom-components => 08_custom-components}/06_frequently-asked-questions.md (100%) rename guides/{07_custom-components => 08_custom-components}/07_pdf-component-example.md (100%) rename guides/{07_custom-components => 08_custom-components}/08_multimodal-chatbot-part1.md (100%) rename guides/{07_custom-components => 08_custom-components}/09_documenting-custom-components.md (100%) rename guides/{08_gradio-clients-and-lite => 09_gradio-clients-and-lite}/01_getting-started-with-the-python-client.md (100%) rename guides/{08_gradio-clients-and-lite => 09_gradio-clients-and-lite}/02_getting-started-with-the-js-client.md (100%) rename guides/{08_gradio-clients-and-lite => 09_gradio-clients-and-lite}/03_querying-gradio-apps-with-curl.md (100%) rename guides/{08_gradio-clients-and-lite => 09_gradio-clients-and-lite}/04_gradio-and-llm-agents.md (100%) rename guides/{08_gradio-clients-and-lite => 09_gradio-clients-and-lite}/05_gradio-lite.md (100%) rename guides/{08_gradio-clients-and-lite => 09_gradio-clients-and-lite}/06_gradio-lite-and-transformers-js.md (100%) rename guides/{08_gradio-clients-and-lite => 09_gradio-clients-and-lite}/07_fastapi-app-with-the-gradio-client.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/01_using-hugging-face-integrations.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/Gradio-and-Comet.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/Gradio-and-ONNX-on-Hugging-Face.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/Gradio-and-Wandb-Integration.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/create-your-own-friends-with-a-gan.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/creating-a-dashboard-from-bigquery-data.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/creating-a-dashboard-from-supabase-data.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/creating-a-realtime-dashboard-from-google-sheets.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/deploying-gradio-with-docker.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/developing-faster-with-reload-mode.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/how-to-use-3D-model-component.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/image-classification-in-pytorch.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/image-classification-in-tensorflow.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/image-classification-with-vision-transformers.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/installing-gradio-in-a-virtual-environment.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/named-entity-recognition.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/plot-component-for-maps.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/running-background-tasks.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/running-gradio-on-your-web-server-with-nginx.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/setting-up-a-demo-for-maximum-performance.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/styling-the-gradio-dataframe.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/theming-guide.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/using-flagging.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/using-gradio-for-tabular-workflows.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/using-gradio-in-other-programming-languages.md (100%) rename guides/{09_other-tutorials => 10_other-tutorials}/wrapping-layouts.md (100%) diff --git a/.changeset/floppy-nails-grab.md b/.changeset/floppy-nails-grab.md new file mode 100644 index 0000000000000..b59772a49e004 --- /dev/null +++ b/.changeset/floppy-nails-grab.md @@ -0,0 +1,5 @@ +--- +"gradio": minor +--- + +feat:Object Detection From Webcam Stream Guide diff --git a/demo/rt-detr-object-detection/draw_boxes.py b/demo/rt-detr-object-detection/draw_boxes.py new file mode 100644 index 0000000000000..9a0442e6b5ead --- /dev/null +++ b/demo/rt-detr-object-detection/draw_boxes.py @@ -0,0 +1,45 @@ +from PIL import ImageDraw, ImageFont # type: ignore +import colorsys + + +def get_color(label): + # Simple hash function to generate consistent colors for each label + hash_value = hash(label) + hue = (hash_value % 100) / 100.0 + saturation = 0.7 + value = 0.9 + rgb = colorsys.hsv_to_rgb(hue, saturation, value) + return tuple(int(x * 255) for x in rgb) + + +def draw_bounding_boxes(image, results: dict, model, threshold=0.3): + draw = ImageDraw.Draw(image) + font = ImageFont.load_default() + + for score, label_id, box in zip( + results["scores"], results["labels"], results["boxes"] + ): + if score > threshold: + label = model.config.id2label[label_id.item()] + box = [round(i, 2) for i in box.tolist()] + color = get_color(label) + + # Draw bounding box + draw.rectangle(box, outline=color, width=3) # type: ignore + + # Prepare text + text = f"{label}: {score:.2f}" + text_bbox = draw.textbbox((0, 0), text, font=font) + text_width = text_bbox[2] - text_bbox[0] + text_height = text_bbox[3] - text_bbox[1] + + # Draw text background + draw.rectangle( + [box[0], box[1] - text_height - 4, box[0] + text_width, box[1]], # type: ignore + fill=color, # type: ignore + ) + + # Draw text + draw.text((box[0], box[1] - text_height - 4), text, fill="white", font=font) + + return image diff --git a/demo/rt-detr-object-detection/requirements.txt b/demo/rt-detr-object-detection/requirements.txt new file mode 100644 index 0000000000000..c55994f2c0094 --- /dev/null +++ b/demo/rt-detr-object-detection/requirements.txt @@ -0,0 +1,4 @@ +safetensors==0.4.3 +opencv-python +torch +transformers>=4.43.0 \ No newline at end of file diff --git a/demo/rt-detr-object-detection/run.ipynb b/demo/rt-detr-object-detection/run.ipynb new file mode 100644 index 0000000000000..75412f0d91183 --- /dev/null +++ b/demo/rt-detr-object-detection/run.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: rt-detr-object-detection"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio safetensors==0.4.3 opencv-python torch transformers>=4.43.0"]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["# Downloading files from the demo repo\n", "import os\n", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/rt-detr-object-detection/draw_boxes.py"]}, {"cell_type": "code", "execution_count": null, "id": "44380577570523278879349135829904343037", "metadata": {}, "outputs": [], "source": ["import spaces\n", "import gradio as gr\n", "import cv2\n", "from PIL import Image\n", "import torch\n", "import time\n", "import numpy as np\n", "import uuid\n", "\n", "from transformers import RTDetrForObjectDetection, RTDetrImageProcessor # type: ignore\n", "\n", "from draw_boxes import draw_bounding_boxes\n", "\n", "image_processor = RTDetrImageProcessor.from_pretrained(\"PekingU/rtdetr_r50vd\")\n", "model = RTDetrForObjectDetection.from_pretrained(\"PekingU/rtdetr_r50vd\").to(\"cuda\")\n", "\n", "\n", "SUBSAMPLE = 2\n", "\n", "\n", "@spaces.GPU\n", "def stream_object_detection(video, conf_threshold):\n", " cap = cv2.VideoCapture(video)\n", "\n", " video_codec = cv2.VideoWriter_fourcc(*\"mp4v\") # type: ignore\n", " fps = int(cap.get(cv2.CAP_PROP_FPS))\n", "\n", " desired_fps = fps // SUBSAMPLE\n", " width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) // 2\n", " height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) // 2\n", "\n", " iterating, frame = cap.read()\n", "\n", " n_frames = 0\n", "\n", " name = f\"output_{uuid.uuid4()}.mp4\"\n", " segment_file = cv2.VideoWriter(name, video_codec, desired_fps, (width, height)) # type: ignore\n", " batch = []\n", "\n", " while iterating:\n", " frame = cv2.resize(frame, (0, 0), fx=0.5, fy=0.5)\n", " frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n", " if n_frames % SUBSAMPLE == 0:\n", " batch.append(frame)\n", " if len(batch) == 2 * desired_fps:\n", " inputs = image_processor(images=batch, return_tensors=\"pt\").to(\"cuda\")\n", "\n", " print(f\"starting batch of size {len(batch)}\")\n", " start = time.time()\n", " with torch.no_grad():\n", " outputs = model(**inputs)\n", " end = time.time()\n", " print(\"time taken for inference\", end - start)\n", "\n", " start = time.time()\n", " boxes = image_processor.post_process_object_detection(\n", " outputs,\n", " target_sizes=torch.tensor([(height, width)] * len(batch)),\n", " threshold=conf_threshold,\n", " )\n", "\n", " for _, (array, box) in enumerate(zip(batch, boxes)):\n", " pil_image = draw_bounding_boxes(\n", " Image.fromarray(array), box, model, conf_threshold\n", " )\n", " frame = np.array(pil_image)\n", " # Convert RGB to BGR\n", " frame = frame[:, :, ::-1].copy()\n", " segment_file.write(frame)\n", "\n", " batch = []\n", " segment_file.release()\n", " yield name\n", " end = time.time()\n", " print(\"time taken for processing boxes\", end - start)\n", " name = f\"output_{uuid.uuid4()}.mp4\"\n", " segment_file = cv2.VideoWriter(\n", " name, video_codec, desired_fps, (width, height)\n", " ) # type: ignore\n", "\n", " iterating, frame = cap.read()\n", " n_frames += 1\n", "\n", "\n", "with gr.Blocks() as demo:\n", " gr.HTML(\n", " \"\"\"\n", "

\n", " Video Object Detection with RT-DETR\n", "

\n", " \"\"\"\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " video = gr.Video(label=\"Video Source\")\n", " conf_threshold = gr.Slider(\n", " label=\"Confidence Threshold\",\n", " minimum=0.0,\n", " maximum=1.0,\n", " step=0.05,\n", " value=0.30,\n", " )\n", " with gr.Column():\n", " output_video = gr.Video(\n", " label=\"Processed Video\", streaming=True, autoplay=True\n", " )\n", "\n", " video.upload(\n", " fn=stream_object_detection,\n", " inputs=[video, conf_threshold],\n", " outputs=[output_video],\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/rt-detr-object-detection/run.py b/demo/rt-detr-object-detection/run.py new file mode 100644 index 0000000000000..ec089664009ed --- /dev/null +++ b/demo/rt-detr-object-detection/run.py @@ -0,0 +1,115 @@ +import spaces +import gradio as gr +import cv2 +from PIL import Image +import torch +import time +import numpy as np +import uuid + +from transformers import RTDetrForObjectDetection, RTDetrImageProcessor # type: ignore + +from draw_boxes import draw_bounding_boxes + +image_processor = RTDetrImageProcessor.from_pretrained("PekingU/rtdetr_r50vd") +model = RTDetrForObjectDetection.from_pretrained("PekingU/rtdetr_r50vd").to("cuda") + + +SUBSAMPLE = 2 + + +@spaces.GPU +def stream_object_detection(video, conf_threshold): + cap = cv2.VideoCapture(video) + + video_codec = cv2.VideoWriter_fourcc(*"mp4v") # type: ignore + fps = int(cap.get(cv2.CAP_PROP_FPS)) + + desired_fps = fps // SUBSAMPLE + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) // 2 + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) // 2 + + iterating, frame = cap.read() + + n_frames = 0 + + name = f"output_{uuid.uuid4()}.mp4" + segment_file = cv2.VideoWriter(name, video_codec, desired_fps, (width, height)) # type: ignore + batch = [] + + while iterating: + frame = cv2.resize(frame, (0, 0), fx=0.5, fy=0.5) + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + if n_frames % SUBSAMPLE == 0: + batch.append(frame) + if len(batch) == 2 * desired_fps: + inputs = image_processor(images=batch, return_tensors="pt").to("cuda") + + print(f"starting batch of size {len(batch)}") + start = time.time() + with torch.no_grad(): + outputs = model(**inputs) + end = time.time() + print("time taken for inference", end - start) + + start = time.time() + boxes = image_processor.post_process_object_detection( + outputs, + target_sizes=torch.tensor([(height, width)] * len(batch)), + threshold=conf_threshold, + ) + + for _, (array, box) in enumerate(zip(batch, boxes)): + pil_image = draw_bounding_boxes( + Image.fromarray(array), box, model, conf_threshold + ) + frame = np.array(pil_image) + # Convert RGB to BGR + frame = frame[:, :, ::-1].copy() + segment_file.write(frame) + + batch = [] + segment_file.release() + yield name + end = time.time() + print("time taken for processing boxes", end - start) + name = f"output_{uuid.uuid4()}.mp4" + segment_file = cv2.VideoWriter( + name, video_codec, desired_fps, (width, height) + ) # type: ignore + + iterating, frame = cap.read() + n_frames += 1 + + +with gr.Blocks() as demo: + gr.HTML( + """ +

+ Video Object Detection with RT-DETR +

+ """ + ) + with gr.Row(): + with gr.Column(): + video = gr.Video(label="Video Source") + conf_threshold = gr.Slider( + label="Confidence Threshold", + minimum=0.0, + maximum=1.0, + step=0.05, + value=0.30, + ) + with gr.Column(): + output_video = gr.Video( + label="Processed Video", streaming=True, autoplay=True + ) + + video.upload( + fn=stream_object_detection, + inputs=[video, conf_threshold], + outputs=[output_video], + ) + +if __name__ == "__main__": + demo.launch() diff --git a/demo/yolov10_webcam_stream/requirements.txt b/demo/yolov10_webcam_stream/requirements.txt new file mode 100644 index 0000000000000..fedb000072b32 --- /dev/null +++ b/demo/yolov10_webcam_stream/requirements.txt @@ -0,0 +1,2 @@ +safetensors==0.4.3 +git+https://github.com/THU-MIG/yolov10.git \ No newline at end of file diff --git a/demo/yolov10_webcam_stream/run.ipynb b/demo/yolov10_webcam_stream/run.ipynb new file mode 100644 index 0000000000000..0b0cd2599c081 --- /dev/null +++ b/demo/yolov10_webcam_stream/run.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: yolov10_webcam_stream"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio safetensors==0.4.3 git+https://github.com/THU-MIG/yolov10.git"]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "from ultralytics import YOLOv10\n", "\n", "model = YOLOv10.from_pretrained(\"jameslahm/yolov10n\")\n", "\n", "\n", "def yolov10_inference(image, conf_threshold):\n", " width, _ = image.size\n", " import time\n", "\n", " start = time.time()\n", " results = model.predict(source=image, imgsz=width, conf=conf_threshold)\n", " end = time.time()\n", " annotated_image = results[0].plot()\n", " print(\"time\", end - start)\n", " return annotated_image[:, :, ::-1]\n", "\n", "\n", "css = \"\"\".my-group {max-width: 600px !important; max-height: 600 !important;}\n", " .my-column {display: flex !important; justify-content: center !important; align-items: center !important};\"\"\"\n", "\n", "\n", "with gr.Blocks(css=css) as app:\n", " gr.HTML(\n", " \"\"\"\n", "

\n", " YOLO V10 Webcam Stream Object Detection\n", "

\n", " \"\"\"\n", " )\n", " with gr.Column(elem_classes=[\"my-column\"]):\n", " with gr.Group(elem_classes=[\"my-group\"]):\n", " image = gr.Image(type=\"pil\", label=\"Image\", sources=\"webcam\")\n", " conf_threshold = gr.Slider(\n", " label=\"Confidence Threshold\",\n", " minimum=0.0,\n", " maximum=1.0,\n", " step=0.05,\n", " value=0.30,\n", " )\n", " image.stream(\n", " fn=yolov10_inference,\n", " inputs=[image, conf_threshold],\n", " outputs=[image],\n", " stream_every=0.1,\n", " time_limit=30,\n", " )\n", "\n", "if __name__ == \"__main__\":\n", " app.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} \ No newline at end of file diff --git a/demo/yolov10_webcam_stream/run.py b/demo/yolov10_webcam_stream/run.py new file mode 100644 index 0000000000000..1eb280eb22eb4 --- /dev/null +++ b/demo/yolov10_webcam_stream/run.py @@ -0,0 +1,51 @@ +import gradio as gr + +from ultralytics import YOLOv10 + +model = YOLOv10.from_pretrained("jameslahm/yolov10n") + + +def yolov10_inference(image, conf_threshold): + width, _ = image.size + import time + + start = time.time() + results = model.predict(source=image, imgsz=width, conf=conf_threshold) + end = time.time() + annotated_image = results[0].plot() + print("time", end - start) + return annotated_image[:, :, ::-1] + + +css = """.my-group {max-width: 600px !important; max-height: 600 !important;} + .my-column {display: flex !important; justify-content: center !important; align-items: center !important};""" + + +with gr.Blocks(css=css) as app: + gr.HTML( + """ +

+ YOLO V10 Webcam Stream Object Detection +

+ """ + ) + with gr.Column(elem_classes=["my-column"]): + with gr.Group(elem_classes=["my-group"]): + image = gr.Image(type="pil", label="Image", sources="webcam") + conf_threshold = gr.Slider( + label="Confidence Threshold", + minimum=0.0, + maximum=1.0, + step=0.05, + value=0.30, + ) + image.stream( + fn=yolov10_inference, + inputs=[image, conf_threshold], + outputs=[image], + stream_every=0.1, + time_limit=30, + ) + +if __name__ == "__main__": + app.launch() diff --git a/gradio/route_utils.py b/gradio/route_utils.py index 88a8bfcc858cf..6b0028a1ddfbd 100644 --- a/gradio/route_utils.py +++ b/gradio/route_utils.py @@ -897,7 +897,7 @@ def __init__(self): self.ended = False self.segment_index = 0 self.playlist = "#EXTM3U\n#EXT-X-PLAYLIST-TYPE:EVENT\n#EXT-X-TARGETDURATION:10\n#EXT-X-VERSION:4\n#EXT-X-MEDIA-SEQUENCE:0\n" - self.max_length = 5 + self.max_duration = 5 async def add_segment(self, data: MediaStreamChunk | None): if not data: @@ -905,7 +905,7 @@ async def add_segment(self, data: MediaStreamChunk | None): segment_id = str(uuid.uuid4()) self.segments.append({"id": segment_id, **data}) - self.max_duration = max(self.max_length, data["duration"]) + 1 + self.max_duration = max(self.max_duration, data["duration"]) + 1 def end_stream(self): self.ended = True diff --git a/guides/04_additional-features/02_streaming-outputs.md b/guides/04_additional-features/02_streaming-outputs.md index fca501585f4f4..ab0cd1ff00a8a 100644 --- a/guides/04_additional-features/02_streaming-outputs.md +++ b/guides/04_additional-features/02_streaming-outputs.md @@ -33,7 +33,7 @@ For audio, the next "chunk" can be either an `.mp3` or `.wav` file or a `bytes` For video, the next "chunk" has to be either `.mp4` file or a file with `h.264` codec with a `.ts` extension. For smooth playback, make sure chunks are consistent lengths and larger than 1 second. -We'll finish with some simple examples illustrating these points. For a deeper tutorial on streaming audio with [transformers](https://huggingface.co/docs/transformers/index), please see [this guide](/main/guides/streaming-ai-generated-audio). +We'll finish with some simple examples illustrating these points. ### Streaming Audio @@ -67,4 +67,8 @@ gr.Interface(keep_repeating, gr.Video(sources=["webcam"], format="mp4"), gr.Video(streaming=True, autoplay=True) ).launch() -``` \ No newline at end of file +``` + +## End-to-End Examples + +For an end-to-end example of streaming media, see the object detection from video [guide](/main/guides/object-detection-from-video) or the streaming AI-generated audio with [transformers](https://huggingface.co/docs/transformers/index) [guide](/main/guides/streaming-ai-generated-audio). \ No newline at end of file diff --git a/guides/04_additional-features/03_streaming-inputs.md b/guides/04_additional-features/03_streaming-inputs.md index 7c22cd7d7c91b..78c04dc84a9d2 100644 --- a/guides/04_additional-features/03_streaming-inputs.md +++ b/guides/04_additional-features/03_streaming-inputs.md @@ -38,7 +38,7 @@ $demo_streaming_filter_unified Your streaming function should be stateless. It should take the current input and return its corresponding output. However, there are cases where you may want to keep track of past inputs or outputs. For example, you may want to keep a buffer of the previous `k` inputs to improve the accuracy of your transcription demo. You can do this with Gradio's `gr.State()` component. -Let's showcase this with a sample demo +Let's showcase this with a sample demo: ```python def transcribe_handler(current_audio, state, transcript): @@ -60,3 +60,7 @@ with gr.Blocks() as demo: demo.launch() ``` + +## End-to-End Examples + +For an end-to-end example of streaming from the webcam, see the object detection from webcam [guide](/main/guides/object-detection-from-webcam). \ No newline at end of file diff --git a/guides/09_other-tutorials/streaming-ai-generated-audio.md b/guides/07_streaming/01_streaming-ai-generated-audio.md similarity index 100% rename from guides/09_other-tutorials/streaming-ai-generated-audio.md rename to guides/07_streaming/01_streaming-ai-generated-audio.md diff --git a/guides/07_streaming/02_object-detection-from-webcam.md b/guides/07_streaming/02_object-detection-from-webcam.md new file mode 100644 index 0000000000000..f6439c2e7b1eb --- /dev/null +++ b/guides/07_streaming/02_object-detection-from-webcam.md @@ -0,0 +1,93 @@ +# Object Detection from a Webcam Stream + +Tags: VISION, STREAMING, WEBCAM + +In this guide we'll use Yolo-v10 to do near-real time object detection in Gradio from a user's webcam. +Along the way, we'll be using the latest streaming features introduced in Gradio 5.0. + +## Setting up the Model + +First, we'll follow the installation instructions for [Yolov10n](https://huggingface.co/jameslahm/yolov10n) on the Hugging Face hub. + +Run `pip install git+https://github.com/THU-MIG/yolov10.git` in your virtual environment. + +Then, we'll download the model from the Hub (`ultralytics` is the library we've just installed). + +```python +from ultralytics import YOLOv10 + +model = YOLOv10.from_pretrained('jameslahm/yolov10n') +``` + +We are using the `yolov10-n` variant because it has the lowest latency. See the [Performance](https://github.com/THU-MIG/yolov10?tab=readme-ov-file#performance) section of the README in the github repository. + + +## The Inference Function + +Our inference function will accept a PIL image from the webcam as well as a desired conference threshold. +Object detection models like YOLO identify many objects and assign a confidence score to each object. The lower the confidence, the higher the chance of a false positive. So we will let our users play with the conference threshold. + +```python +def yolov10_inference(image, conf_threshold): + width, _ = image.size + results = model.predict(source=image, imgsz=width, conf=conf_threshold) + annotated_image = results[0].plot() + return annotated_image[:, :, ::-1] +``` + +We will use the `plot` method to draw a bounding box around each detected object. YoloV10 asses images are in the BGR color format, so we will flip them to be in the expected RGB format of web browsers. + +## The Gradio Demo + +The Gradio demo will be pretty straightforward but we'll do a couple of things that are specific to streaming: + +* The user's webcam will be both an input and an output. That way, the user will only see their stream with the detected objects. +* We'll use the `time_limit` and `stream_every` parameters of the `stream` event. The `time_limit` parameter will mean that we'll process each user's stream for that amount of time. In a multi-user setting, such as on Spaces, this means that after this period of time, the next user in the queue will be able to use the demo. The `stream_every` function will control how frequently the webcam stream is sent to the server. + +In addition, we'll apply some custom css so that the webcam and slider are centered on the page. + +```python +css=""".my-group {max-width: 600px !important; max-height: 600 !important;} + .my-column {display: flex !important; justify-content: center !important; align-items: center !important};""" + + +with gr.Blocks(css=css) as app: + gr.HTML( + """ +

+ YOLOv10 Webcam Stream +

+ """) + gr.HTML( + """ +

+ arXiv | github +

+ """) + with gr.Column(elem_classes=["my-column"]): + with gr.Group(elem_classes=["my-group"]): + image = gr.Image(type="pil", label="Image", sources="webcam") + conf_threshold = gr.Slider( + label="Confidence Threshold", + minimum=0.0, + maximum=1.0, + step=0.05, + value=0.30, + ) + image.stream( + fn=yolov10_inference, + inputs=[image, conf_threshold], + outputs=[image], + stream_every=0.1, + time_limit=30 + ) +``` + + +## Conclusion + +You can check out our demo hosted on Hugging Face Spaces [here](https://huggingface.co/spaces/gradio/YOLOv10-webcam-stream). + +It is also embedded on this page below + +$demo_yolov10_webcam_stream \ No newline at end of file diff --git a/guides/07_streaming/03_object-detection-from-video.md b/guides/07_streaming/03_object-detection-from-video.md new file mode 100644 index 0000000000000..cabc12af6b9ee --- /dev/null +++ b/guides/07_streaming/03_object-detection-from-video.md @@ -0,0 +1,181 @@ +# Object Detection from a Webcam Stream + +Tags: VISION, STREAMING, VIDEO + +In this guide we'll use the [RT-DETR](https://huggingface.co/docs/transformers/en/model_doc/rt_detr) model to detect objects in a user uploaded video. We'll stream the results from the server using the new video streaming features introduced in Gradio 5.0. + +![video_object_detection_stream_latest](https://github.com/user-attachments/assets/4e27ac58-5ded-495d-9e0d-5e87e68b1355) + +## Setting up the Model + +First, we'll install the following requirements in our system: + +``` +opencv-python +torch +transformers>=4.43.0 +spaces +``` + +Then, we'll download the model from the Hugging Face Hub: + +```python +from transformers import RTDetrForObjectDetection, RTDetrImageProcessor + +image_processor = RTDetrImageProcessor.from_pretrained("PekingU/rtdetr_r50vd") +model = RTDetrForObjectDetection.from_pretrained("PekingU/rtdetr_r50vd").to("cuda") +``` + +We're moving the model to the GPU. We'll be deploying our model to Hugging Face Spaces and running the inference in the [free ZeroGPU cluster](https://huggingface.co/zero-gpu-explorers). + + +## The Inference Function + +Our inference function will accept a video and a desired confidence threshold. +Object detection models identify many objects and assign a confidence score to each object. The lower the confidence, the higher the chance of a false positive. So we will let our users set the conference threshold. + +Our function will iterate over the frames in the video and run the RT-DETR model over each frame. +We will then draw the bounding boxes for each detected object in the frame and save the frame to a new output video. +The function will yield each output video in chunks of two seconds. + +In order to keep inference times as low as possible on ZeroGPU (there is a time-based quota), +we will halve the original frames-per-second in the output video and resize the input frames to be half the original +size before running the model. + +The code for the inference function is below - we'll go over it piece by piece. + +```python +import spaces +import cv2 +from PIL import Image +import torch +import time +import numpy as np +import uuid + +from draw_boxes import draw_bounding_boxes + +SUBSAMPLE = 2 + +@spaces.GPU +def stream_object_detection(video, conf_threshold): + cap = cv2.VideoCapture(video) + + # This means we will output mp4 videos + video_codec = cv2.VideoWriter_fourcc(*"mp4v") # type: ignore + fps = int(cap.get(cv2.CAP_PROP_FPS)) + + desired_fps = fps // SUBSAMPLE + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) // 2 + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) // 2 + + iterating, frame = cap.read() + + n_frames = 0 + + # Use UUID to create a unique video file + output_video_name = f"output_{uuid.uuid4()}.mp4" + + # Output Video + output_video = cv2.VideoWriter(output_video_name, video_codec, desired_fps, (width, height)) # type: ignore + batch = [] + + while iterating: + frame = cv2.resize( frame, (0,0), fx=0.5, fy=0.5) + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + if n_frames % SUBSAMPLE == 0: + batch.append(frame) + if len(batch) == 2 * desired_fps: + inputs = image_processor(images=batch, return_tensors="pt").to("cuda") + + with torch.no_grad(): + outputs = model(**inputs) + + boxes = image_processor.post_process_object_detection( + outputs, + target_sizes=torch.tensor([(height, width)] * len(batch)), + threshold=conf_threshold) + + for i, (array, box) in enumerate(zip(batch, boxes)): + pil_image = draw_bounding_boxes(Image.fromarray(array), box, model, conf_threshold) + frame = np.array(pil_image) + # Convert RGB to BGR + frame = frame[:, :, ::-1].copy() + output_video.write(frame) + + batch = [] + output_video.release() + yield output_video_name + output_video_name = f"output_{uuid.uuid4()}.mp4" + output_video = cv2.VideoWriter(output_video_name, video_codec, desired_fps, (width, height)) # type: ignore + + iterating, frame = cap.read() + n_frames += 1 +``` + +1. **Reading from the Webcam** + +One of the industry standards for creating videos in python is OpenCV so we will use it in this video. + +The `cap` variable is how we will read from the input video. Whenever we call `cap.read()`, we are reading the next frame in the video. + +In order to stream video in Gradio, we need to yield a different video file for each "chunk" of the output video. +We create the next video file to write to with the `output_video = cv2.VideoWriter(output_video_name, video_codec, desired_fps, (width, height))` line. The `video_codec` is how we specify the type of video file. Only "mp4" and "ts" files are supported for video sreaming at the moment. + + +2. **The Inference Loop** + +For each frame in the video, we will resize it to be half the size. OpenCV reads files in `BGR` format, so will convert to the expected `RGB` format of transfomers. That's what the first two lines of the while loop are doing. + +We take every other frame and add it to a `batch` list so that the output video is half the original FPS. When the batch covers two seconds of video, we will run the model. The two second threshold was chosen to keep the processing time of each batch small enough so that video is smoothly displayed in the server while not requiring too many separate forward passes. In order for video streaming to work properly in Gradio, the batch size should be at least 1 second. + +We run the forward pass of the model and then use the `post_process_object_detection` method of the model to scale the detected bounding boxes to the size of the input frame. + +We make use of a custom function to draw the bounding boxes (source [here](https://huggingface.co/spaces/gradio/rt-detr-object-detection/blob/main/draw_boxes.py#L14)). We then have to convert from `RGB` to `BGR` before writing back to the output video. + +Once we have finished processing the batch, we create a new output video file for the next batch. + +## The Gradio Demo + +The UI code is pretty similar to other kinds of Gradio apps. +We'll use a standard two-column layout so that users can see the input and output videos side by side. + +In order for streaming to work, we have to set `streaming=True` in the output video. Setting the video +to autoplay is not necessary but it's a better experience for users. + +```python +with gr.Blocks() as app: + gr.HTML( + """ +

+ Video Object Detection with RT-DETR +

+ """) + with gr.Row(): + with gr.Column(): + video = gr.Video(label="Video Source") + conf_threshold = gr.Slider( + label="Confidence Threshold", + minimum=0.0, + maximum=1.0, + step=0.05, + value=0.30, + ) + with gr.Column(): + output_video = gr.Video(label="Processed Video", streaming=True, autoplay=True) + + video.upload( + fn=stream_object_detection, + inputs=[video, conf_threshold], + outputs=[output_video], + ) +``` + + +## Conclusion + +You can check out our demo hosted on Hugging Face Spaces [here](https://huggingface.co/spaces/gradio/rt-detr-object-detection). + +It is also embedded on this page below + +$demo_rt-detr-object-detection \ No newline at end of file diff --git a/guides/09_other-tutorials/real-time-speech-recognition.md b/guides/07_streaming/04_real-time-speech-recognition.md similarity index 100% rename from guides/09_other-tutorials/real-time-speech-recognition.md rename to guides/07_streaming/04_real-time-speech-recognition.md diff --git a/guides/07_custom-components/01_custom-components-in-five-minutes.md b/guides/08_custom-components/01_custom-components-in-five-minutes.md similarity index 100% rename from guides/07_custom-components/01_custom-components-in-five-minutes.md rename to guides/08_custom-components/01_custom-components-in-five-minutes.md diff --git a/guides/07_custom-components/02_key-component-concepts.md b/guides/08_custom-components/02_key-component-concepts.md similarity index 100% rename from guides/07_custom-components/02_key-component-concepts.md rename to guides/08_custom-components/02_key-component-concepts.md diff --git a/guides/07_custom-components/03_configuration.md b/guides/08_custom-components/03_configuration.md similarity index 100% rename from guides/07_custom-components/03_configuration.md rename to guides/08_custom-components/03_configuration.md diff --git a/guides/07_custom-components/04_backend.md b/guides/08_custom-components/04_backend.md similarity index 100% rename from guides/07_custom-components/04_backend.md rename to guides/08_custom-components/04_backend.md diff --git a/guides/07_custom-components/05_frontend.md b/guides/08_custom-components/05_frontend.md similarity index 100% rename from guides/07_custom-components/05_frontend.md rename to guides/08_custom-components/05_frontend.md diff --git a/guides/07_custom-components/06_frequently-asked-questions.md b/guides/08_custom-components/06_frequently-asked-questions.md similarity index 100% rename from guides/07_custom-components/06_frequently-asked-questions.md rename to guides/08_custom-components/06_frequently-asked-questions.md diff --git a/guides/07_custom-components/07_pdf-component-example.md b/guides/08_custom-components/07_pdf-component-example.md similarity index 100% rename from guides/07_custom-components/07_pdf-component-example.md rename to guides/08_custom-components/07_pdf-component-example.md diff --git a/guides/07_custom-components/08_multimodal-chatbot-part1.md b/guides/08_custom-components/08_multimodal-chatbot-part1.md similarity index 100% rename from guides/07_custom-components/08_multimodal-chatbot-part1.md rename to guides/08_custom-components/08_multimodal-chatbot-part1.md diff --git a/guides/07_custom-components/09_documenting-custom-components.md b/guides/08_custom-components/09_documenting-custom-components.md similarity index 100% rename from guides/07_custom-components/09_documenting-custom-components.md rename to guides/08_custom-components/09_documenting-custom-components.md diff --git a/guides/08_gradio-clients-and-lite/01_getting-started-with-the-python-client.md b/guides/09_gradio-clients-and-lite/01_getting-started-with-the-python-client.md similarity index 100% rename from guides/08_gradio-clients-and-lite/01_getting-started-with-the-python-client.md rename to guides/09_gradio-clients-and-lite/01_getting-started-with-the-python-client.md diff --git a/guides/08_gradio-clients-and-lite/02_getting-started-with-the-js-client.md b/guides/09_gradio-clients-and-lite/02_getting-started-with-the-js-client.md similarity index 100% rename from guides/08_gradio-clients-and-lite/02_getting-started-with-the-js-client.md rename to guides/09_gradio-clients-and-lite/02_getting-started-with-the-js-client.md diff --git a/guides/08_gradio-clients-and-lite/03_querying-gradio-apps-with-curl.md b/guides/09_gradio-clients-and-lite/03_querying-gradio-apps-with-curl.md similarity index 100% rename from guides/08_gradio-clients-and-lite/03_querying-gradio-apps-with-curl.md rename to guides/09_gradio-clients-and-lite/03_querying-gradio-apps-with-curl.md diff --git a/guides/08_gradio-clients-and-lite/04_gradio-and-llm-agents.md b/guides/09_gradio-clients-and-lite/04_gradio-and-llm-agents.md similarity index 100% rename from guides/08_gradio-clients-and-lite/04_gradio-and-llm-agents.md rename to guides/09_gradio-clients-and-lite/04_gradio-and-llm-agents.md diff --git a/guides/08_gradio-clients-and-lite/05_gradio-lite.md b/guides/09_gradio-clients-and-lite/05_gradio-lite.md similarity index 100% rename from guides/08_gradio-clients-and-lite/05_gradio-lite.md rename to guides/09_gradio-clients-and-lite/05_gradio-lite.md diff --git a/guides/08_gradio-clients-and-lite/06_gradio-lite-and-transformers-js.md b/guides/09_gradio-clients-and-lite/06_gradio-lite-and-transformers-js.md similarity index 100% rename from guides/08_gradio-clients-and-lite/06_gradio-lite-and-transformers-js.md rename to guides/09_gradio-clients-and-lite/06_gradio-lite-and-transformers-js.md diff --git a/guides/08_gradio-clients-and-lite/07_fastapi-app-with-the-gradio-client.md b/guides/09_gradio-clients-and-lite/07_fastapi-app-with-the-gradio-client.md similarity index 100% rename from guides/08_gradio-clients-and-lite/07_fastapi-app-with-the-gradio-client.md rename to guides/09_gradio-clients-and-lite/07_fastapi-app-with-the-gradio-client.md diff --git a/guides/09_other-tutorials/01_using-hugging-face-integrations.md b/guides/10_other-tutorials/01_using-hugging-face-integrations.md similarity index 100% rename from guides/09_other-tutorials/01_using-hugging-face-integrations.md rename to guides/10_other-tutorials/01_using-hugging-face-integrations.md diff --git a/guides/09_other-tutorials/Gradio-and-Comet.md b/guides/10_other-tutorials/Gradio-and-Comet.md similarity index 100% rename from guides/09_other-tutorials/Gradio-and-Comet.md rename to guides/10_other-tutorials/Gradio-and-Comet.md diff --git a/guides/09_other-tutorials/Gradio-and-ONNX-on-Hugging-Face.md b/guides/10_other-tutorials/Gradio-and-ONNX-on-Hugging-Face.md similarity index 100% rename from guides/09_other-tutorials/Gradio-and-ONNX-on-Hugging-Face.md rename to guides/10_other-tutorials/Gradio-and-ONNX-on-Hugging-Face.md diff --git a/guides/09_other-tutorials/Gradio-and-Wandb-Integration.md b/guides/10_other-tutorials/Gradio-and-Wandb-Integration.md similarity index 100% rename from guides/09_other-tutorials/Gradio-and-Wandb-Integration.md rename to guides/10_other-tutorials/Gradio-and-Wandb-Integration.md diff --git a/guides/09_other-tutorials/create-your-own-friends-with-a-gan.md b/guides/10_other-tutorials/create-your-own-friends-with-a-gan.md similarity index 100% rename from guides/09_other-tutorials/create-your-own-friends-with-a-gan.md rename to guides/10_other-tutorials/create-your-own-friends-with-a-gan.md diff --git a/guides/09_other-tutorials/creating-a-dashboard-from-bigquery-data.md b/guides/10_other-tutorials/creating-a-dashboard-from-bigquery-data.md similarity index 100% rename from guides/09_other-tutorials/creating-a-dashboard-from-bigquery-data.md rename to guides/10_other-tutorials/creating-a-dashboard-from-bigquery-data.md diff --git a/guides/09_other-tutorials/creating-a-dashboard-from-supabase-data.md b/guides/10_other-tutorials/creating-a-dashboard-from-supabase-data.md similarity index 100% rename from guides/09_other-tutorials/creating-a-dashboard-from-supabase-data.md rename to guides/10_other-tutorials/creating-a-dashboard-from-supabase-data.md diff --git a/guides/09_other-tutorials/creating-a-realtime-dashboard-from-google-sheets.md b/guides/10_other-tutorials/creating-a-realtime-dashboard-from-google-sheets.md similarity index 100% rename from guides/09_other-tutorials/creating-a-realtime-dashboard-from-google-sheets.md rename to guides/10_other-tutorials/creating-a-realtime-dashboard-from-google-sheets.md diff --git a/guides/09_other-tutorials/deploying-gradio-with-docker.md b/guides/10_other-tutorials/deploying-gradio-with-docker.md similarity index 100% rename from guides/09_other-tutorials/deploying-gradio-with-docker.md rename to guides/10_other-tutorials/deploying-gradio-with-docker.md diff --git a/guides/09_other-tutorials/developing-faster-with-reload-mode.md b/guides/10_other-tutorials/developing-faster-with-reload-mode.md similarity index 100% rename from guides/09_other-tutorials/developing-faster-with-reload-mode.md rename to guides/10_other-tutorials/developing-faster-with-reload-mode.md diff --git a/guides/09_other-tutorials/how-to-use-3D-model-component.md b/guides/10_other-tutorials/how-to-use-3D-model-component.md similarity index 100% rename from guides/09_other-tutorials/how-to-use-3D-model-component.md rename to guides/10_other-tutorials/how-to-use-3D-model-component.md diff --git a/guides/09_other-tutorials/image-classification-in-pytorch.md b/guides/10_other-tutorials/image-classification-in-pytorch.md similarity index 100% rename from guides/09_other-tutorials/image-classification-in-pytorch.md rename to guides/10_other-tutorials/image-classification-in-pytorch.md diff --git a/guides/09_other-tutorials/image-classification-in-tensorflow.md b/guides/10_other-tutorials/image-classification-in-tensorflow.md similarity index 100% rename from guides/09_other-tutorials/image-classification-in-tensorflow.md rename to guides/10_other-tutorials/image-classification-in-tensorflow.md diff --git a/guides/09_other-tutorials/image-classification-with-vision-transformers.md b/guides/10_other-tutorials/image-classification-with-vision-transformers.md similarity index 100% rename from guides/09_other-tutorials/image-classification-with-vision-transformers.md rename to guides/10_other-tutorials/image-classification-with-vision-transformers.md diff --git a/guides/09_other-tutorials/installing-gradio-in-a-virtual-environment.md b/guides/10_other-tutorials/installing-gradio-in-a-virtual-environment.md similarity index 100% rename from guides/09_other-tutorials/installing-gradio-in-a-virtual-environment.md rename to guides/10_other-tutorials/installing-gradio-in-a-virtual-environment.md diff --git a/guides/09_other-tutorials/named-entity-recognition.md b/guides/10_other-tutorials/named-entity-recognition.md similarity index 100% rename from guides/09_other-tutorials/named-entity-recognition.md rename to guides/10_other-tutorials/named-entity-recognition.md diff --git a/guides/09_other-tutorials/plot-component-for-maps.md b/guides/10_other-tutorials/plot-component-for-maps.md similarity index 100% rename from guides/09_other-tutorials/plot-component-for-maps.md rename to guides/10_other-tutorials/plot-component-for-maps.md diff --git a/guides/09_other-tutorials/running-background-tasks.md b/guides/10_other-tutorials/running-background-tasks.md similarity index 100% rename from guides/09_other-tutorials/running-background-tasks.md rename to guides/10_other-tutorials/running-background-tasks.md diff --git a/guides/09_other-tutorials/running-gradio-on-your-web-server-with-nginx.md b/guides/10_other-tutorials/running-gradio-on-your-web-server-with-nginx.md similarity index 100% rename from guides/09_other-tutorials/running-gradio-on-your-web-server-with-nginx.md rename to guides/10_other-tutorials/running-gradio-on-your-web-server-with-nginx.md diff --git a/guides/09_other-tutorials/setting-up-a-demo-for-maximum-performance.md b/guides/10_other-tutorials/setting-up-a-demo-for-maximum-performance.md similarity index 100% rename from guides/09_other-tutorials/setting-up-a-demo-for-maximum-performance.md rename to guides/10_other-tutorials/setting-up-a-demo-for-maximum-performance.md diff --git a/guides/09_other-tutorials/styling-the-gradio-dataframe.md b/guides/10_other-tutorials/styling-the-gradio-dataframe.md similarity index 100% rename from guides/09_other-tutorials/styling-the-gradio-dataframe.md rename to guides/10_other-tutorials/styling-the-gradio-dataframe.md diff --git a/guides/09_other-tutorials/theming-guide.md b/guides/10_other-tutorials/theming-guide.md similarity index 100% rename from guides/09_other-tutorials/theming-guide.md rename to guides/10_other-tutorials/theming-guide.md diff --git a/guides/09_other-tutorials/using-flagging.md b/guides/10_other-tutorials/using-flagging.md similarity index 100% rename from guides/09_other-tutorials/using-flagging.md rename to guides/10_other-tutorials/using-flagging.md diff --git a/guides/09_other-tutorials/using-gradio-for-tabular-workflows.md b/guides/10_other-tutorials/using-gradio-for-tabular-workflows.md similarity index 100% rename from guides/09_other-tutorials/using-gradio-for-tabular-workflows.md rename to guides/10_other-tutorials/using-gradio-for-tabular-workflows.md diff --git a/guides/09_other-tutorials/using-gradio-in-other-programming-languages.md b/guides/10_other-tutorials/using-gradio-in-other-programming-languages.md similarity index 100% rename from guides/09_other-tutorials/using-gradio-in-other-programming-languages.md rename to guides/10_other-tutorials/using-gradio-in-other-programming-languages.md diff --git a/guides/09_other-tutorials/wrapping-layouts.md b/guides/10_other-tutorials/wrapping-layouts.md similarity index 100% rename from guides/09_other-tutorials/wrapping-layouts.md rename to guides/10_other-tutorials/wrapping-layouts.md