2025年2月21日 星期五

Python 學習筆記 : 簡單好用的 Web app 套件 gradio (八)

Gradio 原本去年底我就大致測試完畢, 但最近在測試 DuckDuckGo API 時發現它還有一個好用的 Block 元件, 可以用來自訂 web app 版面, 讓開發者可以更靈活地排列各種 UI 元件, 此外它也提供狀態管理與事件處理功能, 非常適合用來製作 AI 聊天機器人或 Dashboard (儀錶板) 等較複雜的應用程式介面. 

本系列文章索引參考 : 



十一. 用 Block 元件自訂 web app 版面 : 

在之前的 Gradio 測試中, 我們都使用 Interface 類別來建立 web app 的標準網頁介面, 只要用 inputs, outputs, 以及 fn 參數指定輸出入元件與 Submit 按鈕之處理函式即可簡單地建立應用程式介面. 但若要建立結構較複雜的 App, 則 Interface 所提供的簡單且固定的版面就不敷使用了, 這時就需要用到 Blocks 與 Row, Column, Tab, 或 Acordion 等布局元件來自行為介面排版. 

Blocks 類別是一個比 Interface 類別還低階的 API, 呼叫其建構式 Blocks() 會建立一個 Blocks 物件 : 

>>> import gradio as gr 
>>> blocks=gr.Blocks()   
>>> type(blocks)   
<class 'gradio.blocks.Blocks'>   

用 Blocks 布局元件時需要用到 with 語法形成一個語境 (context) 區塊, 然後在此語境內使用 Row, Column, Tab, 或 Acordion 等布局元件為其他 UI 元件進行排版 (也都使用 with 語法) : 

with gr.Blocks() as blocks:
    # 在此 context 內進行 UI 元件布局
    with gr.Row(): # 列布局 
        # 放置水平排列的 UI 元件 (由左向右)
    with gr.Column(): 
        # 放置垂直排列的 UI 元件  (由上而下)
    with gr.Tab():
        # 放置第一個頁籤內的 UI 元件  (由左向右)
    with gr.Tab():
        # 放置第二個頁籤內的 UI 元件  (由左向右)
    with gr.Acordion():
        # 放置手風琴內的 UI 元件  (由左向右)

使用 with 語法的好處是能確保 Blocks 物件在執行完 with 語境後能自動釋放資源, 在語境內部建立的 UI 元件都會被自動加入 Blocks 物件內, 使程式碼更整潔更有可讀性. 

最後在語境外呼叫 Blocks 物件的 launch() 方法即可發布 web app : 
   
blocks.launch()


1. 僅使用 Blocks 排版 : 

這種排版方式不使用 Row, Column, Tab, 或 Acordion 等布局元件, 直接將 UI 元件放在 Blocks 語境內, 這時 UI 元件會流水式依序由左向右, 由上而下排列, 例如下面將輸入文字轉成大寫的簡單範例中, 我們直接在 blocks 語境內建立了一個 TextBox 輸入與輸出元件, 以及一個 Button 元件 : 

>>> with blocks:
 in1=gr.Textbox(label="輸入文字")
 btn=gr.Button("送出")
 out1=gr.Textbox(label="輸出結果")
 btn.click(lambda in1: in1.upper(), inputs=in1, outputs=out1) 

 {'id': 0, 'targets': [(6, 'click')], 'inputs': [5], 'outputs': [7], 'backend_fn': True, 'js': None, 'queue': True, 'api_name': 'lambda', 'scroll_to_output': False, 'show_progress': 'full', 'batch': False, 'max_batch_size': 4, 'cancels': [], 'types': {'generator': False, 'cancel': False}, 'collects_event_data': False, 'trigger_after': None, 'trigger_only_on_success': False, 'trigger_mode': 'once', 'show_api': True, 'zerogpu': False, 'rendered_in': None, 'connection': 'sse', 'time_limit': None, 'stream_every': 0.5, 'like_user_message': False, 'event_specific_args': None}

其中 Button 物件的第一個參數是按鈕事件的處理函式, 並且用關鍵字 inputs 要傳入此函式的輸入元件, 以及用 outputs 指定接收函式傳回值的輸出元件. 

接著只要呼叫 Blocks 物件的 launch() 方法發布此 web app : 

>>> blocks.launch()    
* Running on local URL:  http://127.0.0.1:7860

To create a public link, set `share=True` in `launch()`. 

結果如下 :




按鈕事件處理函式也可以用 def 來定義, 然後於 click() 方法中以 fn 參數指定 :

import gradio as gr

def handler(text):
    return text.upper()

with gr.Blocks() as blocks:
     in1=gr.Textbox(label="輸入文字")
     btn=gr.Button("送出")
     out1=gr.Textbox(label="輸出結果")
     btn.click(fn=handler , inputs=in1, outputs=out1)
     
blocks.launch()

結果是一樣的. 


2. 使用 Row 列布局元件排版 : 

Row 類別用來將 UI 元件以水平方式 (由左向右) 做橫列排版, 呼叫其建構式 Row() 即可建立一個列布局物件, 與 Blocks 物件用法一樣, 也是使用 with gr.Row() 用法建立一個 Row 物件語境, 然後在其內佈放 UI 物件, 例如 : 

import gradio as gr

def handler(text):
    return text.upper()

with gr.Blocks() as blocks:
    with gr.Row():
        in1=gr.Textbox(label="輸入文字")
        btn=gr.Button("送出")
        out1=gr.Textbox(label="輸出結果")
    btn.click(fn=handler , inputs=in1, outputs=out1)
     
blocks.launch()

此處 in1, btn, 與 out1 三個 UI 元件佈放在 Row 物件的語境內, 它們會被水平排列於版面中, 結果如下 : 




可見三個 UI 元件以橫列方式水平排列. 


3. 使用 Column 行布局元件排版 : 

Column 類別用來將 UI 元件以垂直方式 (由上而下) 做垂直排版, 呼叫其建構式 Column() 即可建立一個行布局物件, 與 Blocks 物件用法一樣, 也是使用 with gr.Column() 用法建立一個 Column 物件語境, 然後在其內佈放 UI 物件, 例如 : 

# gradio_blocks_test_3.py
import gradio as gr

def handler(text):
    return text.upper()

with gr.Blocks() as blocks:
    with gr.Column():
        in1=gr.Textbox(label="輸入文字")
        btn=gr.Button("送出")
        out1=gr.Textbox(label="輸出結果")
    btn.click(fn=handler , inputs=in1, outputs=out1)
     
blocks.launch()

此處 in1, btn, 與 out1 三個 UI 元件佈放在 Column 物件的語境內, 它們會被垂直排列於版面中, 結果如下 : 




可見這與上面直接在 Blocks 物件內排版的效果是一樣的. 


4. 使用 Tab 頁籤布局元件排版 :  

Tab 類別用來將 UI 元件以頁籤的方式排版, 呼叫其建構式 Tab() 並傳入頁籤標題即可建立一個頁籤布局物件, 與 Blocks 物件用法一樣, 也是使用 with gr.Tab() 用法建立一個 Tab 物件語境, 然後在其內佈放 UI 物件, 通常需要建立一個以上的 Tab 語境來各自佈放頁籤內之 UI 元件, 例如 : 

# gradio_blocks_test_4.py
import gradio as gr

def upper(text):
    return text.upper()

def lower(text):
    return text.lower()

with gr.Blocks() as blocks:
    with gr.Tab('轉成大寫'):
        in1=gr.Textbox(label="輸入文字")
        btn1=gr.Button("送出")
        out1=gr.Textbox(label="輸出結果")
    with gr.Tab('轉成小寫'):
        in2=gr.Textbox(label="輸入文字")
        btn2=gr.Button("送出")
        out2=gr.Textbox(label="輸出結果")       
    btn1.click(fn=upper, inputs=in1, outputs=out1)
    btn2.click(fn=lower, inputs=in2, outputs=out2)
     
blocks.launch()

此處建立了兩個頁籤物件, 並在各自語境下佈放 UI 元件, 分別達成轉大寫與轉小寫的 web app 功能, 結果如下 : 





按頁籤標題即可切換至轉大寫與轉小寫之頁籤. 


5. 使用 Accordion 手風琴布局元件排版 :  

Accordion 類別用來將 UI 元件以手風琴版面方式排版, 呼叫其建構式 Accordion() 並傳入標題 (第一參數) 即可建立一個手風琴版面物件, 與 Blocks 物件用法一樣, 也是使用 with gr.Accordion() 用法建立一個 Accordion 物件語境, 然後在其內佈放 UI 物件. 手風琴預設是開啟的, 但可以傳入 open=False 將其關閉, 例如 : 

# gradio_blocks_test_5.py
import gradio as gr

def upper(text):
    return text.upper()

def lower(text):
    return text.lower()

with gr.Blocks() as blocks:
    with gr.Accordion('轉成大寫'):
        in1=gr.Textbox(label="輸入文字")
        btn1=gr.Button("送出")
        out1=gr.Textbox(label="輸出結果")
    with gr.Accordion('轉成小寫', open=False):
        in2=gr.Textbox(label="輸入文字")
        btn2=gr.Button("送出")
        out2=gr.Textbox(label="輸出結果")       
    btn1.click(fn=upper, inputs=in1, outputs=out1)
    btn2.click(fn=lower, inputs=in2, outputs=out2)
     
blocks.launch()

此例建立了兩個手風琴物件, 分別佈放轉大寫與轉小寫的 UI 元件, 其中轉大寫的預設是開啟, 轉小寫的社為關閉, 初始化時結果如下 : 





按手風琴右邊的三角形按鈕可以收合或開啟版面 : 




這是關閉轉大寫, 開啟轉小寫版面的效果. 

沒有留言:

張貼留言