State in Blocks 块中的状态
我们介绍了接口中的状态,这个指南将看看块中的状态,其工作原理大致相同。
全局状态
块中的全局状态与接口中的工作原理相同。在函数调用外创建的任何变量都是所有用户共享的引用。
会话状态
Gradio 支持会话状态,在块应用程序中,数据在页面会话中多次提交后仍然持续存在。重申一下,会话数据不会在模型的不同用户之间共享。要在会话状态中存储数据,您需要做三件事:
创建一个
gr.State()
对象。如果这个有状态的对象有默认值,请将其传递给构造函数。在事件监听器中,将
State
对象作为输入和输出。在事件监听器函数中,将变量添加到输入参数和返回值中。
让我们来看一场挂人游戏。
import gradio as gr # 导入gradio库
secret_word = "gradio" # 设置游戏的秘密单词
with gr.Blocks() as demo: # 使用gr.Blocks创建一个应用布局
used_letters_var = gr.State([]) # 使用状态变量记录已使用过的字母
with gr.Row() as row: # 创建一行用于并排放置输入框和显示框
with gr.Column(): # 创建第一列,用于放置输入文本框和猜测按钮
input_letter = gr.Textbox(label="Enter letter") # 创建输入文本框,用于输入字母
btn = gr.Button("Guess Letter") # 创建按钮,用于提交猜测的字母
with gr.Column(): # 创建第二列,用于放置挂人游戏进度和已使用字母显示框
hangman = gr.Textbox(
label="Hangman",
value="_"*len(secret_word) # 初始化挂人游戏的显示,用下划线代表秘密单词的每个字母
)
used_letters_box = gr.Textbox(label="Used Letters") # 创建一个文本框,用于显示已猜过的字母
def guess_letter(letter, used_letters): # 定义猜测字母的函数
used_letters.append(letter) # 将猜测的字母添加到已使用字母列表
answer = "".join([
(letter if letter in used_letters else "_") # 根据已猜测的字母更新挂人游戏的显示
for letter in secret_word
])
return {
used_letters_var: used_letters, # 更新状态变量中的已使用字母列表
used_letters_box: ", ".join(used_letters), # 更新已使用字母文本框的内容
hangman: answer # 更新挂人游戏显示框的内容
}
btn.click(
guess_letter, # 将按钮点击事件绑定到guess_letter函数
[input_letter, used_letters_var], # 指定输入参数:输入的字母和已使用字母列表
[used_letters_var, used_letters_box, hangman] # 指定更新的目标组件:状态、已使用字母显示框和挂人游戏显示框
)
demo.launch() # 启动应用
这段代码使用Gradio库创建了一个Web应用程序,实现了一个简单的挂人(Hangman)游戏。游戏的目标是猜测一个秘密单词,这里秘密单词被设置为"gradio"。
用户通过输入框输入一个字母,点击"Guess Letter"按钮提交猜测。
游戏记录用户已经猜测过的字母,并更新挂人进度显示以及显示已用字母列表。如果猜测的字母在秘密单词中,那么对应位置的下划线会被替换为实际字母;否则,猜测的字母只会出现在已用字母列表中。
guess_letter
函数处理字母猜测过程,包括更新游戏进度和已用字母。每次猜测后,游戏状态通过Gradio的State
组件进行更新,以保留游戏进度。GUI布局采用了行和列的组织方式,以清晰地分隔输入、游戏进度显示和已用字母列表。
这个示例展示了Gradio如何用于实现交互式Web应用,以及如何利用状态管理维护应用的动态数据。
让我们看看我们如何在这个游戏中执行上面列出的 3 个步骤:
我们在
used_letters_var
中存储使用过的字母。在State
的构造函数中,我们将这个的初始值设置为[]
,一个空列表。在
btn.click()
中,我们在输入和输出中都有对used_letters_var
的引用。在
guess_letter
中,我们将这个State
的值传递给used_letters
,然后在返回语句中返回这个State
的更新值。
对于更复杂的应用程序,您可能会在单个 Blocks 应用程序中有许多 State 变量存储会话状态。
了解更多关于 State
的信息,请查阅文档。https://gradio.app/docs/state
Dynamic Apps with the Render Decorator
动态应用程序与渲染装饰器
在 Blocks 中定义的组件和事件监听器到目前为止都是固定的 - 一旦演示启动,就不能添加新的组件和监听器,也不能移除已有的。
@gr.render
装饰器引入了动态更改这一能力的可能。让我们来看一下。</