Gradio

Егор Горбань — Data Engineer

Gradio: Overview

Gradio is an open-source Python package that allows you to quickly build a demo or web application for your machine learning model, API, or any arbitary Python function.

Типы приложений

  • gr.Blocks - кастомное приложение: базовый класс;
  • Интерфейсы
    • gr.Interface - input-output интерфейс;
    • gr.ChatInterface - чат-интерфейс;
    • gr.TabbedInterface - приложение, разделённое на несколько tab-секций. То есть несколько приложений внутри одного;

Интерфейс

Запуск любого приложения: gradio <filename.py> или python <filename.py>

gr.Interface — input-output приложение, позволяющее в интерактивном режиме взаимодействовать с пользователем.

import gradio as gr
import pandas as pd

df = pd.read_csv("examples/data/sales.csv")


def get_sample_dataframe(
    sample_size,
):
    return df.sample(sample_size)


demo = gr.Interface(
    fn=get_sample_dataframe,
    inputs=["number"], # inputs=[gr.Number()],
    outputs=["dataframe"], # outputs=[gr.DataFrame()],
)
demo.launch()

Интерфейс: Data Flow

  • input —>

    1. preprocessing - преобразование к объекту Python
    2. function prosessing
    3. postprocessing - преобразование к объекту HTML
  • —> output

  • Например gr.Image может быть картинкой (np.ndarray), путём до файла с картинкой (str), списком путей до файлов (list[str]).

Интерфейс: специальные возможности

  • можно указать, каким образом препроцессить input

    demo = gr.Interface(
        fn=your_func,
        inputs=[gr.Image(type="pil"), gr.DataFrame(type='polars')],
        outputs=["dataframe"],
    )
  • input/output могут отсутствовать

    gr.Interface(
        fn=predict,
        inputs=None,
        outputs=["str"],
    )

Интерфейс: специальные возможности

  • можно добавить примеры для тестирования интерфейса

    gr.Interface(
        fn=predict,
        inputs=gr.Image(type="pil"),
        outputs=gr.Label(num_top_classes=3),
        examples=["lion.jpg", "cheetah.jpg"]
    )

Чат-интерфейс

gr.ChatInterface - приложение-чат

  • input
    1. message: str
    2. history: list[tuple[str, str]]
  • output — ret_val: str
import random

import gradio as gr


def magic_answer(message, history):
    return random.choice(["Yes", "No"])


demo = gr.ChatInterface(magic_answer)
demo.launch()

gr.Blocks

Наконец рассмотрим более общий класс, который позволяет создать практически сколь угодно сложное приложение, подобно тому как мы строили приложения с помощью Streamlit.

import gradio as gr
def update(name):
    return f"Welcome to Gradio, {name}!"

with gr.Blocks() as demo:
    # Отформатированный текст
    gr.Markdown("Start typing _below_ and then click **Run** to see the output.")

    # Вёрстка: компоновка элементов в строку
    with gr.Row():
        # текстовое поле
        inp = gr.Textbox(placeholder="What is your name?")
        # текстовый ввод
        out = gr.Textbox()

    # Кнопка
    btn = gr.Button("Run")

    # действие при нажатии на кнопку
    btn.click(fn=update, inputs=inp, outputs=out)

demo.launch()

gr.Blocks - Data Flow

  • свободный flow — зависит от вашей фантазии
  • общие возможности:
    • кнопочка к которой прикреплено событие

      with gr.Blocks() as demo:
          ...
          def update(inp_item):
              ...
      
          inp = ... # компонент
          out = ... # компонент
      
          btn = gr.Button("Act")
          btn.click(fn=update, inputs=inp, outputs=out)
    • real-time change

          with gr.Blocks() as demo:
              ...
              def update(inp_item):
                  ...
      
              inp = ... # компонент
              out = ... # компонент
      
              inp.change(update, inp, out)
    • интерактивность

      text_area = gr.Textbox(..., interactive=True)

Компоненты

  • List of components
  • Custom Components
  • Демонстрация контента: Label, DataFrame, Code, Chatbot, Image, Video, BarPlot, etc
  • Виджеты: Radio, Slider, UploadButton, etc

Компоненты

AnnotatedImage: картинки с аннотациями объектов

Компоненты

  • MultimodalTextbox - поле ввода, в которое можно загружать мульти-медиа
  • Model3D - 3D модель в формате .obj, .glb, .stl, .gltf, .splat, .ply

Переменные состояния

  • Состояние: глобальное и локальное (в пределах сессии)
  • Global State — переменные в global scope.
    • Определение в глобальной области видимости.

    • Синглтон для всех пользователей.

    • Пример

      import gradio as gr
      
      global_list = []
      
      def add_item(item):
          global_list.append(item)
          return global_list
      
      demo = gr.Interface(add_item, gr.Textbox(), gr.JSON(label="All items"))
      demo.launch()

Переменные состояния

Session State — переменные сессии.

  • Доступ через gr.State().
  • Синглтон для сессии
  • Для интерфейсов доступна только одна переменная, для Blocks — сколько угодно
  • Пример для gr.Interface (history — обращение к singleton)
import gradio as gr

def store_message(message: str, history: list[str]):
    output = {
        "Current messages": message,
        "Previous messages": history[::-1]
    }
    history.append(message)
    return output, history

demo = gr.Interface(
    fn=store_message, 
    inputs=["textbox", gr.State(value=[])], 
    outputs=["json", gr.State()]
)

demo.launch()

Переменные состояния

Пример для gr.Blocks

with gr.Blocks() as demo:
    words_singleton = gr.State(set()) # переменная сессии
    with gr.Row() as row:
        with gr.Column():
            input_letter = gr.Textbox(label="Enter word")
            btn = gr.Button("Add word")
        with gr.Column():
            session_words_box = gr.Textbox(label="Current words")

    def add_word(word, session_words):
        session_words.add(word)
        return [
            session_words, # присвоится синглтон-переменной `words_singleton`
            ", ".join(session_words),
        ]

    btn.click(
        add_word,
        [input_letter, words_singleton],
        [
            words_singleton, # обновляем синглтон-переменную через первый retval функции
            session_words_box
        ],
    )
demo.launch()

Streaming

  • streaming outputs
    • Вместо функции в интерфейсе используется генератор.

    • Тогда значение будет перезаписываться по мере того как будут поступать новые yield-values

    • Например: можно стримить вывод ML-модели.

      import time
      import gradio as gr
      
      
      def magic_answer(message):
          for i in range(len(message)):
              time.sleep(0.1)
              yield message[: i + 1]
      
      
      demo = gr.Interface(magic_answer, inputs=["text"], outputs=["text"])
      demo.launch()
  • streaming inputs
    • Некоторые компоненты могут работать в “интерактивном режиме”

      demo = gr.Interface(
          ...
          inputs = [
              ...
              gr.Audio(
                  sources=[gr.Microphone()],
                  streaming=True,
              ),
              ...
          ],
          ...
      )

Reactive interfaces

Реактивный интерфейс - интерфейс который реагирует на изменение пользовательского ввода и позволяет “на лету” обновлять приложение и генерировать вывод не по нажатию кнопки “Submit”, а при изменении input.

  • live=True

    demo = gr.Interface(
        ...
        live=True, # Reactive interface
        ...
    )
  • Пример: Automatic Speech Recognition (тут больше примеров).

    # libs are required: numpy, torch, torchaudio, transformers
    
    import gradio as gr
    import numpy as np
    from transformers import pipeline
    
    transcriber = pipeline("automatic-speech-recognition", model="openai/whisper-base.en")
    
    def transcribe(stream, new_chunk):
        sr, y = new_chunk
        left_ch = y[:, 0].astype(np.float32) # костыль для получения одноканального аудио
        left_ch /= np.max(np.abs(left_ch))
        if stream is not None:
            stream = np.concatenate([stream, left_ch])
        else:
            stream = left_ch
        return stream, transcriber({"sampling_rate": sr, "raw": stream})["text"]
    
    demo = gr.Interface(
        transcribe,
        [gr.State(), gr.Audio(sources=[gr.Microphone()], streaming=True)],
        [gr.State(), gr.Textbox()],
        live=True,
    )
    
    demo.launch()

Дополнительные возможности

Что можно делать с gr.Interface кроме launch?

Развёртывание

demo.launch(share=True)

Выводы:

  • Подходит для создания интерфейсов для ML-моделей
  • Позволяет интерактивно взаимодействовать с пользователем
  • Подходит для создания чатботов
  • Есть интеграции с HuggingFace, transformers.pipeline, MlFlow и т.д.