Table of Content

Important

Tham khảo

1. Introduction Machine Learning Operation (MLOps)

1.1 Introduction to MLOps

Machine Learning Life Cycle

Các mô hình học máy sẽ sử dụng X và y để học mối quan hệ, từ đó đưa ra dự đoán. Một số mô hình cơ bản gồm:

  • Decision Tree: chia nhánh dựa trên điều kiện để phân loại hoặc dự đoán.
  • KNN (K-Nearest Neighbors): dự đoán dựa vào các điểm dữ liệu gần nhất.
  • Linear Regression: mô hình hóa mối quan hệ tuyến tính giữa biến độc lập và biến phụ thuộc.
  • Logistic Regression: phân loại nhị phân dựa trên xác suất. image 79.png Trong thực tế khi triển khai một sản phẩm MLO thì ta phải biết được vòng đời của một dự án học máy (ML). Ở đây gồm nhiều bước nối tiếp và lặp lại. Quy trình này đảm bảo mô hình không chỉ hoạt động chính xác mà còn mang lại giá trị thực tiễn: image 1 39.png
  1. Define Problem: Xác định rõ bài toán cần giải quyết và mục tiêu kinh doanh. Đây là nền tảng để chọn đúng hướng tiếp cận và mô hình phù hợp.
  2. Collect and Process Data: Thu thập dữ liệu, làm sạch, xử lý và chuẩn hóa để đảm bảo chất lượng đầu vào cho mô hình.
  3. Train Models: Huấn luyện mô hình học máy với dữ liệu đã xử lý, thử nhiều thuật toán khác nhau.
  4. Evaluate Models: Đánh giá hiệu quả mô hình bằng các chỉ số như Accuracy, Precision, Recall, F1-score… để chọn ra mô hình tối ưu.
  5. Deployment: Đưa mô hình vào môi trường thực tế để phục vụ người dùng hoặc tích hợp vào hệ thống. Quy trình này không tuyến tính mà có tính lặp lại. Ví dụ, sau khi đánh giá, ta có thể quay lại bước huấn luyện hoặc xử lý dữ liệu để cải thiện chất lượng mô hình. 💡 Tip: Luôn coi vòng đời ML là một quá trình liên tục và lặp lại, thay vì nghĩ nó chỉ kết thúc khi mô hình được triển khai. Để đưa mô hình học máy từ phòng thí nghiệm vào thực tiễn sản xuất, ta cần một hệ thống công cụ và quy trình quản lý toàn diện – gọi là MLOps.

Khái niệm MLOps

  • MLOps (Machine Learning Operations) là tập hợp các công cụthực hành tốt nhất (best practices) giúp triển khai, giám sát và bảo trì mô hình học máy trong môi trường sản xuất.
  • Mục tiêu chính: đảm bảo mô hình ổn định, đáng tin cậy và có thể tái sử dụng/lặp lại trong quy mô lớn. image 2 37.png
  1. Machine Learning: Xây dựng và huấn luyện mô hình từ dữ liệu.
  2. Develop: Phát triển, thử nghiệm và tích hợp mô hình với hệ thống.
  3. Operate: Vận hành, giám sát hiệu suất, cập nhật và bảo trì mô hình. Ba bước này liên tục xoay vòng, đảm bảo mô hình luôn được cải thiện và thích ứng với dữ liệu hoặc nhu cầu thực tế mới.

1.2. Introduction to Gradio

Developer vs End-user

Một trong những thách thức lớn trong học máy là khoảng cách giữa developer (người phát triển)end-user (người dùng cuối).

  • Developer thường triển khai mô hình bằng môi trường như Jupyter Notebook, sử dụng mã nguồn để thử nghiệm và kiểm chứng.
  • End-user thì không quen với code, họ chỉ muốn sử dụng mô hình thông qua một giao diện đơn giản, trực quan. Điều này dẫn đến vấn đề: mô hình tuy hoạt động tốt với developer, nhưng end-user lại không thể tiếp cận trực tiếp. image 3 35.png

Development Flow

Để giải quyết vấn đề trên, cần có UI/Application đóng vai trò cầu nối:

  1. Developer viết code và triển khai mô hình.
  2. UI/App (giao diện web hoặc ứng dụng) được xây dựng để hiển thị và cho phép tương tác với mô hình.
  3. End-user chỉ cần thao tác qua UI mà không cần biết đến code phía sau. image 4 30.png Đây chính là lý do Gradio ra đời: giúp rút ngắn khoảng cách giữa developer và end-user, cho phép tạo nhanh giao diện tương tác với mô hình ML mà không cần viết HTML, CSS, hay JavaScript.

2. Web application

Web application (ứng dụng web) là phần mềm chạy trên trình duyệt, cho phép người dùng tương tác thông qua giao diện trực quan mà không cần cài đặt thêm phần mềm cục bộ. Đây là cầu nối quan trọng giúp end-user tiếp cận mô hình học máy mà không cần biết đến code.

Cấu trúc công nghệ nền tảng

image 5 28.png Một ứng dụng web thường được xây dựng dựa trên bộ ba công nghệ chính:

  • HTML (HyperText Markup Language): Định nghĩa nội dung và cấu trúc của trang web, ví dụ như văn bản, tiêu đề, bảng, biểu mẫu.
  • CSS (Cascading Style Sheets): Quy định giao diện và phong cách (màu sắc, bố cục, font chữ), giúp web trở nên trực quan và dễ sử dụng.
  • JavaScript (JS): Đảm nhận hành vi động (tương tác, sự kiện, xử lý dữ liệu), làm cho ứng dụng web trở nên linh hoạt và có tính tương tác cao.

Liên hệ với học máy

Trong ngữ cảnh Machine Learning, web application chính là lớp giao diện mà end-user sử dụng để nhập dữ liệu (văn bản, hình ảnh, âm thanh…) và nhận kết quả dự đoán/trả về từ mô hình. 💡 Tip: Nếu không có ứng dụng web, người dùng sẽ phải trực tiếp chạy code trong notebook hoặc terminal – điều này gây khó khăn cho những ai không có kiến thức kỹ thuật.

3. Gradio

Gradio là một thư viện Python mã nguồn mở cho phép xây dựng giao diện người dùng (UI) để demo và triển khai các mô hình Machine Learning. Với Gradio, developer có thể tạo ứng dụng web trực quan chỉ với vài dòng code, mà không cần viết HTML, CSS hay JavaScript.

Các tính năng chính của Gradio

image 6 26.png

  1. Easy setup – Cài đặt và sử dụng nhanh chóng chỉ trong môi trường Python.
  2. UI components – Cung cấp nhiều thành phần giao diện sẵn có (textbox, image uploader, audio recorder…).
  3. No JavaScript, CSS – Loại bỏ nhu cầu phải code frontend, giúp tập trung vào logic của mô hình.
  4. Shareable links – Tạo link chia sẻ công khai để người khác có thể thử mô hình ngay trong trình duyệt.
  5. Integration with Hugging Face – Hỗ trợ tích hợp trực tiếp với Hugging Face Spaces để deploy mô hình.
  6. Provided models, APIs, hosting – Cung cấp môi trường hosting, các API tích hợp và mô hình mẫu để sử dụng nhanh.

Build first Gradio web

import gradio as gr
# Hàm xử lý
def greet(name):
    return "Hello, " + name
# Tạo giao diện
demo = gr.Interface(
    fn=greet,          # Hàm cần gọi
    inputs=["text"],   # Kiểu input
    outputs=["text"],  # Kiểu output
)
# Chạy app
demo.launch()

Sau khi chạy python 1.first_demo.py, terminal sẽ hiển thị link cục bộ:

Running on local URL: http://127.0.0.1:7860
To create a public link, set `share=True` in `launch()`.

Mở link trên trình duyệt, bạn sẽ thấy một giao diện gồm:

  • Ô nhập tên (input).
  • Nút Submit.
  • Kết quả trả về: “Hello, [Tên]”. image 7 21.png

Input/Output of ML application

Trong một ứng dụng Machine Learning, dữ liệu có thể đi vào (input) và đi ra (output) dưới nhiều dạng khác nhau. Tùy thuộc vào bài toán, mô hình sẽ tiếp nhận loại dữ liệu phù hợp và trả về kết quả tương ứng. Các loại Input và Output phổ biến

  1. Text
    • Input: Chuỗi ký tự, đoạn văn, câu hỏi.
    • Output: Văn bản mới như câu trả lời, bản dịch, tóm tắt.
  2. Image
    • Input: Ảnh tĩnh (jpg, png, bmp).
    • Output: Ảnh đã được xử lý (nhận diện, chỉnh sửa, tạo mới).
  3. Speech (Âm thanh/Giọng nói)
    • Input: File âm thanh hoặc ghi âm trực tiếp.
    • Output: Văn bản chuyển đổi từ giọng nói (ASR) hoặc giọng nói tổng hợp (TTS).
  4. Video
    • Input: Chuỗi hình ảnh động hoặc video clip.
    • Output: Video được phân tích, tạo phụ đề, nhận diện hoạt động hoặc tổng hợp mới. image 8 21.png Các dạng phổ biến:
  • Text → Text: Chatbot, dịch máy, tóm tắt văn bản.
  • Image → Text: OCR (nhận diện ký tự từ ảnh).
  • Speech → Text: Voice assistant, ghi biên bản tự động.
  • Video → Text: Video captioning, phân tích hành vi. 💡 Tip: Một ứng dụng ML có thể kết hợp nhiều dạng input/output cùng lúc (ví dụ: ứng dụng học ngôn ngữ nhận input giọng nói, trả output văn bản và phát lại giọng đọc chuẩn).

4. Hand-on Gradio

Gradio interface

  • Interface là lớp high-level (cấp cao) trong Gradio.
  • Nó cho phép bạn xây dựng giao diện web hoặc demo cho mô hình Machine Learning (hoặc bất kỳ hàm Python nào) chỉ với vài dòng code.
  • Các thành phần chính của một Interface:
    • fn: hàm Python cần gọi.
    • inputs: kiểu dữ liệu đầu vào (textbox, image, audio…).
    • outputs: kiểu dữ liệu đầu ra (text, label, image…). image 9 20.png

Input: Text

Textbox

Docs: https://www.gradio.app/docs/gradio/textbox

  • Textbox là thành phần input cơ bản, cho phép người dùng nhập chuỗi văn bản (string) hoặc hiển thị kết quả đầu ra dạng text.
  • Có thể tuỳ chỉnh label (nhãn hiển thị) và placeholder (gợi ý nhập liệu).
import gradio as gr
def greet(name):
    return "Hello, " + name
demo = gr.Interface(
    fn=greet,
    inputs=gr.Textbox(label="Enter your name", placeholder="Type your name here..."),
    outputs=gr.Textbox(label="Greeting")
)
demo.launch()

image 10 19.png

HighlightedText

Docs: https://www.gradio.app/docs/gradio/highlightedtext

  • HighlightedText hiển thị văn bản trong đó các phần tử (spans/tokens) được tô màu hoặc gắn nhãn dựa trên category (loại) hoặc giá trị số.
  • Hữu ích cho các tác vụ như:
    • Sentiment Analysis (phân tích cảm xúc – highlight từ tích cực/tiêu cực).
    • POS Tagging (gắn nhãn từ loại).
    • NER (Nhận diện thực thể tên riêng).
import gradio as gr
def highlight_sentiment(text):
    # Giả sử đây là kết quả phân tích cảm xúc
    return [("love", "positive"), ("amazing", "positive")]
demo = gr.Interface(
    fn=highlight_sentiment,
    inputs=gr.Textbox(label="Input text", placeholder="I love this amazing course.", lines=4),
    outputs=gr.HighlightedText(
        label="Token highlights",
        color_map={"positive": "\#10b981", "negative": "\#ef4444"}
    ),
    title="HighlightedText Demo",
    description="Tiny sentiment demo: highlights a few positive/negative words.",
    examples=[
        "I love this course, it is amazing!",
        "The movie was good but the ending was terrible.",
        "What a wonderful day, I'm so happy.",
        "The service was bad and the food was awful."
    ]
)
demo.launch()
  • Người dùng nhập câu vào ô Input text.
  • Output sẽ hiển thị cùng câu văn nhưng những từ mang sắc thái positive (xanh) hoặc negative (đỏ) được highlight.
  • Ví dụ: “I love this course, it is amazing!” → highlight từ love, amazing. image 11 19.png

Input Code

Docs: https://www.gradio.app/docs/gradio/code

  • Code là một thành phần input đặc biệt, cung cấp code editor ngay trong giao diện web.
  • Nó có thể được dùng để:
    • Cho phép người dùng nhập và chạy đoạn code.
    • Hiển thị code như một dạng output view.
import gradio as gr
# Hàm xử lý code Python
def execute_python(code):
    try:
        # chạy code bằng hàm eval/exec
        exec_globals = {}
        exec(code, exec_globals)
        return "Executed successfully"
    except Exception as e:
        return str(e)
demo = gr.Interface(
    fn=execute_python,
    inputs=gr.Code(
        label="Python Code", \#Text mô tả cho block code
        language="python",   \#Highlight syntax theo ngôn ngữ. 
											       \#Không phải là setting ngôn ngữ
        value="print('Hello, World!')\nprint(2 + 2)",
        lines=5
    ),
    outputs=gr.Textbox(label="Output", lines=5),
    title="Simple Python Code Runner",
    description="Enter Python code and see the output"
)
demo.launch()

image 12 18.png

Inputs: Image

Image component trong Gradio

  • Image là một thành phần giao diện cho phép:
    • Input: người dùng tải ảnh lên để xử lý.
    • Output: hiển thị ảnh trả về từ mô hình.
  • Có thể lựa chọn định dạng dữ liệu đầu vào:
    • type="numpy": ảnh dưới dạng NumPy array.
    • type="pil": ảnh dưới dạng đối tượng PIL.
import gradio as gr
import numpy as np
from PIL import Image
def get_image_info(image):
    """Lấy thông tin cơ bản của ảnh"""
    if image is None:
        return "No image provided"
    
    # Trường hợp ảnh dưới dạng numpy array
    if isinstance(image, np.ndarray):
        height, width = image.shape[:2]
        channels = image.shape[2] if len(image.shape) == 3 else 1
        return f"Image size: {width}x{height}, Channels: {channels}, Type: NumPy array"
    
    # Trường hợp ảnh dưới dạng PIL Image
    elif isinstance(image, Image.Image):
        width, height = image.size
        return f"Image size: {width}x{height}, Mode: {image.mode}, Type: PIL Image"
    
    else:
        return f"Unsupported image type: {type(image)}"
demo = gr.Interface(
    fn=get_image_info,
    inputs=gr.Image(label="Upload an Image", type="pil"),
    outputs=gr.Textbox(label="Image Information"),
    title="Image Information Tool",
    description="Upload an image to see its basic information"
)
demo.launch()
  • Người dùng chọn một ảnh từ máy tính.
  • Giao diện sẽ hiển thị thông tin cơ bản của ảnh:
    • Kích thước (width × height).
    • Mode (RGB, Grayscale…).
    • Loại dữ liệu (NumPy hoặc PIL).

ImageEditor trong Gradio

ImageEditor là một thành phần mở rộng của Image, cho phép:

  • Input mode: Người dùng tải ảnh lên hoặc chụp từ webcam rồi thực hiện các thao tác chỉnh sửa cơ bản.
  • Output mode: Hiển thị lại ảnh sau khi đã chỉnh sửa hoặc xử lý.
import gradio as gr
def process_image(image_data):
    if image_data is None:
        return None
    # Lấy ảnh đã chỉnh sửa từ composite layer
    return image_data.get("composite", None)
with gr.Blocks(title="Simple Image Editor") as demo:
    gr.Markdown("# 🖼️ Simple Image Editor")
    with gr.Row():
        image_editor = gr.ImageEditor(
            label="Edit Your Image",
            type="pil",
            sources=["upload", "webcam"],   # Cho phép tải ảnh hoặc dùng webcam
            transforms=["crop"],             # Cho phép crop ảnh
            brush=gr.Brush(default_size=10), # Bút vẽ
            eraser=gr.Eraser(default_size=10) # Công cụ tẩy
        )
        output_image = gr.Image(label="Edited Result", type="pil")
    # Gắn hàm xử lý khi có thay đổi ảnh
    image_editor.change(
        fn=process_image,
        inputs=[image_editor],
        outputs=[output_image]
    )
demo.launch()
  • Người dùng tải ảnh lên và có thể:
    • Vẽ thêm chi tiết bằng brush.
    • Cắt ảnh (crop).
    • Xoá vùng bằng eraser.
  • Ảnh sau khi chỉnh sửa sẽ hiển thị ở ô kết quả bên phải.

Output: Label

Output: JSON

Multi-Input / Multi-Output

Inputs: File

5. Gradio Block

Layout

Row

  • Row trong Gradio Blocks cho phép sắp xếp các component nằm ngang cạnh nhau.
  • Điều này giúp bố trí form, input và output gọn gàng, trực quan hơn thay vì xếp dọc.
import gradio as gr
# Hàm xử lý
def greet(name: str, times: float) -> str:
    n = int(times or 1)
    name = name or "there"
    return "\n".join([f"Hello, {name}!" for _ in range(max(n, 1))])
with gr.Blocks(title="Blocks + Row: simplest") as demo:
    gr.Markdown("## Simple Blocks + Row demo")
    # Bố trí input theo hàng ngang
    with gr.Row():
        name = gr.Textbox(label="Name", placeholder="Type your name")
        times = gr.Number(value=1, label="Times")
    # Bố trí output và nút bấm theo hàng ngang
    with gr.Row():
        btn = gr.Button("Greet")
        out = gr.Textbox(label="Output")
    # Sự kiện click nút
    btn.click(greet, inputs=[name, times], outputs=out)
demo.launch()

Column

  • Column trong Gradio Blocks giúp xếp các component theo chiều dọc (từng dòng một).
  • Khác với Row (nằm ngang), Column phù hợp cho form nhập liệu tuần tự từ trên xuống. image 13 17.png
import gradio as gr
# Hàm xử lý
def greet(name: str, times: float) -> str:
    n = int(times or 1)
    name = name or "there"
    return "\n".join([f"Hello, {name}!" for _ in range(max(n, 1))])
with gr.Blocks(title="Blocks + Column: simplest") as demo:
    gr.Markdown("## Simple Blocks + Column demo")
    with gr.Column():
        name = gr.Textbox(label="Name", placeholder="Type your name")
        times = gr.Slider(1, 5, value=1, step=1, label="Times")
        btn = gr.Button("Greet")
        out = gr.Textbox(label="Output", interactive=False)
    # Liên kết sự kiện
    btn.click(greet, inputs=[name, times], outputs=out)
demo.launch()

Event handling

  • Event handling trong Gradio là cơ chế giúp ứng dụng phản hồi lại hành động của người dùng.
  • Các hành động này có thể là:
    • Nhập dữ liệu (keystrokes).
    • Nhấn nút (click).
    • Gửi form (submit).
    • Chọn giá trị từ menu/dropdown.
  • Khi sự kiện xảy ra, một hàm xử lý (handler) sẽ được gọi để cập nhật kết quả.
import gradio as gr
# Hàm xử lý
def greet(name: str, times: float) -> str:
    n = int(times or 1)
    name = name or "there"
    return "\n".join([f"Hello, {name}!" for _ in range(max(n, 1))])
def live_preview(name: str) -> str:
    return f"Typing: {name or ''}"
def on_times_change(times: float) -> str:
    return f"Times set to {int(times or 1)}"
with gr.Blocks(title="Event Handling: simplest") as demo:
    gr.Markdown("## Event Handling demo")
    with gr.Row():
        with gr.Column():
            name = gr.Textbox(label="Name", placeholder="Type your name and press Enter")
            times = gr.Slider(1, 5, value=1, step=1, label="Times")
            greet_btn = gr.Button("Greet")
        with gr.Column():
            live_md = gr.Markdown("(Start typing to see live preview)")
            times_md = gr.Markdown("Times set to 1")
            out = gr.Textbox(label="Output", interactive=False)
    # Đăng ký các event
    name.input(live_preview, inputs=name, outputs=live_md)
    name.submit(greet, inputs=[name, times], outputs=out)
    greet_btn.click(greet, inputs=[name, times], outputs=out)
    times.change(on_times_change, inputs=times, outputs=times_md)
demo.launch()

image 14 17.png

  • Khi gõ tên trong textbox → hiện preview ngay lập tức.
  • Khi thay đổi slider Times → cập nhật số lần lặp.
  • Khi nhấn nút Greet → xuất kết quả chào hỏi nhiều lần theo giá trị slider.

Event Listeners

State (lưu trữ dự liệu trong session)

gr.State: Đây là component đặc biệt cho phép lưu biến tạm trong workflow để truyền dữ liệu giữa các bước.

6. Advanced Usage. Ad

Multi-step Workflows

  • Multi-step workflow là quy trình xử lý nhiều bước nối tiếp nhau.
  • Thay vì chỉ có một input → một output, ứng dụng ML phức tạp thường cần chuỗi pipeline để biến đổi dữ liệu qua nhiều giai đoạn.
  • Gradio hỗ trợ thiết kế các pipeline này dễ dàng thông qua Blocks và event handling. image 15 17.png Ví dụ pipeline xử lý ảnh
  1. Upload: Người dùng tải ảnh lên.
  2. Preprocessing: Làm sạch, resize, chuẩn hóa dữ liệu ảnh.
  3. Extract Edges: Áp dụng bộ lọc phát hiện biên (Canny, Sobel…).
  4. Enhance Images: Cải thiện chất lượng ảnh (sharpening, denoising, super-resolution).

Ví dụ pipeline xử lý văn bản

  1. Type/Paste text: Người dùng nhập hoặc dán văn bản.
  2. Clean: Xử lý trước như xóa ký tự đặc biệt, chuẩn hóa chính tả.
  3. Summarize: Tóm tắt văn bản dài thành phiên bản ngắn gọn.
  4. Sentiment: Phân tích cảm xúc (tích cực, tiêu cực, trung lập).

Complex Apps

Đoạn code hiện thực một ứng dụng Gradio dạng Blockshai pipeline (ảnh và văn bản), mỗi pipeline gồm nhiều bước tuần tự với state nội bộ, event handlingthanh tiến độ (Progress). Bên dưới là giải thích theo cụm chức năng.

Tiện ích ảnh: chuẩn hoá input & các bước xử lý

**_to_pil(img)**

def _to_pil(img: Any) -> Optional[Any]:
	if img is None:
		return None
	if Image is None:
		raise RuntimeError("Pillow not available. Please install 'pillow'.")
	if isinstance(img, Image.Image):
		return img
	arr = np.asarray(img)
	if not (arr.ndim == 2 or (arr.ndim == 3 and arr.shape[2] in (3, 4))):
		raise ValueError("Unsupported image array shape")
	return Image.fromarray(arr.astype(np.uint8))

Chuyển mọi kiểu ảnh (PIL hoặc numpy.ndarray) về PIL Image để thống nhất xử lý. Nó:

  1. trả về None nếu không có ảnh;
  2. kiểm tra Pillow đã cài chưa;
  3. nếu nhận ndarray, xác nhận shape hợp lệ (2D hoặc 3D với 3/4 kênh) rồi ép kiểu uint8Image.fromarray(...).

**preprocess_image(img, max_side=512, progress=None)**

def preprocess_image(img: Any, max_side: int = 512, progress: Optional[gr.Progress] = None) -> Optional[Any]:
	if img is None:
		gr.Warning("Please upload an image first.")
		return None
	if progress:
		progress(0, desc="Loading image…")
	pil = _to_pil(img)
	if pil is None:
		return None
	if progress:
		progress(0.3, desc="Resizing…")
	# Keep aspect ratio, cap the longest side
	w, h = pil.size
	scale = min(1.0, max_side / max(w, h))
	if scale < 1.0:
		pil = pil.resize((int(w * scale), int(h * scale)))
	if progress:
		progress(0.7, desc="Auto-contrast…")
	pil = ImageOps.autocontrast(pil)
	if progress:
		progress(1.0, desc="Done")
	return pil

Bước tiền xử lý: cảnh báo nếu thiếu ảnh; cập nhật progress; giữ tỉ lệgiới hạn cạnh dài nhấtmax_side; sau đó tăng tương phản tự động bằng ImageOps.autocontrast. Trả về ảnh PIL đã tiền xử lý.

**detect_edges(img, strength=1.0, progress=None)**

def detect_edges(img: Any, 
								 strength: float = 1.0, 
								 progress: Optional[gr.Progress] = None) -> Optional[Any]:
	if img is None:
		gr.Warning("Please run Preprocess first or upload an image.")
		return None
	pil = _to_pil(img).convert("L")  # grayscale
	if progress:
		progress(0.2, desc="Computing gradients…")
	arr = np.asarray(pil, dtype=np.float32)
	# Use numpy gradient as a simple edge detector (fast and dependency-free)
	gy, gx = np.gradient(arr)
	mag = np.hypot(gx, gy)
	mag *= (255.0 / (mag.max() + 1e-6))
	if progress:
		progress(0.7, desc="Applying strength…")
	mag = np.clip(mag * float(max(0.1, strength)), 0, 255).astype(np.uint8)
	out = Image.fromarray(mag)
	if progress:
		progress(1.0, desc="Done")
	return out

Bước edge detection đơn giản, không phụ thuộc thư viện ngoài:

  1. ép ảnh về grayscale;
  2. dùng numpy.gradient để lấy gx, gy, tính độ lớn gradient mag;
  3. chuẩn hoá về 0–255, nhân thêm hệ số strength, clip và ép uint8;
  4. trả ảnh biên dưới dạng PIL.

**enhance_image(img, progress=None)**

def enhance_image(img: Any, progress: Optional[gr.Progress] = None) -> Optional[Any]:
	if img is None:
		gr.Warning("Please run Detect Edges first.")
		return None
	pil = _to_pil(img)
	if progress:
		progress(0.5, desc="Enhancing…")
	# Simple enhancement via auto-contrast again; could be extended
	pil = ImageOps.autocontrast(pil)
	if progress:
		progress(1.0, desc="Done")
	return pil
  • Bước tăng cường: hiện demo dùng lại autocontrast (có thể thay bằng sharpen, denoise, SR…).

**run_all_image(image, strength=1.0, progress=None)**

def run_all_image(image: Any, strength: float = 1.0, progress: Optional[gr.Progress] = None):
	if image is None:
		gr.Warning("Please upload an image.")
		return None, None, None
	# Use the same progress object for simplicity
	p = preprocess_image(image, progress=progress)
	e = detect_edges(p, strength=strength, progress=progress)
	h = enhance_image(e, progress=progress)
	return p, e, h
  • Chạy cả ba bước theo thứ tự và trả về bộ (preprocessed, edges, enhanced).

Tiện ích văn bản: làm sạch, tóm tắt, cảm xúc

  • clean_text(text)

    Kiểm tra rỗng và chuẩn hoá khoảng trắng/ngoặc kép: " ".join(text.strip().split()).

  • summarize_text(text, max_sentences=2)

    Tóm tắt ngây thơ theo câu: tách câu bằng regex (?<=[.!?])\s+ và lấy N câu đầu.

  • sentiment(text) -> (label, score)

    Lexicon-based cực gọn: đếm chênh lệch số từ thuộc tập tích cực/tiêu cực → gán nhãn positive/negative/neutral. Điểm số được chuẩn hoá thô theo độ dài (xấp xỉ trong [-1, 1]).

Xây UI với Blocks, Tabs, State và Progress

  • Khởi tạo app:

    with gr.Blocks(title="Complex Multi-step Workflows", theme=gr.themes.Soft()) as demo:
        gr.Markdown("# Complex Apps with Gradio Blocks ...")
        with gr.Tabs():
            with gr.TabItem("Image Pipeline"):
                ...
            with gr.TabItem("Text Pipeline"):
                ...

    Dùng theme Soft, tạo 2 Tab cho ảnh và văn bản.

  • Thành phần và state (Image tab):

    gr.Image (input), gr.Slider (độ mạnh biên), các nút Step 1/2/3, Run All, Reset; ba ô gr.Image output.

    Dùng st_pre = gr.State()st_edge = gr.State() để lưu ảnh trung gian giữa các bước.

  • Wiring sự kiện (Image tab):

    • btn_pre.click(_preprocess_and_store, inputs=[image_in], outputs=[out_pre, st_pre])

      Chạy preprocess_image, vừa hiển thị vừa lưu vào state.

    • btn_edge.click(_edge_and_store, inputs=[st_pre, strength], outputs=[out_edge, st_edge])

      Lấy từ st_pre, tính biên với strength, hiển thị + lưu state.

    • btn_enh.click(_enhance, inputs=[st_edge], outputs=out_enh)

      Lấy từ st_edge, enhance và hiển thị.

    • btn_run_all.click(_run_all, ...) chạy trọn pipeline và cũng đồng bộ lại state.

    • btn_reset_img.click(_reset_img, ...) đưa mọi thành phần về rỗng.

  • Thành phần và state (Text tab):

    gr.Textbox nhập văn bản; gr.Accordion chứa tùy chọn max_sents; các nút Clean / Summarize / Sentiment, Run All, Reset; output gồm gr.Textbox (clean & summary) và gr.Label (sentiment).

    Dùng st_clean, st_sum để chuyển tiếp dữ liệu giữa bước 1→2→3.

  • Wiring sự kiện (Text tab):

    • btn_clean.click(_clean_and_store, inputs=text_in, outputs=[out_clean, st_clean])
    • btn_sum.click(_summarize_and_store, inputs=[st_clean, max_sents], outputs=[out_sum, st_sum])
    • btn_sent.click(_sentiment, inputs=st_sum, outputs=out_sent)
    • btn_run_all_txt.click(_run_all_txt, inputs=[text_in, max_sents], outputs=[out_clean, out_sum, out_sent, st_clean, st_sum])
    • btn_reset_txt.click(_reset_txt, ...) để xoá nội dung và state.
  • Progress & cảnh báo người dùng:

    Mỗi handler nhận progress=gr.Progress(...) để hiển thị % và mô tả (“Loading image…”, “Resizing…”, …). Khi người dùng sai thứ tự, dùng gr.Warning(...) để báo ngay trên UI.

  • Bật hàng đợi & chạy:

    demo.queue().launch()

    queue() mở hàng đợi yêu cầu (hữu ích khi thao tác tốn thời gian); launch() khởi chạy app.

Customization

Theming

JS/HTML integration

7. Deployment & Sharing

Để chia sẻ cho người khác truy cập từ internet, ta cần tạo public link.

  • Thêm tham số share=True trong hàm launch():
demo.launch(share=True)
  • Sau khi chạy, ngoài URL cục bộ, Gradio sẽ sinh thêm một URL công khai (dạng https://xxxx.gradio.live).
  • Link này có hiệu lực trong thời gian giới hạn (thường 1 tuần). image 16 14.png

Hugging Face Spaces (free hosting)

Chúng ta có thể build một demo đơn giản và nhúng vào trang web của chúng ta.

Dockerize a Gradio app

Quiz and Discuss


  • Trong thực tế thì nhiều bài nghiên cứu ưu tiên thực hiện demo trên Gradio

    → Hugging Face hơn là Streamlit.

  • Trong các công ty cũng thường dùng C# để đóng gói vì tính bảo mật, chuyên nghiệp, hiệu quả. Trong khi đó Python thì dùng Docker để đóng gói.

  • Khi sử dụng Gradio với mô hình lớn (LLM, diffusion model), ta nên dùng cách nào để tối ưu hiệu suất?

    Dùng queue (**queue=True**) để xử lý yêu cầu theo hàng đợi → Đúng. Điều này giúp quản lý request tốt hơn khi nhiều người dùng truy cập cùng lúc, tránh crash.