gradio-mlp
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}(MLP 实际完整路径较长,见下方说明) - 数据存储:
/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 或文件访问时推荐)
重要背景: MLP 平台的反向代理实际完整路径很长:
https://ais.mlp.shopee.io/api/notebooks/clusters/.../proxy/{port}/而不是简单的/proxy/{port}。因此:
- Gradio API 调用:通过 FIX_ROOT_JS 中间件从
window.location.pathname动态获取,自动适配- gr.HTML 中的图片/资源路径:必须使用相对路径
./file={path},不要硬编码 root_path
import uvicorn
from fastapi import FastAPI, Request
from fastapi.responses import Response
import gradio as gr
app = FastAPI()
# 反向代理 root 路径自动修复中间件
# 从浏览器 URL 动态获取实际代理路径,无需硬编码
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)
# 注意:必须移除旧 content-length,因为注入 JS 后 body 长度变了
# 不移除会导致浏览器一直处于加载状态(读到一半连接断开)
new_headers = {
k: v for k, v in response.headers.items()
if k.lower() != "content-length"
}
return Response(content=body, status_code=response.status_code,
headers=new_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={绝对路径}(相对路径,自动适配 MLP 反向代理)
#
# ⚠️ 不要使用 {root_path}/file={path} 硬编码方式!
# MLP 实际代理路径: https://ais.mlp.shopee.io/api/notebooks/.../proxy/{port}/
# 硬编码 /proxy/{port}/file=... 会丢失中间路径,导致图片 404
# 相对路径 ./file=... 浏览器会基于当前页面 URL 自动解析为正确的完整路径
def render_table(data):
html = '<table><tr><th>Index</th><th>Image</th></tr>'
for row in data:
img_url = "./file={}".format(row['image_path'])
html += '<tr><td>{}</td>'.format(row["idx"])
html += '<td><img src="{}" style="max-height:120px"></td></tr>'.format(img_url)
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 中的图片/资源路径: 使用相对路径
./file={绝对路径},不要用{root_path}/file=硬编码(MLP 实际代理路径很长,硬编码会 404) - 中间件 content-length: FIX_ROOT_JS 中间件注入 JS 后 body 变大,必须移除原 content-length header,否则浏览器会一直卡在加载状态
- allowed_paths: 使用 FastAPI 方式时必须配置,否则无法访问本地文件
- 显存管理: 加载大模型前用
gc.collect()+torch.cuda.empty_cache()清理 - 端口冲突: MLP 平台多人共用,注意使用不同端口;启动前建议检测端口占用
Weekly Installs
3
Repository
oneboxcream/cla…de-setupFirst Seen
Feb 19, 2026
Security Audits
Installed on
amp3
gemini-cli3
github-copilot3
codex3
kimi-cli3
cursor3