mcpField
H
huggingface-lora-space-builder

huggingface-lora-space-builder

github.com/huggingface云与 DevOps11.2k824 次安装5 天前更新
代码仓库

关于 huggingface-lora-space-builder

用于在 Hugging Face Spaces 创建并发布 Gradio 演示的技能,可通过用户提供的 LoRA 运行推理。它涵盖检查模型卡、选择推理管线、设计任务专属界面,并私下发布 Space。

主要功能

  1. 01检查 LoRA 文件和模型卡
  2. 02选择基础管线与推理方案
  3. 03设计任务专属 Gradio 控件
  4. 04生成 app、requirements 和 README 文件
  5. 05私下发布 Space

适用场景

  1. 01为 Hub 上的 LoRA 创建浏览器演示
  2. 02用定制界面分享扩散模型 LoRA

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/huggingface/skills --skill huggingface-lora-space-builder

安装后在 Claude Code 中输入/huggingface-lora-space-builder确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
adapting-to-the-lora.md
creative-mode.md
tasks.md
zerogpu-and-publishing.md
references/base-models/
krea-2.md
ltx.md
qwen-image.md

详细介绍

Gradio LoRA 空间构建器

在 Hugging Face Spaces 上构建并发布 Gradio 演示,使用用户提供的 LoRA 运行推理。只要有人要求为 LoRA 创建、生成、交付或发布“Space”“演示”“Gradio 应用”或“试验场”,就使用此工具——无论基础模型是 Qwen-Image、Qwen-Image-Edit、LTX,还是其他扩散模型。用户描述自己训练或托管在 Hub 上的 LoRA,并希望分享时,也使用此工具。默认目标是 ZeroGPU 硬件;如果基础模型支持,默认推理库为 diffusers。

产物是一个真实发布的 Space(默认设为私有),用户可以在浏览器中试用,而不是本地脚本。

这类演示的理想效果

演示应针对这款特定 LoRA 精心打造,而不是一个生硬套用 LoRA 的通用模板。即使两款 LoRA 执行相同任务,也可能需要不同的演示:姿势控制视频 LoRA 和视频扩图 LoRA 都输入视频并生成视频,但用户提供的输入、预处理方式和控件完全不同。识别这些差异是这项工作的核心。

具体来说,出色的演示应:

  • 加载迅速、运行流畅——尽量减少模型加载,采用合理的步数,并避免每次调用时进行不必要的计算。
  • 界面只包含这款 LoRA 所需的控件,不多不少。多余的滑块会增加成本,而非提升体验。
  • 清楚展示当前进度——显示进度、在有帮助时展示中间结果、显示所用种子,并在缺少输入时给出明确错误。
  • 遵循模型卡中对 LoRA 的建议:触发词、推荐步数、推荐引导强度、推荐 LoRA 强度和示例输入。
  • 在创意能提升体验时发挥创意——例如交互式画布、前后对比滑块、中间处理结果的并排预览;该简洁时则保持简洁。

工作流

按顺序完成以下阶段。每个阶段收集的信息将决定下一步。

  1. 收集选择管线和设计界面所需的 LoRA 信息。
  2. 选择基础管线和推理方案。
  3. 针对这款 LoRA 的任务和输入设计界面。
  4. 同时编写 app.py、requirements.txt 和 README.md;一次性向用户展示这三项并征求批准。
  5. 发布 Space(设为私有)。

不要在多轮对话中零散提问。请将问题集中起来一次提出。


阶段 1 — 收集 LoRA 信息

必需:Hub 上的 LoRA 仓库(例如 username/my-lora)。

首先,尝试不使用令牌读取仓库。 如果成功,说明仓库是公开的——继续操作。如果返回 401/403,说明仓库是私有或受限的,你需要通过已认证的会话读取。不要立即索要令牌。 先检查用户是否已通过身份验证。

from huggingface_hub import HfApi, get_token

cached_token = get_token()  # picks up HF_TOKEN env var or cached CLI login
if cached_token:
    try:
        info = HfApi().whoami(token=cached_token)
        username = info["name"]
        # info also has fine-grained token scope info if applicable
    except Exception:
        cached_token = None  # token exists but is invalid/expired

然后:

  • 如果存在有效的缓存令牌,并且它可以读取仓库,就使用它。无需提示用户。
  • 如果没有缓存令牌,或者缓存令牌无法读取此私有仓库,就向用户索要令牌——只问一次,并附上下面的说明。

需要索要令牌时(且仅在确实需要索要时):

我需要一个具有写入权限的 Hugging Face 访问令牌(用于读取私有或受限的 LoRA,以及发布 Space)。请在 https://huggingface.co/settings/tokens 创建令牌,并粘贴到这里。

最终阶段发布时会再次使用同一个令牌,因此只需索要一次。

然后读取仓库内容:

  • 列出仓库文件(huggingface_hub.HfApi().list_repo_files(repo_id))。查找 .safetensors、README.md、示例图片/视频以及多个检查点。
  • 获取模型卡(huggingface_hub.ModelCard.load(repo_id))。data 字典中包含结构化字段;text 中是 README 正文。
  • 如果存在多个 .safetensors 文件,选择合适的文件——参见 references/zerogpu-and-publishing.md 中的“选择 LoRA 权重文件”。简而言之:优先选择 README 推荐的文件,其次是 pytorch_lora_weights.safetensors,然后是最新的训练检查点;否则询问用户。

尝试从模型卡中确定以下信息:

  • 基础模型 — base_model 字段,或 README 中提到的模型。通常都能找到。用它来选择管线参考文件(见阶段 2)。
  • 任务 — 如果设置了 pipeline_tag,就使用该字段;否则根据基础模型和 README 文本推断。此技能支持五种任务:text-to-image、image-to-image、text-to-video、image-to-video、video-to-video。
  • 触发词 — 通常称为“trigger word”“instance prompt”或“activation word”;有时也会嵌入示例提示词中。
  • 推荐的推理方案 — 步数、引导比例、真实 CFG 比例、LoRA 比例、分辨率。许多 LoRA 卡片都包含 Python 代码片段;请参考其中的参数(步数、引导比例、CFG、LoRA 比例、dtype)。关于加载方式,请参见 adapting-to-the-lora.md——优先使用 pipe.load_lora_weights(...),而不是代码片段采用的其他加载方式。
  • 示例提示词和示例媒体 — 将它们用作 UI 中的 Gradio 示例。
  • 子任务/具体用例 — 对于图像编辑和视频 LoRA,“这个 LoRA 实际能做什么”与任务类别同样重要。光照调整 LoRA、人脸替换 LoRA 和风格 LoRA 都可能属于 image-to-image,但它们的 UI 各不相同。

如果有些信息无法推断,就询问用户——一次性通过一条消息集中提问。 问题应便于用户作答。询问任务类别时,将五个选项列为带编号的选项。询问子任务时,提供一句说明(“这个 LoRA 能做什么?例如‘调整人像光照’‘应用漫画风格’‘将视频扩展为更宽的纵横比’”)。如果可以根据基础模型或 README 有把握地推断,就不要提问。

如果模型卡完全没有有用信息——没有基础模型、任务或示例——请明确说明:“模型卡中没有可用信息。我需要你告诉我:(1) 基础模型,(2) 这个 LoRA 的用途,(3) 如果知道的话,推荐的步数和引导比例。”


第 2 阶段 — 选择基础流水线

这里需要确定两件事:加载哪个参考文件,以及使用哪个流水线类。这是两个不同的问题——一个基础模型系列文件(例如 qwen-image.md)涵盖多个变体,而同一系列中的变体不一定使用相同的流水线类。选错会导致 Space 虽然能加载,却生成错误的输出,或者在启动时失败。

第 1 步 — 加载此基础模型系列的参考文件。

  • references/base-models/qwen-image.md — 涵盖 Qwen-Image 和 Qwen-Image-Edit 系列(文生图和图生图)。
  • references/base-models/ltx.md — 涵盖 LTX 系列(文生视频、图生视频、视频生视频,包括 IC-LoRAs)。
  • references/base-models/krea-2.md — 涵盖 Krea 2(K2),文生图(使用 RAW 训练,在 Turbo 蒸馏检查点上运行推理/LoRAs)。

如果基础模型不在这些文件中,则此技能尚未提供一等支持。请告知用户,并询问他们是想参考类似模型的方案继续(使用最接近的模型方案并进行调整),还是停止。不要默默猜测。

第 2 步 — 根据基础模型自身的模型卡验证流水线类。此步骤为必需,不可省略。

新基础模型变体可能使用相同的流水线类,但仓库路径不同;也可能使用全新的流水线类。不要只相信参考文件中的表格——表格尽力而为,可能无法及时反映近期发布的内容。提交前请验证:

from huggingface_hub import ModelCard
base_card = ModelCard.load(base_model_id)
# Read base_card.text — find the diffusers inference snippet, note the pipeline class it imports.

基础模型模型卡的 diffusers 代码片段中导入的类才是权威依据。以下是一些这点很重要的实际示例:

  • Qwen-Image-Edit 使用 QwenImageEditPipeline。Qwen-Image-Edit-2509 和 Qwen-Image-Edit-2511 使用 QwenImageEditPlusPipeline——类不同,默认参数不同,且接收图像列表而不是单张图像。将针对 2511 的 LoRA 加载到 QwenImageEditPipeline 上会产生错误输出。
  • LTX-Video 使用 LTXPipeline/LTXImageToVideoPipeline/LTXConditionPipeline。LTX-2 使用来自不同模块路径的 LTX2Pipeline。LTX-2.3 有时需要使用 diffusers 之外的原生流水线。

如果基础模型模型卡完全没有 diffusers 代码片段,则退而使用参考文件中的表格,并告知用户你正在采用该表格的信息,以防他们知道表格未涵盖的情况。

验证只需获取一次 Hub 信息并花几秒钟阅读。跳过验证的代价,就是上一条所述的故障模式——Space 表面上“能正常工作”,实际上却悄悄使用了错误的类。

第 3 步 — Diffusers 与原生流水线。 如果基础模型有 diffusers 流水线类,默认使用 diffusers。Qwen-Image、Qwen-Image-Edit 和大多数 LTX 都属于这种情况。某些 LTX 变体(特别是搭配特定 IC-LoRAs 的 LTX-2.3)需要原生流水线;LTX 参考文件会说明适用情况。Diffusers 提供标准的 load_lora_weights / set_adapters 语义;原生路径则需要针对 LoRA 的衔接代码。


第 3 阶段 — 为这个 LoRA 设计 UI

不要直接套用模板。根据 LoRA 的任务和输入来构思 UI。

阅读 references/tasks.md,了解各类任务的基础 UI 模式(T2I、I2I、T2V、I2V、V2V 的标准输入和输出是什么)。

然后阅读 references/adapting-to-the-lora.md,了解如何思考这个特定 LoRA 的需求,而不只是看任务类别。这个文件是本技能中最重要的。同一任务可能需要截然不同的 UI:姿势控制 LTX LoRA 需要视频输入和姿势提取预览;扩展画布 LTX LoRA 需要宽高比选择器和黑色边缘预览;重新打光 Flux LoRA 需要一张图像和一个用于指示添加光线位置的画笔画布。这些都不能简化为“V2V 模板”或“I2I 模板”。

编写 UI 前先自检。 用一句话描述用户如何在 10 秒内使用这个 Space。如果这句话无法将这个 LoRA 与其他同类任务的 LoRA 区分开来,那么 UI 还不够贴合需求。

通过自检的示例:

  • “上传视频,选择目标宽高比,点击 Generate;模型会填充空白边缘。”
  • “在想要添加光线的位置绘制彩色笔触,选择照明风格,点击 Generate;模型会为照片重新打光。”
  • “上传一段人物动作视频和另一角色的图像;模型会生成一段该角色执行相同动作的视频。”

未通过的示例:

  • “输入提示词并点击生成。”(通用 T2I——请说得更具体。)
  • “上传图像并输入指令。”(通用编辑——具体要做什么编辑?)

Gradio 组件的更新。 Gradio 的组件集会不断演进。优先使用基础组件前,先考虑是否有更合适的新组件——例如,用于编辑类 LoRA 前后对比的 gr.ImageSlider、用于保存偏好设置的 gr.BrowserState,以及用于根据输入动态改变 UI 的 @gr.render。如果不确定某个组件是否存在或其签名是什么,请通过网络获取最新的 Gradio 文档:https://www.gradio.app/docs,不要猜测。

内置组件和 Hub 自定义组件都不够用时——创意模式。 如果 LoRA 的自然输入形式无法用任何 Gradio 组件(内置组件或 Hub 组件)妥善表达——例如点集、笔触、轨迹、带元数据的多区域标注、3D 旋转控件、时间轴拖动条,或其他任何需要用户在媒体上操控对象的形式——请改用 gr.HTML 编写自定义 HTML/JS。请参阅 references/creative-mode.md,了解 Gradio 基础组件(gr.HTML、head= 注入、elem_id 寻址、两种 JS↔Python 状态同步方案)、定义 JSON 线格式的规范以及常见陷阱。不要只因为创意模式看起来很酷就使用它——只有在 LoRA 的输入形式确实需要时才用。完全自定义之前,也不要跳过上面的 Hub 自定义组件选项(例如 gradio_image_annotation)。

媒体输入类 Space 的 gr.Examples。 如果模型自己的仓库中没有合适的示例媒体,请从共享输入池中获取——数据集按模态拆分,方便 HF 数据集查看器渲染合适的缩略图:图像位于 linoyts/repo-to-space-example-inputs,视频位于 linoyts/repo-to-space-example-videos。两个数据集均采用 CC0 许可,并带有 categories 和自然语言 caption 元数据;每个数据集的 README 中都提供相同的筛选和排序方案。选择 2–3 个适合任务的示例,预处理为模型所需的形状,然后将副本放入 Space。设置 cache_examples=True, cache_mode="lazy",这样首次点击时才会缓存,而不是在构建时运行示例(参阅 references/zerogpu-and-publishing.md)。

阶段 4 — 编写 Space 文件

编写文件前,具体告诉用户接下来要做什么——列出实际文件名。不要说“我会编写这三个文件”,而要像这样:

“现在,我将编写发布 Space 所需的三个文件:app.py(Gradio 演示和推理代码)、requirements.txt(Python 依赖项)和 README.md(包含 ZeroGPU 硬件设置的 Space 配置)。然后我会把这三个文件都展示给你审核,再进行发布。”

这样能让用户清楚了解将要生成的内容。不要只说“三个文件”而不列出文件名——这很含糊,也显得没有明确承诺交付内容。

这三个文件紧密相关:requirements.txt 取决于 app.py 导入的内容,而 README.md 的 YAML frontmatter 中设置的 SDK 版本、硬件和 Space 标题也必须相互匹配。请一并编写,然后在发布前通过一条合并消息将这三个文件展示给用户审批。

阅读 references/zerogpu-and-publishing.md,了解 ZeroGPU 规则。以下是一些不那么显而易见的规则:

  • 模型应在模块级别加载到 cuda(不要在 GPU 函数内部延迟加载)。ZeroGPU 使用 CUDA 仿真,因此模型可以在分配 GPU 前完成加载;在模块级别加载也显著快于延迟加载。
  • 执行推理的函数需使用 @spaces.GPU(duration=...) 装饰器。根据任务选择合适的时长——图像生成时长较短,视频生成时长较长。
  • 不要使用 torch.compile——它与 ZeroGPU 的进程模型不兼容。
app.py

根据阶段 1–3 中确定的内容组合代码。不要直接复制模板。每个部分都应有其必要性:

  • 导入项——gradio as gr、torch、spaces、管道类,以及预处理所需的内容。
  • 常量——LORA_REPO、BASE_MODEL、推荐步数、引导系数、LoRA 缩放系数、触发词。
  • 模块级模型加载——通过 from_pretrained 加载管道,调用 .to("cuda"),再调用 load_lora_weights。如果 LoRA 仓库是私有的,请传入 token=os.environ["HF_TOKEN"]。
  • 预处理函数(如果需要)——姿态提取、填充、掩码构建等。CPU 代码可以在模块级别运行;GPU 代码必须放在 @spaces.GPU 函数内部。
  • 推理函数——使用 @spaces.GPU(duration=...) 装饰器。验证输入、应用触发词、构建管道参数并返回输出。
  • Gradio Blocks——创建阶段 3 中的 UI,并将其连接到推理函数。

需要正确处理的常见事项:

  • 返回实际使用的种子值以及结果,以便用户复现结果。
  • 在推理函数上使用 gr.Progress(track_tqdm=True),以显示 diffusers 的内部进度条。
  • 验证输入——缺少必填输入时,应抛出 gr.Error("Please upload an image first."),而不是让管道报出晦涩的错误。
  • 在 gr.Examples 中使用 cache_examples=True, cache_mode="lazy"——单独使用 cache_examples=True 会在构建时运行示例,并在 ZeroGPU 上失败;延迟模式会等到用户首次点击时再缓存。
  • 当 gr.Examples 设置了 fn= 时,点击某一行会按位置向 fn 传入仅 inputs= 中的值——因此,不在 inputs 中的每个 fn 参数都必须设置默认值,否则点击时会报错:TypeError: missing N required positional arguments。运行事件会连接所有组件,因此手动测试和冒烟测试都能通过,只有点击示例时才会出问题。解决方法:为额外参数设置默认值(保留 inputs=[prompt]),或列出所有输入并为其提供完整的示例行,或移除 fn/outputs,这样点击时就只会填充字段。
requirements.txt

不要只提供一份固定的最精简列表,然后寄希望于一切顺利。这份“最精简”列表适用于普通的 T2I LoRA,但只要基础模型使用视觉语言文本编码器、生成视频,或涉及任何不简单的预处理,就会出问题。应根据 Space 实际需要的内容生成 requirements.txt,按以下顺序检查:

  1. **app.py 中每个顶层的非标准库导入。**如果 app.py 执行 import cv2,requirements.txt 就需要包含 opencv-python。如果执行 from controlnet_aux import OpenposeDetector,就需要包含 controlnet-aux。逐项检查所有导入。(注意下一段中的排除项——有些导入是运行时内置的,无需列出。)
  2. **基础模型参考资料的“Required dependencies”小节。**每个基础模型文件都会列出流水线所需的不明显额外依赖——例如 Qwen-Image(Qwen 2.5-VL 文本编码器)需要 torchvision,LTX(视频导出)需要 imageio[ffmpeg] 等。全部添加。这些依赖不会从导入中自动识别,因为流水线的组件会在加载时传递导入它们。
  3. **LoRA 自己的模型卡明确提到要安装的依赖。**如果 LoRA README 中有自己的 pip install 代码块,就把其中的依赖列出来。
  4. diffusers/机器学习栈:diffusers、transformers、accelerate、peft、safetensors。默认使用普通版本(不固定版本)。如果基础模型参考资料指出模型需要从 GitHub 安装,就将 diffusers 换为 git+https://github.com/huggingface/diffusers(近期发布的模型经常需要如此,Qwen-Image-Edit-2511 就是一个当前的例子)。

requirements.txt 中不要列出以下内容:

  • gradio——由 README.md 的 YAML frontmatter 中的 sdk_version: 字段控制,而不是由 requirements.txt 控制。在 requirements 中列出它,轻则被忽略,重则与 SDK 发生版本冲突。只在 README 中设置版本。
  • torch——由 Space 运行时提供。只有需要固定特定版本时才添加(这种情况很少见,通常意味着其他地方出了问题)。
  • spaces——由 Space 运行时提供。只有需要固定特定版本时才添加。
  • huggingface_hub——由 Space 运行时提供。只有需要固定特定版本时才添加。

这四个包在 ZeroGPU 容器中已预装。对于非基础依赖,“宁可包含,不要遗漏”这种做法是对的;但对于基础依赖,这样做是错的,因为固定版本可能与运行时管理的版本冲突。

**对于其他所有依赖,拿不准时,宁可添加,不要遗漏。**Space 实际上没用到的包只会让构建稍微变慢。缺少必要的包则会导致启动时崩溃,用户也更难查明原因。这两种代价并不对等——促使我们制定这条规则的测试失败,恰恰属于第二种情况。

不过,有两个特定依赖不适合不假思索地添加,因为它们在 ZeroGPU 上经常弊大于利:

  • xformers——固定依赖特定的 torch 版本,经常导致冲突。ZeroGPU 运行时提供的是 torch 2.8+,因此任何固定的 xformers 版本都必须支持该版本。在 Blackwell 上还有一个额外问题:xformers 的 FA3 调度会错误地识别硬件(FA3 内核仅支持 sm_90a 上的 Hopper,但调度器以 device_capability >= (9, 0) 为判断条件,Blackwell 也符合该条件),随后会在启动内核时因 CUDA invalid argument 崩溃。如果使用 xformers attention 的 Space 遇到这种情况,请在模块加载时禁用 FA3 调度:

    try:
        from xformers.ops.fmha import _set_use_fa3
        _set_use_fa3(False)
    except Exception:
        pass
    

    只有当 app.py 实际使用 xformers 时才添加。

  • flash-attn——需要构建步骤,而且经常安装失败。与 xformers 一样,还要注意它是否与 torch 2.8+ 兼容。只有当 app.py 实际使用 flash-attn 时才添加。

只有在有充分理由时才固定其他版本(例如,已知的不兼容问题,或需要匹配模型卡中的配置)。

README.md

Space 通过 README.md 顶部的 YAML frontmatter 进行配置。此 frontmatter 用于选择 ZeroGPU。

---
title: <human-readable title>
emoji: 🎨
colorFrom: pink
colorTo: purple
sdk: gradio
sdk_version: <current Gradio version>
app_file: app.py
pinned: false
hardware: zero-a10g
short_description: <one short line for the Space tile, ~60 chars max>
models:
  - <base model repo>
  - <lora repo>
---

# <title>

A short description with links to the LoRA and base model.

关键字段:

  • sdk: gradio — ZeroGPU 必需。
  • sdk_version — 与你所基于的 Gradio 版本一致。请查询当前版本(pip index versions gradio,或查看 https://www.gradio.app),不要猜测。
  • hardware: zero-a10g — ZeroGPU 的旧版字符串。实际硬件是 NVIDIA RTX Pro 6000 Blackwell,但标识符为 zero-a10g。ZeroGPU 面向 PRO、Team 和 Enterprise 账户提供;如果用户没有订阅,Space 将回退到 CPU。如果你怀疑用户没有订阅 PRO,请说明这一点。
  • models: — 列出基础模型和 LoRA 仓库。此字段可启用 Hub 缓存和发现功能。
  • short_description — 显示在 Space 磁贴上。请保持简短(约 60 个字符以内)。 Hub 的 YAML 验证器会拒绝过长的值,并从 https://huggingface.co/api/validate-yaml 返回 400 错误;在调用 create_repo 或 upload_file 时,这会显示为 HfHubHTTPError。服务器端的确切限制没有文档说明,且可能会变化,因此请以磁贴上可见的长度为目标,不要贴着上限填写。如果遇到 400 错误,几乎总是缩短此字段即可解决。用一句话描述 Space 的功能就足够了——较长的说明可以放在下方 YAML 之后的 README 正文中。
一次性批量审批——操作顺序很重要

这里的原则是:**先写完全部三个文件,再在一条消息中一并展示。**不要采用“写 app.py → 讨论它 → 写 requirements → 讨论它 → 写 README → 讨论它”的方式。即使你没有明确请求审批,这种节奏也会产生三次审批,因为用户在每个文件写完后都需要作出回应。

具体来说:

  1. 依次编写 app.py、requirements.txt 和 README.md,中间不要插入任何说明文字。 文件之间不要有评论。不要说“现在我来写下一个”。不要在编写每个文件时描述其用途。只需连续给出这三个文件。
  2. **然后在一条消息中请求对全部三个文件进行审批。**可以这样说:“这是 Space——app.py(N 行)、requirements.txt 和 README.md。请检查并确认发布,或告诉我需要修改的内容。”
  3. 用户只需回复一次,即可说明他们希望对这三个文件中的哪些内容作出修改。

应避免的做法:

  • 写完 app.py 后、写其他文件之前,逐步讲解它的结构或设计选择。相关说明只能放在编写前的公告(第 4 阶段开头),或所有文件都完成后的单次审批消息中。
  • 询问“准备好继续下一个了吗?”或“要我继续写 requirements 吗?”——这些都等于针对单个文件请求审批。
  • 只展示一个文件,并表示“准备好后再展示下一个”——这同样会陷入上述问题。
  • 将这三个文件中的任何一个视为可选内容或后续事项。它们应作为一个整体交付。

如果用户看到第一个文件后中途提出反馈或问题,可以正常回应——但仍须遵守这条规则:下次编写代码时,应一并提供所有剩余文件,而不是一次只给一个。


阶段 5 — 发布 Space

使用阶段 1 中经过身份验证的会话。默认设为私有,让用户先检查 Space,再将其设为公开。创建前,请向用户确认目标用户名:“我将发布到 {username}/{space_name}——确认吗?”

from huggingface_hub import HfApi, SpaceHardware

api = HfApi(token=hf_token)
username = api.whoami()["name"]
repo_id = f"{username}/{space_name}"

api.create_repo(
    repo_id=repo_id,
    repo_type="space",
    space_sdk="gradio",
    space_hardware=SpaceHardware.ZERO_A10G,
    private=True,
    exist_ok=True,
)

# Upload files
for path in ["app.py", "requirements.txt", "README.md"]:
    api.upload_file(path_or_fileobj=path, path_in_repo=path,
                    repo_id=repo_id, repo_type="space")

如果 LoRA 仓库本身是私有或受限的,Space 需要在运行时使用令牌下载 LoRA。请将令牌设为 Space 密钥:

api.add_space_secret(repo_id=repo_id, key="HF_TOKEN", value=HF_TOKEN)

……并在 app.py 中使用 token=os.environ["HF_TOKEN"] 加载 LoRA。

上传后,请在分享前运行以下冒烟测试——构建是异步运行的,静默失败(例如 weight_name 错误、缺少依赖项、流水线类错误)只会在首次推理时显现。冒烟测试通过后,分享 Space URL(https://huggingface.co/spaces/{repo_id}),并告知用户 Space 是私有的——他们需要登录才能查看。请注意,构建需要几分钟;如果发生故障,可在 https://huggingface.co/spaces/{repo_id}/logs/container 查看日志。

发布时失败(构建开始前):

  • 在 create_repo 或 upload_file 期间,https://huggingface.co/api/validate-yaml 返回 HfHubHTTPError: 400 Bad Request。README YAML 未通过服务器端验证。最常见的原因是 short_description 太长;有时则是多余字段或格式错误的值。解决方法:将 short_description 缩短到约 60 个字符,然后重试。如果缩短后问题仍未解决,请检查字段名称是否有拼写错误或值是否无效(例如,colorFrom/colorTo 中使用了不受支持的颜色,或 hardware 字符串无效)。
  • 使用 space_hardware="zero-a10g" 调用 create_repo 时出现 403:用户未使用 PRO/Team/Enterprise,因此无法在创建时申请 ZeroGPU。解决方法:不带 space_hardware 重试 create_repo,并在 README YAML 中保留 hardware: zero-a10g——Space 会在 CPU 上创建。之后,用户可以升级到 PRO(自动升级为 ZeroGPU),或申请社区 GPU 资助(通过 Space 的硬件设置申请)。
  • upload_file 返回 401/403:令牌没有写入权限。解决方法:向用户索取具有写入权限的令牌。

常见构建失败(构建开始后):

  • 在 load_lora_weights 中,LoRA 的 weight_name 不匹配 → 通过 list_repo_files 检查实际文件名。
  • 基础模型受限,但未将令牌设为 Space 密钥。
  • 未分配 ZeroGPU(用户未使用 PRO)→ Space 会退回到 CPU,速度慢到无法使用。
  • Diffusers 版本无法识别流水线类 → 在 requirements.txt 中固定使用 git diffusers。
  • 模块加载时缺少依赖项 → 参见上文的 requirements.txt 推导规则;最常见的情况是缺少传递依赖项,例如 Qwen-Image 文本编码器所需的 torchvision。

如果构建失败,请提出查看日志并给出修复方案。


阶段 6 — 对 Space 进行冒烟测试

在宣布 Space 已完成并将 URL 发给用户之前,先端到端测试一次。有几种故障模式(错误的 weight_name、错误的 pipeline 类、缺少传递依赖、受限基础模型的令牌问题)虽然能顺利构建,但只会在首次推理时暴露出来。gradio Python 包自带的 CLI 正好可以完成这项测试——gradio info 会返回端点签名,gradio predict 会执行实际推理。它们都随 Space 已需要的 gradio pip 依赖一起提供,因此运行此技能的任何环境中都可以使用。

步骤 1 — 等待构建完成。 create_repo 会立即返回,但容器镜像仍在构建。轮询 HfApi().get_space_runtime(repo_id).stage,直到状态变为 RUNNING:

import time
from huggingface_hub import HfApi
api = HfApi(token=hf_token)
while True:
    stage = api.get_space_runtime(repo_id).stage
    if stage == "RUNNING": break
    if stage in {"BUILD_ERROR", "RUNTIME_ERROR", "CONFIG_ERROR"}:
        raise RuntimeError(f"Build failed: {stage}. Logs: https://huggingface.co/spaces/{repo_id}/logs/container")
    time.sleep(15)

如果构建失败,请获取容器日志(https://huggingface.co/spaces/{repo_id}/logs/container),查看回溯信息并提出修复方案。不要对尚未运行的 Space 执行 gradio info——它会卡住或返回 503。

步骤 2 — 验证端点签名。 gradio info {repo_id} --token {hf_token} 会返回公开的端点及其参数类型。查看输出并确认:(a)端点存在(默认为 /predict,但 Blocks Space 通常会根据 Python 函数名使用自定义名称);(b)参数顺序与 app.py 中的声明一致;(c)文件类型参数按预期显示 "type": "filepath"。如果其中任何一项不符,面向用户的 UI 可能看起来正常,但 API 调用会失败——修复后重新上传。

步骤 3 — 执行一次实际推理。 选择最轻量且可用的输入——LoRA 卡片中最简单的示例,或 gr.Examples 中的一个条目。对于私有 Space,请传入 --token。文件输入的负载格式为 {"path": "...", "meta": {"_type": "gradio.FileData"}}。

# Text-to-image:
gradio predict {repo_id} /predict '{"prompt": "...", "aspect_ratio": "1:1", ...}' --token $HF_TOKEN

# Image-to-image (file input):
gradio predict {repo_id} /predict '{"input_image": {"path": "/tmp/sample.jpg", "meta": {"_type": "gradio.FileData"}}, "prompt": "..."}' --token $HF_TOKEN

如果没有用于 I2I 的本地示例图片,可以从 LoRA 仓库获取一张(hf_hub_download(repo_id, filename="example.png")),或从基础模型卡片获取。

创作模式 Space 的注意事项。 gradio info 和 gradio predict 只会测试 Python 端点——无法告诉你 gr.HTML 组件中的自定义 JS 是否有效。如果 Space 使用创作模式(参见 references/creative-mode.md),API 冒烟测试通过后,请在浏览器中打开 Space URL,并在分享之前验证一次交互效果。对于这类 Space,最常见的故障模式就是服务端运行正常,但 JS 已损坏。

步骤 4 — 解读结果。

  • 成功返回且输出看起来合理 → 完成。分享 URL。
  • HTTPError 503 / "Space is sleeping" → Space 在步骤 1 和步骤 3 之间进入休眠状态。唤醒它(api.restart_space(repo_id))并重试。
  • 推理错误提及 weight_name / safetensors → app.py 中的 LoRA 文件名与 LoRA 仓库中的实际文件不匹配。重新检查 list_repo_files,修正 weight_name=,然后重新上传 app.py。
  • 推理错误提及缺少 pipeline 类或属性 → diffusers 版本太旧。将 requirements.txt 改为 git+https://github.com/huggingface/diffusers,然后重新上传。
  • 模块加载时发生 ImportError → 缺少依赖。将其添加到 requirements.txt 并重新上传。运行时日志(/logs/run)会指出缺少哪个包。
  • OOM → 降低默认分辨率或步数,或选择更小的基础模型变体。
  • 超时 / 卡住 → 增大 @spaces.GPU(duration=...) 的时长,然后重新上传。

冒烟测试的目的是将“用户发现问题并反馈”变成“你在分享之前发现问题并修复”。即使构建成功,也不要跳过测试——对于使用非简单 pipeline 的 Space,最常见的故障模式就是构建成功但推理失败。


应避免的做法

  • 使用通用的“一个演示适用于所有 LoRA”模板。这个技能的核心就是量身定制。
  • 在 GPU 函数中延迟加载模型。这在 ZeroGPU 上会很慢,还会导致启动错误直到首次请求时才暴露。
  • 使用 torch.compile。ZeroGPU 不支持。
  • 在 ZeroGPU 上使用 cache_examples=True,却不设置 cache_mode="lazy"。
  • 使用 gr.Examples(fn=…),但其 inputs 未涵盖推理函数所需的参数——构建成功,点击第一个示例时却因缺少位置参数而崩溃。
  • 将 LoRA 权重上传到 Space 仓库。运行时应从 LoRA 自己的 Hub 仓库拉取。
  • 到最后才询问 HF 令牌,结果发现 LoRA 一直是私有的,无法读取模型卡。
  • 暴露 diffusers 的所有参数。挑出对这个 LoRA 最重要的 1–3 个控制项。
  • 发布 Space 后,在聊天回复中写冗长的开场白。Space URL 才是交付内容;简短总结即可。

评论

支持 Markdown