gr.Blocks와 이벤트 리스너 — 레이아웃을 내 손으로
gr.Blocks와 이벤트 리스너 — 레이아웃을 내 손으로
gr.Interface는 함수 하나를 감싸는 가장 빠른 방법이라면, gr.Blocks는 그 이상을 원할 때 쓰는 도구예요. 입력-버튼-출력을 원하는 위치에 배치하고, '이 버튼을 누르면 이 함수가 실행돼'라는 연결(event listener)을 직접 지정할 수 있어요. 데모가 조금 복잡해지기 시작하면 여기로 넘어오게 돼요.
Blocks 구조
먼저 with gr.Blocks() as demo:라는 블록 안에 앱 코드를 담아요. 이 안에 컴포넌트들을 배치하면 그게 곧 화면이 돼요.
import gradio as gr
def greet(name):
return "Hello " + name + "!"
with gr.Blocks() as demo:
name = gr.Textbox(label="Name")
output = gr.Textbox(label="Output Box")
greet_btn = gr.Button("Greet")
greet_btn.click(fn=greet, inputs=name, outputs=output, api_name="greet")
demo.launch()
이벤트 리스너로 상호작용 만들기
여기서 핵심은 .click(fn=greet, inputs=name, outputs=output, api_name="greet") 부분이에요. "greet_btn 버튼이 클릭되면, name 텍스트박스의 값을 greet 함수에 넣고, 그 결과를 output 텍스트박스에 써줘"라고 하는 거예요. api_name은 이 이벤트에 외부에서 접근할 API 이름을 붙여주는 옵션이에요.
이벤트 리스너는 종류가 여러 개예요. 버튼 클릭(click), 입력값이 바뀔 때(change), 컴포넌트를 선택했을 때(select), 마우스를 올렸을 때(hover) 같은 트리거를 상황에 맞게 골라 쓸 수 있어요.
여러 데이터 흐름
함수는 입력 목록과 출력 목록을 받아요. 입력이 여러 개면 함수의 파라미터 여러 개에 순서대로 들어가요.
def add(a, b):
return a + b
with gr.Blocks() as demo:
num1 = gr.Number()
num2 = gr.Number()
add_btn = gr.Button("Add")
result = gr.Number()
add_btn.click(add, inputs=[num1, num2], outputs=result)
demo.launch()
컴포넌트 값을 다른 컴포넌트 값의 함수로
"어떤 컴포넌트의 값이 항상 다른 컴포넌트 값들의 함수가 되도록" 하려면 이런 축약 문법을 써요.
with gr.Blocks() as demo:
num1 = gr.Number()
num2 = gr.Number()
product = gr.Number(lambda a, b: a * b, inputs=[num1, num2])
이것은 num1·num2 값이 바뀔 때마다 product를 다시 계산해주는 것과 같은 동작이에요. gr.on으로 여러 트리거를 묶은 것과 동일하죠.
더 알아보기
Blocks의 레이아웃 제어(gr.Row, gr.Column)와 상태 관리(gr.State)는 공식 Controlling Layout과 State In Blocks 가이드에서 이어서 볼 수 있어요.