Files
popiart-server/docs/stable-media-url-v1.md
T
wtgoku d0318292c1 Make artifact and media metadata first-class server records
Artifact and media metadata were previously reconstructed from job result
refs and JSON sidecar files. This change regularizes metadata into SQLite,
keeps filesystem blobs in place, and preserves backward compatibility via
lazy fallback and backfill from existing job refs and JSON metadata.

Constraint: Blob storage remains on the local filesystem in this phase
Rejected: Migrate blobs into SQLite | larger scope and worse operational profile for current media sizes
Rejected: Hard cutover without fallback | unsafe for historical data already on the test server
Confidence: medium
Scope-risk: moderate
Directive: Treat SQLite as the metadata source of truth; JSON sidecars are compatibility fallback only
Tested: go test ./...; deployed to test server 101.42.99.35; verified /v1/artifacts, /v1/artifacts/:id, signed media URL 200, unsigned content 401
Not-tested: Full historical backfill sweep over all existing artifact rows under production-sized data volume
2026-04-18 23:06:34 +08:00

3.9 KiB
Raw Blame History

popiartServer Stable Media URL V1

这份文档只描述 popiartServer 这一层为了支持稳定媒体 URL 所做的职责扩展,不覆盖 popiartcli 的命令面,也不要求修改 PopiNewAPI 的现有通道实现。

背景

原有本地开发版 popiartServer 更偏向:

  • artifact read-through
  • result_refs_jsondata_url 或上游临时 url
  • GET /artifacts/:id/content 由 server 当场去解码或代理下载

这种实现能跑通基本流程,但不适合多模态 skill 的复用:

  • img2img 经常还要重新拉流或转 base64
  • 上游签名 URL 可能过期
  • 前一个 job 的输出不能稳定地作为下一个 job 的 URL 输入

V1 目标

popiartServer 在不依赖外部对象存储的前提下,先提供一套本地可运行的稳定媒体 URL 能力:

  • 本地上传文件可立即获得稳定 URL
  • 新生成的 job 结果会被 re-host 到本地 media store
  • 新 artifact 会携带 media_idurl
  • image2videovidu* 路由可以直接复用 artifact URL

新接口

POST /v1/media/upload

上传一个本地文件,直接创建 media 记录并返回:

  • id
  • project_id
  • filename
  • content_type
  • size_bytes
  • created_at
  • url
  • visibility
  • sha256

GET /v1/media/:id

读取 media 元数据。这个接口需要登录态,并要求 media 属于当前用户。

GET /v1/media/:id/content

读取稳定内容 URL。

当前语义改为:

  • 元数据接口仍然要求登录态,并要求 media 属于当前用户
  • 内容 URL 使用短期签名 query 参数作为 capability URL
  • 外部模型可以直接 fetch 已签名的 URL,不需要 bearer session
  • 裸的 /content 路径默认不可直接匿名读取

Artifact 行为变化

POST /v1/artifacts/upload 现在不再只把内容塞成 data_url

  1. server 先把上传文件写入本地 media store
  2. 再创建本地 upload job
  3. 最终 artifact 返回:
    • id
    • media_id
    • url
    • visibility
    • sha256
    • storage_status

Job 结果行为变化

对于新的 text2imageimg2imgimage2video 结果:

  1. 先从 PopiNewAPI 或上游临时结果读出真实内容
  2. re-host 到 POPIART_DATA_DIR/media/
  3. local_path + media_id + stable url 写回 result_refs_json

这样新的 artifact 不再依赖上游临时 URL。

本地 media store

V1 的本地开发版不引入 S3/R2/OSS,而是用本地文件系统:

  • blob 文件:POPIART_DATA_DIR/media/blobs/
  • metadata JSONPOPIART_DATA_DIR/media/meta/

如果 POPIART_DATA_DIR 没显式配置,但 POPIART_SQLITE_PATH 已配置,则 DataDir 会自动落到 SQLite 所在目录,避免测试把 media 文件写进源码目录。

当前已打通的 URL 复用

Artifact / media

  • media upload -> stable URL
  • artifact upload -> stable URL
  • artifactGET /artifacts/:id -> url

Runtime output

  • text2image 输出会 re-host
  • img2img 输出会 re-host
  • image2video 输出会 re-host

URL-first dispatch

当前已优先 URL 化的路径是:

  • video.image2video
  • 当模型 ID 以 vidu 开头,且 reference 已有 stable URL 时,server 会优先用 JSON images 传给 /v1/videos

这是为了先覆盖当前测试环境最常用的 viduq2-pro-fast 路由。

兼容策略

旧数据仍然兼容:

  • 如果 result_ref.kind == data_url,继续解码读取
  • 如果 result_ref.kind == url,继续代理下载
  • 如果 result_ref.kind == local_path,优先从本地 media store 读取

也就是说:

  • 历史 artifact 不会立即失效
  • 新 artifact 才开始享受稳定 URL

后续阶段

后续如果要走生产化路线,可以保持接口不变,只把签名 URL 和存储实现替换成对象存储:

  • 本地 media/blobs/ -> S3 / R2 / OSS / COS
  • metadata JSON -> 独立 media table 或对象存储元数据
  • GET /v1/media/:id/content -> CDN / 受控稳定 URL

但这一步不是 V1 本地开发验证的前置条件。