哼哼猫文档
本页内容

文件上传 API

POST https://api.meowload.net/openapi/v1/uploads 为音频、图片和视频提供同一套上传流程,返回 uploadId,需要传文件时还会返回单次 PUT 地址。

申请使用 Authorization: Bearer <你的 API Key>。API 积分余额须大于 0,但申请上传不扣积分;业务任务独立检查余额和计费,单价见 开发者管理中心 的「计费规则」。

使用流程

  1. 计算原文件的精确字节数和 SHA-256,POST /uploads 申请上传。
  2. upload 非空时,将完整原始文件 PUT 到返回地址,原样携带全部返回请求头,不附加哼哼猫 API Key。等待 PUT 返回成功的 2xx。
  3. upload 为 null 时,表示已命中本用户可复用的已验证内容,跳过 PUT。
  4. 将 uploadId 直接交给支持的业务任务。音视频转文字 使用 mediaType: "audio" 申请,随后 POST /transcriptions,提交 {uploadId, language?, speakerLabels?}。

不提供公开 complete、上传状态 GET、分片、地址续签、文件列表或删除端点。服务端在任务后台确认上传并校验文件,验证失败通过该业务任务交付。

音频、图片、视频共用申请接口,但业务仍会核对实际媒体类型。当前转录只接收音频 uploadId,本指南不表示图片/视频任务 API 已经开放。

大小与格式

mediaType接收范围
audio可解码音频,最多 1 GiB(1,073,741,824 字节)
imageJPEG、PNG、WebP,最多 30 MiB(31,457,280 字节)、1 亿像素
videoMP4,最多 500 MiB(524,288,000 字节)、600 秒

声明、文件名和 Content-Type 不决定真实格式,仍会验证文件内容、大小、摘要与元数据。文件验证通过,也不代表任意业务或模型都能接收。

M4A/MP4 容器可只包含音频;音频的附带封面不视为真实视频轨道。含真实视频轨的文件不能通过声明 audio 来转录,应先提取音轨再上传,或使用转录的音视频文件直链输入。

申请上传

curl https://api.meowload.net/openapi/v1/uploads \
  -H 'Authorization: Bearer <你的 API Key>' \
  -H 'Content-Type: application/json' \
  -d '{"mediaType":"audio","fileName":"meeting.mp3","sizeBytes":12345678,"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"}'

示例大小和摘要仅用于说明,需按实际文件计算。

字段必填规则
mediaType是audio、image 或 video
fileName否展示用文件名,不作为格式校验依据
sizeBytes是原文件精确字节数,正整数,须符合所选类型的限制
sha256是完整原文件的 SHA-256,64 位十六进制字符

申请 JSON 正文最多 8 KiB,不包含文件正文,也不接受存储路径、模型、价格、内部素材 ID 或调用方指定的请求 ID。上传申请没有公开幂等参数。

响应与 PUT

HTTP 200:

{
  "uploadId": "0123456789abcdefghijklmn",
  "upload": {
    "method": "PUT",
    "url": "https://uploads.example.com/signed-object?signature=EXAMPLE",
    "headers": {"Content-Type":"application/octet-stream"},
    "expiresAt": "2030-01-01T01:00:00.000Z"
  }
}

使用完整返回地址和全部返回请求头,包括可能存在的校验头。上面的 headers 是示例,不是固定请求头清单。发送文件原始字节,不使用 multipart 表单:

curl --request PUT '<upload.url>' \
  --header 'Content-Type: application/octet-stream' \
  --header '<其他返回请求头>: <原值>' \
  --data-binary @meeting.mp3

PUT 地址最长有效 1 小时,同时受当前上传会话剩余时间约束。upload.expiresAt 是本次签名地址的期限,不是已验证文件的可用期限。中断后在地址有效期内重传同一个完整文件,不支持分片续传;地址过期则重新申请,不往原地址发送不同内容。

PUT 成功只表示文件送达,不表示通过真实媒体验证。收到 2xx 后直接创建业务任务,不需要解析 ETag、调用 complete 或轮询上传状态。

已验证内容复用响应:

{"uploadId":"0123456789abcdefghijklmn","upload":null}

只有明确的 null 才表示可跳过 PUT,并不表示业务任务已经完成。

多任务复用与期限

同一有效 uploadId 可以创建多个参数不同的任务,前提是属于本用户、源文件当前可用且符合对应业务的媒体规则。同用户轮换 Key 后仍可引用,他人的 Key 不可使用。

每次业务 POST 创建独立任务,可能分别收费,即使引用同一 uploadId。文件身份不是任务幂等键;创建回包丢失时不要自动重试任务 POST。拿到任务 ID 后保存它,只重试免费的结果 GET。

不额外设置“uploadId 创建满 24 小时便禁止新任务”的规则。原上传会话与来源当前使用资格仍然有效,uploadId 不保证永久保存;源文件不再可用时可重新申请上传。已经保存的转录文字不依赖原文件保留,仍可查询。

Node.js:流式计算摘要并上传

Node.js 24 可使用文件支持的 Blob,示例不会把 1 GiB 文件整体放进内存。摘要计算至 PUT 期间不要修改文件。示例仅创建一次转录,后续按 转录指南 每 3 秒查询。

import { createHash } from "node:crypto"
import { createReadStream, openAsBlob } from "node:fs"

const base = "https://api.meowload.net/openapi/v1"
const auth = { Authorization: "Bearer <你的 API Key>", "Content-Type": "application/json" }
const path = "./meeting.mp3"
const file = await openAsBlob(path)
const hash = createHash("sha256")
for await (const chunk of createReadStream(path)) hash.update(chunk)

const application = await fetch(`${base}/uploads`, {
  method: "POST",
  headers: auth,
  body: JSON.stringify({ mediaType: "audio", fileName: "meeting.mp3", sizeBytes: file.size, sha256: hash.digest("hex") }),
})
if (!application.ok) throw new Error(`Upload request failed: ${application.status}`)
const { uploadId, upload } = await application.json()
if (upload !== null) {
  const put = await fetch(upload.url, { method: upload.method, headers: upload.headers, body: file })
  if (!put.ok) throw new Error(`PUT failed: ${put.status}`)
}
const created = await fetch(`${base}/transcriptions`, {
  method: "POST", headers: auth,
  body: JSON.stringify({ uploadId, language: "auto", speakerLabels: false }),
})
if (!created.ok) throw new Error(`Create failed: ${created.status}`)
console.log("Save this task ID:", (await created.json()).id)

API 请求错误沿用非 2xx 与 {message, code?, detail?}。文件真实校验失败通过业务任务返回,发生在执行预扣之前。完整参数与返回字段见 API 参考。