Shopee MLP 平台 Gradio 应用开发专用技能。包含反向代理配置、图片/视频展示、数据浏览、FastAPI 集成等常用模式。适用于多模态大模型的训练可视化、数据浏览、评估结果展示等场景。
Install
npx skillscat add oneboxcream/claude-code-setup/gradio-mlp Install via the SkillsCat registry.
SKILL.md
MLP 平台 Gradio 应用开发指南
你是 Shopee MLP 平台上 Gradio 应用的开发专家。用户从事多模态大模型(图片/视频理解与生成)的训练、数据构建和评估工作。
环境信息
- Python: 3.8.13 (不支持 3.9+ 语法如
match/case、type X = ...等) - Gradio: 4.44.1
- 平台: Shopee MLP web-shell
- 反向代理格式:
/proxy/{port} - 数据存储:
/home/work/aigc_video_bpfs_3/挂载盘
核心规则
1. 反向代理配置(必须)
MLP 平台通过 /proxy/{port} 反向代理访问 Gradio 服务。每个 Gradio 应用都必须正确配置。
方式 A:纯 Gradio(简单应用推荐)
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--port", type=int, default=7860)
parser.add_argument("--root_path", type=str, default=None,
help="MLP reverse proxy path, e.g. /proxy/7860")
args = parser.parse_args()
demo.launch(
server_name="0.0.0.0",
server_port=args.port,
root_path=args.root_path or f"/proxy/{args.port}",
)
# 启动: python app.py --port 7860
# 访问: https://{mlp-host}/proxy/7860方式 B:FastAPI + Gradio(需要 API 或文件访问时推荐)
import uvicorn
from fastapi import FastAPI, Request
from fastapi.responses import Response
import gradio as gr
app = FastAPI()
# 反向代理 root 路径自动修复中间件
FIX_ROOT_JS = b"""<script>
(function(){
var c = window.gradio_config;
if (c) {
var p = window.location.pathname.replace(/\\/$/, '');
c.root = p;
}
})();
</script>
</head>"""
@app.middleware("http")
async def fix_gradio_root(request: Request, call_next):
response = await call_next(request)
ct = response.headers.get("content-type", "")
if "text/html" in ct:
body = b""
async for chunk in response.body_iterator:
body += chunk
body = body.replace(b"</head>", FIX_ROOT_JS, 1)
return Response(content=body, status_code=response.status_code,
headers=dict(response.headers), media_type="text/html")
return response
# Gradio 挂载
demo = gr.Blocks()
# ... 构建 UI ...
ALLOWED_PATHS = ["/home/work/aigc_video_bpfs_3/"]
gr.mount_gradio_app(app, demo, path="/", allowed_paths=ALLOWED_PATHS)
uvicorn.run(app, host="0.0.0.0", port=7860)2. 图片展示
方式 A:gr.Image 组件(单张,推荐)
gr.Image(type="pil", label="Result", interactive=False, height=320)方式 B:gr.Gallery(多张浏览)
gr.Gallery(label="Results", columns=4, height="auto", object_fit="contain")方式 C:gr.HTML 自定义表格(带缩放悬浮,数据浏览推荐)
# 需要 FastAPI 方式,配置 allowed_paths
# 图片 URL 格式: /file={绝对路径}
def render_table(data, root_path=""):
html = '<table><tr><th>Index</th><th>Image</th></tr>'
for row in data:
img_url = f"{root_path}/file={row['image_path']}"
html += f'<tr><td>{row["idx"]}</td>'
html += f'<td><img src="{img_url}" style="max-height:120px"></td></tr>'
html += '</table>'
return html
# CSS 悬浮放大
CSS = """
table img { transition: transform 0.2s; cursor: pointer; }
table img:hover { transform: scale(3); z-index: 100; box-shadow: 0 4px 20px rgba(0,0,0,0.3); }
"""3. 视频展示
# 视频输出组件
gr.Video(label="Generated Video", interactive=False, autoplay=True)
# 视频输入
gr.Video(label="Input Video", sources=["upload"])4. 常用 UI 布局模式
图像处理/生成 工作流
with gr.Blocks(title="App Name") as demo:
gr.Markdown("## Title")
with gr.Row():
with gr.Column():
input_image = gr.Image(type="pil", label="Input", height=320)
prompt = gr.Textbox(label="Prompt", lines=2)
with gr.Accordion("Advanced Options", open=False):
steps = gr.Slider(1, 100, value=50, label="Steps")
seed = gr.Slider(-1, 2147483647, value=-1, step=1, label="Seed")
resolution = gr.Dropdown(
choices=["720*1280", "480*832", "512*512"],
value="512*512", label="Resolution"
)
run_btn = gr.Button("Generate", variant="primary")
with gr.Column():
output = gr.Image(type="pil", label="Result", interactive=False)
status = gr.Textbox(label="Status", interactive=False)
run_btn.click(fn=process, inputs=[input_image, prompt, steps, seed, resolution],
outputs=[output, status])多 Tab 评估结果展示
with gr.Blocks() as demo:
with gr.Tabs():
with gr.Tab("Metrics"):
metrics_html = gr.HTML()
with gr.Tab("Samples"):
gallery = gr.Gallery(columns=4)
with gr.Tab("Comparison"):
with gr.Row():
gr.Image(label="Model A")
gr.Image(label="Model B")
gr.Image(label="Ground Truth")数据浏览 + 分页
with gr.Blocks() as demo:
with gr.Row():
search = gr.Textbox(label="Search", scale=3)
filter_dd = gr.Dropdown(choices=["All", ...], label="Filter", scale=1)
sort_dd = gr.Dropdown(choices=["Original", "By Name"], label="Sort", scale=1)
table_html = gr.HTML()
with gr.Row():
prev_btn = gr.Button("< Prev")
page_info = gr.Markdown("Page 1 / N")
next_btn = gr.Button("Next >")5. 大模型推理集成
# 全局模型变量 + 延迟加载(节省显存)
model_480p = None
model_720p = None
def load_model(resolution):
global model_480p, model_720p
import gc, torch
# 释放旧模型
if resolution == "480P" and model_720p is not None:
del model_720p
model_720p = None
gc.collect()
torch.cuda.empty_cache()
# 加载新模型 ...
# 队列模式(长时间推理必须)
demo = gr.Blocks().queue()
# 进度条集成
def process(image, progress=gr.Progress(track_tqdm=True)):
# tqdm 进度会自动同步到 Gradio UI
for step in tqdm(range(100)):
...6. 启动模板
始终使用以下命令行参数模式:
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--port", type=int, default=7860)
parser.add_argument("--root_path", type=str, default=None)
args = parser.parse_args()
demo.queue().launch(
server_name="0.0.0.0",
server_port=args.port,
root_path=args.root_path or f"/proxy/{args.port}",
)注意事项
- Gradio 启动慢: 约需 15 秒才能响应请求,测试时需等待
- Python 3.8 兼容: 不要使用
match/case、type别名、X | Y类型联合等 3.9+ 语法 - gr.HTML 中的图片路径: 必须手动拼接
root_path前缀,格式{root_path}/file={绝对路径} - allowed_paths: 使用 FastAPI 方式时必须配置,否则无法访问本地文件
- 显存管理: 加载大模型前用
gc.collect()+torch.cuda.empty_cache()清理 - 端口冲突: MLP 平台多人共用,注意使用不同端口