界面状态

本指南介绍了 Gradio 中如何处理状态。 了解全局状态和会话状态之间的区别,以及如何使用两者。

This guide covers how State is handled in Gradio. Learn the difference between Global and Session states, and how to use both.

全局状态

你的函数可能会使用在单个函数调用之后持续存在的数据。 如果所有函数调用和所有用户都可以访问数据,则可以在函数调用外部创建一个变量并在函数内部访问它。 例如,你可以在函数外部加载一个大型模型并在函数内部使用它,这样每次函数调用都不需要重新加载模型。

Your function may use data that persists beyond a single function call. If the data is something accessible to all function calls and all users, you can create a variable outside the function call and access it inside the function. For example, you may load a large model outside the function and use it inside the function so that every function call does not need to reload the model.

import gradio as gr

scores = []

def track_score(score):
    scores.append(score)
    top_scores = sorted(scores, reverse=True)[:3]
    return top_scores

demo = gr.Interface(
    track_score, 
    gr.Number(label="Score"), 
    gr.JSON(label="Top Scores")
)
demo.launch()

在上面的代码中, scores 数组在所有用户之间共享。 如果多个用户正在访问此演示,他们的分数将全部添加到同一个列表中,并且将从该共享参考中收集返回的前 3 名分数。

In the code above, the scores array is shared between all users. If multiple users are accessing this demo, their scores will all be added to the same list, and the returned top 3 scores will be collected from this shared reference.

会话状态

Gradio 支持的另一种数据持久化类型是会话状态,其中数据在页面会话中跨多个提交持久化。 但是,数据不会在模型的不同用户之间共享。 要在会话状态中存储数据,你需要做三件事:

Another type of data persistence Gradio supports is session state, where data persists across multiple submits within a page session. However, data is not shared between different users of your model. To store data in a session state, you need to do three things:

  1. 将一个额外的参数传递到你的函数中,该参数表示界面的状态。

    Pass in an extra parameter into your function, which represents the state of the interface.

  2. 在函数结束时,返回状态的更新值作为额外的返回值。

    At the end of the function, return the updated value of the state as an extra return value.

  3. 创建 Interface 时添加 'state' 输入和 'state' 输出组件

    Add the 'state' input and 'state' output components when creating your Interface

聊天机器人是一个你需要会话状态的示例 - 你想要访问用户以前提交的内容,但你不能将聊天历史存储在全局变量中,因为那样聊天历史会在不同用户之间混乱。

A chatbot is an example where you would need session state - you want access to a users previous submissions, but you cannot store chat history in a global variable, because then chat history would get jumbled between different users.

import gradio as gr
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-medium")
model = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-medium")


def user(message, history):
    return "", history + [[message, None]]


def bot(history):
    user_message = history[-1][0]
    new_user_input_ids = tokenizer.encode(
        user_message + tokenizer.eos_token, return_tensors="pt"
    )

    # append the new user input tokens to the chat history
    bot_input_ids = torch.cat([torch.LongTensor([]), new_user_input_ids], dim=-1)

    # generate a response
    response = model.generate(
        bot_input_ids, max_length=1000, pad_token_id=tokenizer.eos_token_id
    ).tolist()

    # convert the tokens to text, and then split the responses into lines
    response = tokenizer.decode(response[0]).split("<|endoftext|>")
    response = [
        (response[i], response[i + 1]) for i in range(0, len(response) - 1, 2)
    ]  # convert to tuples of list
    history[-1] = response[0]
    return history


with gr.Blocks() as demo:
    chatbot = gr.Chatbot()
    msg = gr.Textbox()
    clear = gr.Button("Clear")

    msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(
        bot, chatbot, chatbot
    )
    clear.click(lambda: None, None, chatbot, queue=False)

demo.launch()

请注意状态如何在每个页面中跨提交持续存在,但如果你在另一个选项卡中加载此演示(或刷新页面),演示将不会共享聊天历史记录。

Notice how the state persists across submits within each page, but if you load this demo in another tab (or refresh the page), the demos will not share chat history.

state 的默认值为无。 如果将默认值传递给函数的状态参数,它将用作状态的默认值。 Interface 类仅支持单个输入和输出状态变量,但它可以是包含多个元素的列表。 对于更复杂的用例,可以使用 Blocks,它支持多个 State 变量

The default value of state is None. If you pass a default value to the state parameter of the function, it is used as the default value of the state instead. The Interface class only supports a single input and outputs state variable, though it can be a list with multiple elements. For more complex use cases, you can use Blocks, which supports multiple State variables.