Chuyển đến nội dung chính

Xây dựng giao diện người dùng cho ứng dụng AI với Gradio trong Python

Tìm hiểu cách chuyển đổi các mô hình kỹ thuật thành giao diện người dùng tương tác với Gradio trong Python.
· 14 phút đọc

Khám phá cùng AI

Tính hữu dụng của các mô hình AI ngày nay sẽ giảm đi rất nhiều nếu không có giao diện người dùng dễ tiếp cận. Với Gradio, một thư viện web UI Python mã nguồn mở, bạn có thể thu hẹp khoảng cách giữa LLM và người dùng cuối không chuyên kỹ thuật. Công cụ này cho phép bạn tạo nguyên mẫu nhanh cho các dự án AI và đơn giản hóa việc triển khai đến nhiều đối tượng hơn.

Hướng dẫn này dành cho các kỹ sư học máy thường không có kinh nghiệm phát triển web. Nội dung bao gồm những điều cơ bản và khái niệm cốt lõi của Gradio, cách tạo giao diện cho nhiều loại mô hình AI khác nhau, các tính năng nâng cao dành cho UX và tính tương tác, cùng các thực tiễn tốt nhất về triển khai và chia sẻ.

Hãy bắt đầu.

Bắt đầu với Gradio

Cài đặt

Chúng ta sẽ bắt đầu bằng cách tạo một môi trường ảo (ưu tiên dùng Conda):

$ conda create -n gradio_tutorial python=3.9 -y
$ conda activate gradio_tutorial

Sau đó, bạn có thể dùng PIP để cài đặt Gradio và các phụ thuộc:

$ pip install gradio ipykernel

Chúng tôi cũng cài đặt gói ipykernel để có thể hiển thị giao diện Gradio trực tiếp trong notebook Jupyter. Quy trình này yêu cầu bạn thêm môi trường ảo đã tạo làm kernel cho Jupyter Lab. Đây là lệnh để thực hiện:

$ ipython kernel install --user --name=gradio_tutorial
$ jupyter lab  # Start the lab

Bạn sẽ có thể tạo một notebook với kernel đã cài Gradio. Để xác minh, hãy import với bí danh tiêu chuẩn và in phiên bản:

import gradio as gr
print(gr.__version__)
4.37.1

Khái niệm và thuật ngữ cơ bản

Chúng ta sẽ tìm hiểu Gradio thông qua các khái niệm chính và thuật ngữ với ví dụ “Hello World”:

def greet(name):
   return f"Hello, {name}!"
demo = gr.Interface(
   fn=greet,
   inputs=['text'],
   outputs="text",
)
demo.launch()

Khi chạy đoạn mã trên trong một ô, đầu ra sẽ là một giao diện tương tác nhỏ trả về thông điệp chào mừng tuỳ biến:

Một ảnh GIF hiển thị ví dụ Hello World trong Gradio

Gradio xoay quanh một vài khái niệm chính:

  1. Interface: lớp cốt lõi để tạo UI.
  2. Components: Các phần tử đầu vào và đầu ra như ô văn bản, hình ảnh và âm thanh. Hiện có hơn 30 component tích hợp sẵn.
  3. Functions: Các hàm Python xử lý thông tin từ component đầu vào và trả về kết quả để hiển thị bằng component đầu ra.
  4. Launch: Phương thức để khởi động ứng dụng Gradio của bạn.

Ở trên, chúng ta tạo hàm greet nhận và trả về một đầu vào văn bản. Vì vậy, các component đầu vào và đầu ra được chỉ định là text bên trong lớp Interface.

Cuối cùng, chúng ta gọi phương thức launch, phương thức này khởi động một máy chủ cục bộ. Để làm cho UI khả dụng với bất cứ ai, bạn có thể đặt tham số share thành True. Việc này sẽ tạo một đường hầm SSH và triển khai ứng dụng Gradio lên một trang web có thể chia sẻ công khai:

demo.launch(share=True)
Running on public URL: https://d638ed5f2ce0044296.gradio.live
This share link expires in 72 hours. For free permanent hosting and GPU upgrades, run gradio deploy from Terminal to deploy to Spaces (https://huggingface.co/spaces)

Các component của Gradio

Khi xây dựng ứng dụng Gradio, bạn sẽ dành phần lớn thời gian để thử nghiệm các component khác nhau và cách sắp đặt chúng trên trang. Vậy hãy xem kỹ hơn những gì bạn có thể sử dụng.

Component đầu vào và đầu ra

Gradio cung cấp nhiều component để xây dựng giao diện tương tác. Các component này thường được chia thành hai loại: đầu vào và đầu ra.

Component đầu vào cho phép người dùng cung cấp dữ liệu cho bộ xử lý nền (có thể là bất kỳ hàm Python nào). Một số đầu vào phổ biến là:

  • Textbox
  • Image
  • Audio
  • Slider
  • Dropdown

Đây là một giao diện mẫu sử dụng một số component ở trên:

def process_inputs(text, image, audio, number, option):
   # Process inputs and return results
   return f"Processed: {text}, {number}, {option}"
demo = gr.Interface(
   fn=process_inputs,
   inputs=[
       gr.Textbox(label="Enter text"),
       gr.Image(label="Upload image"),
       gr.Audio(label="Upload audio"),  # Uncomment this line to add audio input
       gr.Slider(0, 100, label="Choose a number"),
       gr.Dropdown(["Streamlit", "Taipy", "Gradio"], label="Select a UI library"),
   ],
   outputs="text",
)
demo.launch()

Trong ví dụ này, hàm process_inputs yêu cầu năm tham số. Do đó, chúng ta cần tạo năm component đầu vào và truyền vào inputs. Mặc dù số component đầu vào nên khớp với số tham số bắt buộc của hàm, đây không phải là quy tắc cứng. Để tránh lỗi và cảnh báo, hãy đặt giá trị mặc định cho các tham số không cần người dùng nhập từ UI.

Một bản demo Gradio khác cho thấy cách dùng nhiều component

Lưu ý cách chúng ta dùng lớp Textbox để chỉ định component đầu vào thay vì chuỗi đơn giản text như ví dụ đầu tiên. Luôn nên dùng các lớp chuyên dụng để chỉ định component đầu vào/đầu ra nhằm giúp tuỳ biến dễ dàng hơn. Ví dụ, tất cả lớp component đều có thuộc tính label hữu ích, trong khi Slider và Dropdown có các tham số để chỉ định phạm vi và tuỳ chọn khả dụng.

Nhiều component đầu vào cũng có thể dùng để hiển thị đầu ra. Một số kịch bản phổ biến:

  • Label: Dùng để hiển thị văn bản hoặc kết quả phân loại
  • Image: Dùng để hiển thị ảnh đã xử lý hoặc được tạo
  • Audio: Dùng để phát âm thanh đã xử lý hoặc được tạo
  • Plot: Dùng để hiển thị đồ thị hoặc biểu đồ

Tương tự đầu vào, số component đầu ra phải khớp với số giá trị được trả về từ hàm xử lý.

Tuỳ chỉnh giao diện component

Gradio cho phép bạn tuỳ chỉnh diện mạo các component theo nhu cầu. Ví dụ sau sử dụng các ô văn bản tuỳ chỉnh:

demo = gr.Interface(
   fn=lambda x: int(x) ** 7,
   inputs=gr.Textbox(
       lines=5,
       placeholder="Enter any number...",
       label="Custom textbox",
       info="This is a customized textbox component to raise any number to the power of 7.",
   ),
   outputs=gr.Textbox(label="And the number is...", show_copy_button=True),
)
demo.launch()

Một demo Gradio cho thấy cách dùng ô văn bản tuỳ chỉnh

Trong ví dụ này, chúng ta đã tuỳ chỉnh các component Textbox bằng cách chỉ định số dòng, thêm văn bản gợi ý (placeholder) và thông tin (info), đồng thời thêm nút sao chép cho đầu ra.

Hãy thử nghiệm với các component và thuộc tính khác nhau để tạo ra giao diện phù hợp nhất với yêu cầu của ứng dụng AI của bạn. Để biết bạn có thể thay đổi thuộc tính gì cho component, bạn có thể xem tài liệu của nó, hoặc hay hơn, dùng toán tử ? trong Jupyter Lab ngay sau tên lớp:

Ảnh chụp màn hình hiển thị các thuộc tính của một component Gradio

Xây dựng giao diện cho LLM

Hãy tổng hợp những gì đã học bằng cách tạo hai giao diện văn bản và hình ảnh trong thực tế, được vận hành bởi LLM.

Đầu tiên, chúng ta sẽ xây dựng một công cụ dịch ngôn ngữ từ tiếng Anh sang tiếng Thổ Nhĩ Kỳ, Tây Ban Nha hoặc Trung Quốc:

import openai  # pip install openai
def translate_text(api_key, text, target_language):
  
   openai.api_key = api_key  # Set openai API key
  
   language_map = {
       "Turkish": "Turkish",
       "Spanish": "Spanish",
       "Chinese": "Chinese (Simplified)",
   }
   prompt = f"Translate the following English text to {language_map[target_language]}:\n\nEnglish: {text}\n\n{target_language} translation:"
   try:
       response = openai.chat.completions.create(
           model="gpt-4",
           messages=[
               {"role": "system", "content": "You are a professional translator."},
               {"role": "user", "content": prompt},
           ],
       )
       translation = response.choices[0].message.content.strip()
       return translation
   except Exception as e:
       return f"Error: {str(e)}"

Ban đầu, chúng ta định nghĩa hàm translate_text. Trong thân hàm, chúng ta đặt khóa API OpenAI và tạo ánh xạ ngôn ngữ. Sau đó, xây dựng prompt cho việc dịch. Tiếp theo, trong khối try-except, chúng ta gửi yêu cầu đến endpoint ChatCompletion với một system prompt. Cuối cùng, trả về lựa chọn đầu tiên.

Giờ chúng ta có thể xây dựng giao diện:

iface = gr.Interface(
   fn=translate_text,
   inputs=[
       gr.Textbox(
           placeholder="Enter your OpenAI API key",
           type="password",
           label="OpenAI API Key",
       ),
       gr.Textbox(
           lines=4,
           placeholder="Enter English text to translate...",
           label="English Text",
       ),
       gr.Dropdown(choices=["Turkish", "Spanish", "Chinese"], label="Target Language"),
   ],
   outputs=gr.Textbox(label="Translation", show_copy_button=True),
   title="English to Turkish/Spanish/Chinese Translator",
   description="Translate English text to Turkish, Spanish, or Chinese using OpenAI's GPT-4 model. Enter your OpenAI API key, the text you want to translate, and select the target language.",
)
iface.launch(share=True)

Đoạn mã đơn giản như các giao diện trước đó, nhưng chúng ta giới thiệu thêm một vài thuộc tính mới:

  • Tham số type của ô văn bản chuyển trường nhập văn bản thuần sang kiểu mật khẩu, ẩn nội dung.
  • Tham số title và description của lớp Interface sẽ thêm tiêu đề H1 và phụ đề vào chính giữa đầu trang.

Đây là kết quả:

Một ứng dụng Gradio dịch từ tiếng Anh sang tiếng Thổ Nhĩ Kỳ/Tây Ban Nha/Trung Quốc

Bạn có thể thắc mắc vì sao chúng ta yêu cầu khóa API của người dùng như một phần của ứng dụng thay vì tự cung cấp. Lý do liên quan đến cách Gradio triển khai UI.

Nếu chúng ta cung cấp khóa API của mình như biến môi trường (thực hành tiêu chuẩn), phiên bản ứng dụng có thể chia sẻ công khai sẽ không hoạt động vì nó không thể truy cập biến môi trường của chúng ta. Ở phần triển khai, chúng ta sẽ xem cách khắc phục bằng cách triển khai ứng dụng lên HuggingFace Spaces.

Hãy xây dựng một UI khác để tạo ảnh:

def generate_surrealist_art(api_key, prompt):
   surrealist_prompt = f"Create a surrealist artwork based on the following concept: {prompt}. The artwork should be dreamlike, with unexpected juxtapositions and a sense of the uncanny."
   client = OpenAI(api_key=api_key)
   response = client.images.generate(
       model="dall-e-3",
       prompt=surrealist_prompt,
       size="1024x1024",
   )
   image_url = response.data[0].url
   return image_url

Chúng ta tạo một hàm tên là generate_surrealist_art gửi yêu cầu đến dall-e-3 và trả về URL ảnh được tạo bằng một prompt phong cách siêu thực. Sau đó, chúng ta lại truyền hàm này vào lớp Interface:

iface = gr.Interface(
   fn=generate_surrealist_art,
   inputs=[
       gr.Textbox(
           placeholder="Enter your OpenAI API key",
           type="password",
           label="OpenAI API Key",
       ),
       gr.Textbox(
           lines=2,
           placeholder="Describe your surrealist concept...",
           label="Concept Description",
       ),
   ],
   outputs=gr.Image(value="str"),
   title="Surrealist Artwork Generator",
   description="Generate surrealist artwork based on your prompts using DALL-E. Enter your OpenAI API key and describe your concept.",
)
iface.launch(share=True)

Chúng ta chỉ định hai đầu vào cho khóa API và ý tưởng muốn thể hiện trong bức ảnh siêu thực. Sau đó, tạo một component đầu ra cho ảnh được tạo bằng lớp Image. Nếu đặt tham số value thành str, component có thể tải và hiển thị hình ảnh từ URL, đúng như những gì chúng ta cần.

Và đây là kết quả:

Một gif cho thấy ứng dụng Gradio dựa trên hình ảnh.

Xây dựng giao diện cho các mô hình ML cổ điển

Bây giờ, hãy xây dựng một giao diện cho mô hình hồi quy dạng bảng cổ điển. Chúng ta sẽ dùng bộ dữ liệu Diamonds có trong Seaborn.

Bắt đầu bằng cách tạo một thư mục làm việc mới và một script mới tên là app.py bên trong. Sau đó, dán mã từ gist GitHub này để tải dữ liệu, xử lý bằng Pipeline của Scikit-learn và huấn luyện mô hình RandomForestRegression.

Ảnh chụp màn hình một gist GitHub

Bước tiếp theo là tạo hàm xử lý chấp nhận số lượng đầu vào tương ứng với số đặc trưng trong bộ dữ liệu Diamonds:

# Create the Gradio interface
def predict_price(carat, cut, color, clarity, depth, table, x, y, z):
  
   input_data = pd.DataFrame(
       {
           "carat": [carat],
           "cut": [cut],
           "color": [color],
           "clarity": [clarity],
           "depth": [depth],
           "table": [table],
           "x": [x],
           "y": [y],
           "z": [z],
       }
   )
  
   prediction = model.predict(input_data)[0]
   return f"Predicted Price: ${prediction:.2f}"

Hàm này chuyển các đầu vào thành một DataFrame và truyền cho phương thức .predict() của pipeline mô hình đã huấn luyện. Cuối cùng, trả về một chuỗi chứa giá dự đoán.

Giờ lớp Interface phải khớp với chữ ký của hàm này: chín component đầu vào để xử lý các đặc trưng và một đầu ra để hiển thị giá dự đoán:

iface = gr.Interface(
   fn=predict_price,
   inputs=[
       gr.Slider(
           minimum=diamonds["carat"].min(),
           maximum=diamonds["carat"].max(),
           label="Carat",
       ),
       gr.Dropdown(["Fair", "Good", "Very Good", "Premium", "Ideal"], label="Cut"),
       gr.Dropdown(["D", "E", "F", "G", "H", "I", "J"], label="Color"),
       gr.Dropdown(
           ["I1", "SI2", "SI1", "VS2", "VS1", "VVS2", "VVS1", "IF"], label="Clarity"
       ),
       gr.Slider(
           minimum=diamonds["depth"].min(),
           maximum=diamonds["depth"].max(),
           label="Depth",
       ),
       gr.Slider(
           minimum=diamonds["table"].min(),
           maximum=diamonds["table"].max(),
           label="Table",
       ),
       gr.Slider(minimum=diamonds["x"].min(), maximum=diamonds["x"].max(), label="X"),
       gr.Slider(minimum=diamonds["y"].min(), maximum=diamonds["y"].max(), label="Y"),
       gr.Slider(minimum=diamonds["z"].min(), maximum=diamonds["z"].max(), label="Z"),
   ],
   outputs="text",
   title="Diamond Price Predictor",
   description="Enter the characteristics of a diamond to predict its price.",
)
iface.launch(share=True)

Bên trong lớp, chúng ta tạo ba dropdown cho các đặc trưng phân loại. Các tuỳ chọn được điền bằng các hạng mục duy nhất của từng đặc trưng. Chúng ta cũng tạo sáu component slider để nhận các đặc trưng số. Phạm vi của slider được xác định bởi giá trị nhỏ nhất và lớn nhất của từng đặc trưng.

Giờ việc còn lại là chạy script để khởi động và triển khai ứng dụng:

$ python app.py

Đây là kết quả:

Một gif cho thấy demo Gradio được triển khai bằng script

Để biết các thực tiễn tốt nhất và mẹo tối ưu, hãy chuyển đến phần Thực tiễn tốt nhất bên dưới.

Triển khai ứng dụng Gradio

Chúng ta đã thấy việc triển khai ứng dụng Gradio dễ dàng thế nào chỉ với một tham số. Dĩ nhiên, nhược điểm của phương pháp này là bản demo sẽ hết hạn trong 72 giờ. Vì vậy, phương pháp khuyến nghị để triển khai Gradio là thông qua HuggingFace Spaces. HuggingFace đã mua lại Gradio vào năm 2021, giúp việc tích hợp giữa hai nền tảng trở nên liền mạch.

Vì vậy, cho hướng dẫn này hoặc bất kỳ ứng dụng nào bạn tạo bằng Gradio, hãy đăng ký một tài khoản miễn phí tại huggingface.co và điều hướng đến Settings > Tokens để tạo token truy cập:

Một ảnh Gif cho thấy cách tạo access token trong Hugging Face

Token chỉ hiển thị một lần, vì vậy hãy lưu trữ ở nơi an toàn.

Với token này, bạn có thể triển khai bao nhiêu ứng dụng Gradio tùy thích với lưu trữ vĩnh viễn trên Spaces. Là ví dụ, chúng ta sẽ triển khai mô hình dự đoán giá kim cương từ phần trước, và bạn sẽ thấy điều này dễ dàng đến bất ngờ.

Tất cả những gì bạn cần làm là điều hướng đến thư mục chứa script UI và gọi gradio deploy trên terminal:

Ảnh chụp màn hình cách triển khai ứng dụng gradio bằng terminal

Terminal sẽ hướng dẫn bạn chuyển đổi script thành một Space hoạt động trên HuggingFace. Nó yêu cầu các thông tin như:

  • Token truy cập bạn đã tạo
  • Tiêu đề Space: mục này sẽ là một phần của URL Space sau khi triển khai
  • Tên script chứa mã UI Gradio (mặc định là app.py)
  • Phần cứng của Space; để trống để chỉ dùng CPU (miễn phí)
  • Bất kỳ biến môi trường nào script sử dụng (nơi bạn lưu trữ khóa API và bí mật người dùng một cách an toàn)
  • Phụ thuộc — nhập lần lượt và nhấn ENTER

Sau đó terminal sẽ cung cấp cho bạn liên kết Space đã triển khai. Đây là hình ảnh ví dụ:

image.png

Một điểm tuyệt vời khác của phương pháp triển khai này là Gradio tự động chuyển bản demo thành một REST API hoạt động. Hướng dẫn truy cập và truy vấn luôn nằm ở cuối trang:

Một gif cho thấy phiên bản API của các demo ứng dụng Gradio

Vì vậy, chỉ với một lần triển khai, bạn có cả lưu trữ UI vĩnh viễn cho người dùng không chuyên kỹ thuật và REST API cho đồng nghiệp, bạn bè lập trình viên.

Để biết thêm tuỳ chọn triển khai và chia sẻ, như nhúng demo vào trang web, thêm xác thực Google cho ứng dụng, v.v., hãy truy cập phần “Chia sẻ ứng dụng của bạn” trong tài liệu của Gradio.

Thực tiễn tốt nhất và mẹo dùng Gradio

Khi phát triển giao diện người dùng với Gradio, tuân theo các thực tiễn tốt nhất có thể cải thiện đáng kể trải nghiệm người dùng và khả năng bảo trì ứng dụng. Dưới đây là một số khuyến nghị chính:

1. Dùng script để tổ chức và dễ bảo trì

Tổ chức ứng dụng Gradio trong các script Python để thuận tiện cho quản lý phiên bản, cộng tác và triển khai.

2. Tối ưu phân bổ không gian cho component

Dùng kích thước và công cụ bố cục phù hợp (ví dụ, gr.Column(), gr.Row()) để đảm bảo giao diện cân đối, đáp ứng.

3. Cung cấp thông tin đầy đủ

Tận dụng thuộc tính ‘info’ và ‘label’ để đưa hướng dẫn và ngữ cảnh rõ ràng cho từng component.

4. Xử lý bộ đặc trưng lớn một cách hiệu quả

Với các mô hình có nhiều đặc trưng, hãy dùng đầu vào tệp (CSV, JSON) để cho phép dự đoán theo lô và đơn giản hóa giao diện.

5. Quản lý biến môi trường đúng cách

Dùng python-dotenv cho phát triển cục bộ và đặt biến trong Hugging Face Spaces khi triển khai.

6. Triển khai xử lý lỗi và xác thực

Xác thực đầu vào, cung cấp thông báo lỗi rõ ràng và dùng khối try-except để xử lý lỗi mượt mà.

7. Tối ưu hiệu năng

Triển khai cơ chế cache, tải lười (lazy loading) cho các mô hình lớn và dùng gr.LoadingStatus() cho tác vụ chạy lâu.

8. Thiết kế cho khả năng tiếp cận

Đảm bảo độ tương phản cao, cung cấp văn bản thay thế (alt) cho hình ảnh và bật điều hướng bằng bàn phím cho mọi phần tử tương tác.

9. Tiết lộ dần (progressive disclosure)

Dùng accordion hoặc tab để tổ chức giao diện phức tạp, chỉ hiển thị tuỳ chọn nâng cao khi cần.

10. Cập nhật và bảo trì thường xuyên

Giữ các phụ thuộc được cập nhật, theo dõi lỗi và liên tục cải tiến dựa trên phản hồi người dùng.

11. Tận dụng tài nguyên của HuggingFace

Sử dụng các công cụ và tài nguyên của HuggingFace để tích hợp liền mạch với Gradio, bao gồm kho mô hình và bộ dữ liệu.

12. Lưu trữ mô hình lớn trên HuggingFace Hub

Với các mô hình dạng bảng lớn, hãy tải lên HuggingFace Hub và nạp trực tiếp trong script Gradio của bạn để cải thiện hiệu năng và giảm yêu cầu lưu trữ cục bộ.

13. Tận dụng bộ dữ liệu HuggingFace

Với các bộ dữ liệu lớn, hãy tải lên HuggingFace Hub và truy cập trực tiếp trong ứng dụng Gradio của bạn để hợp lý hóa quản lý dữ liệu và cải thiện thời gian tải.

Kết luận và tài nguyên tham khảo

Trong bài viết này, chúng ta đã học những điều cơ bản về xây dựng giao diện người dùng cho ứng dụng AI bằng Gradio. Chúng ta mới chỉ chạm bề mặt vì Gradio còn cung cấp nhiều tính năng để xây dựng giao diện phức tạp. Chẳng hạn, trạng thái giao diện cho phép ứng dụng của bạn ghi nhớ đầu ra từ lần gọi hàm này sang lần khác. Giao diện phản ứng có thể thay đổi UI một cách động ngay khi đầu vào của người dùng thay đổi. Với Blocks, bạn có thể xây dựng ứng dụng với bố cục và thiết kế tuỳ biến.

Tương tự, hãy xem thêm các tài nguyên liên quan sau để tham khảo thêm:

Chủ đề

Liên quan