Prhub

#30621 Fix image URL response for multiple outputs

原始 PR 作者 AuFlow 合并时间 2026-07-15 19:49 文件变更 2 提交数 6 评论 8 代码增减 +269 / -40

执行摘要

修复多输出时 URL 只返回单个的问题,新增 variant 回退支持

Issue #30648 报告当 n=2 且 response_format='url' 时,响应只返回一个 data 项,而 b64_json 正常返回多个。用户期望每个输出对应一个 URL。PR 旨在使 URL 格式响应与 b64_json 格式对齐,并确保本地持久化输出也能通过 variant 查询参数下载。

此 PR 值得精读,原因:

  • 清晰的变体索引设计,通过列表和索引映射处理多输出。
  • 良好的回退逻辑,兼容旧数据结构。
  • 并发上传优化和明确的错误提示。
  • 测试覆盖全面(8 个用例)。
    建议关注 _build_image_response_kwargs 中 url 分支的循环构建方式,以及下载端点如何使用辅助函数处理 variant。
讨论亮点

Review 中 gemini-code-assist[bot] 提出三个关键改进:

  • cloud_urls 索引对齐:原始实现过滤了 None 值导致索引不对齐,建议存储包含 None 的原始列表。已修复。
  • 并发上传:初始版本顺序 await 逐个上传,建议使用 asyncio.gather 并发上传以提升响应速度。已采用。
  • 下载端点错误提示:当请求的 variant 已上传到云但本地文件不存在时,原先使用 item.get('url') 可能指向错误变体,建议使用 _select_image_variant_cloud_url 提供准确的 cloud URL。已修改。

实现拆解

  1. 新增辅助函数_get_request_field_or_extra 统一获取字段;_upload_and_cleanup_images 使用 asyncio.gather 并发上传多个文件;_fallback_image_urls 根据输出数量生成 variant 形式的本地回退 URL 列表;_select_image_variant_path_image_variant_index_select_image_variant_cloud_url_raise_if_image_variant_not_found 支持按 variant 检索文件路径或云 URL。
  2. 修改 _build_image_response_kwargs:接受可选的 cloud_urlsfallback_urls 列表参数,为每个输出文件独立构建 ImageResponseData,而非使用单个 url;移除必须配置云存储的限制。
  3. 端点 generationsedits 适配:调用 _upload_and_cleanup_images 上传所有文件并收集 URL 列表;在 IMAGE_STORE 中存储 file_pathsurlsnum_outputs;传递列表至响应构建函数。
  4. 下载端点 download_image_content 重构:使用 _select_image_variant_path 读取 indexed file paths;若文件未持久化但云 URL 存在则返回重定向;使用 _raise_if_image_variant_not_found 给出明确的 404 错误(如 'Image variant 5 not found')。
  5. 测试覆盖:新增单元测试文件,覆盖多输出 URL 响应、variant 回退、路径选择、cloud URL 对齐、越界变体错误等场景。
文件 模块 状态 重要度
python/sglang/multimodal_gen/runtime/entrypoints/openai/image_api.py 图像 API modified 8.82
python/sglang/multimodal_gen/test/unit/test_openai_image_api.py 单元测试 added 7.46

关键符号

_build_image_response_kwargs _fallback_image_urls _select_image_variant_path _select_image_variant_cloud_url _raise_if_image_variant_not_found _upload_and_cleanup_images generations edits download_image_content

关键源码片段

python/sglang/multimodal_gen/runtime/entrypoints/openai/image_api.py entrypoint

核心变更文件,修改响应构建、上传、下载端点以支持多输出 URL 和 variant 回退。

def _fallback_image_urls(
    request_id: str, num_outputs: int, is_persistent: bool
) -> list[str] | None:
    '''生成回退 URL 列表。每个输出对应一个 variant URL。'''
    if not is_persistent:
        return None
    if num_outputs <= 1:
        # 单个输出时不加 variant 参数,保持向后兼容
        return [f'/v1/images/{request_id}/content']
    # 多个输出时,每个输出使用不同的 variant 索引
    return [
        f'/v1/images/{request_id}/content?variant={idx}' for idx in range(num_outputs)
    ]# _build_image_response_kwargs 中的 url 分支被重写为循环:
elif resp_format == 'url':
    data = []
    for idx, path in enumerate(save_file_path_list):
        # 优先使用云存储 URL(可能为 None),否则使用本地回退 URL
        url = (
            cloud_urls[idx]
            if cloud_urls and idx < len(cloud_urls) and cloud_urls[idx]
            else fallback_urls[idx]
            if fallback_urls and idx < len(fallback_urls)
            else None
        )
        data.append(
            ImageResponseData(
                url=url,
                revised_prompt=prompt,
                file_path=os.path.abspath(path) if is_persistent else None,
            )
        )
    ret = {'data': data}

评论区精华

cloud_urls 列表索引对齐 正确性

gemini-code-assist[bot] 指出过滤 None 值导致 cloud_urls 列表与 file_paths 索引不对齐,影响 variant 选取。

结论:已修复,存储原始 cloud_urls 列表(含 None),保持索引对应。 · 已解决

并发上传优化 性能

建议使用 asyncio.gather 并发上传多个文件,替代顺序 await。

结论:已采用 _upload_and_cleanup_images 使用 asyncio.gather。 · 已解决

下载端点变体错误提示 正确性

当请求变体已上传云但本地文件不存在时,应显示对应变体的 cloud URL 而非直接使用 item.get('url')。

结论:已修改代码使用 _select_image_variant_cloud_url 获取准确 URL。 · 已解决

风险与影响

主要风险包括:

  • 数据兼容性:IMAGE_STORE 新增 urlsfile_paths 列表字段,旧持久化数据只有 urlfile_path。辅助函数已包含回退逻辑,兼容旧结构。
  • 并发上传:使用 asyncio.gather 增加内存占用,但图像文件通常不大,风险可控。
  • Variant 解析_image_variant_index 处理了类型转换异常,但超大整数值可能引发性能边缘问题。
  • 依赖:仅新增 import asyncio,无其他依赖。

影响所有使用 OpenAI 图像生成 API(/v1/images/generations/v1/images/edits)且设置 response_format='url'n>1 的用户。修复后 URL 响应与 b64_json 行为一致,每个输出返回独立 URL。本地持久化模式下可通过 variant 查询参数下载特定输出。后端存储结构轻微扩展,不影响现有数据。团队需验证向后兼容性。

数据兼容性 并发控制

关联 Issue

#30648 [Bug] OpenAI image API returns only one URL when `n > 1` and `response_format="url"`

完整报告

参与讨论