FurryFans开放平台

接入文档

FurryFans 开放能力通过 furface.furryfans.cn 提供 HTTP API。 所有请求使用 AK/SK 签名鉴权 —— 没有 Bearer 模式,没有降级路径。

服务与端点

服务端点说明
FurFind 毛毛定位POST /v1/detect返回画面中每个兽装的边界框与置信度
Furface 识兽POST /v1/analyze检测 + 识别一体,返回角色候选
POST /v1/recognize对给定 bbox 只做识别(detect 的输出框可直接回喂)

密钥归属单一产品:FurFind 的密钥只能调 /v1/detect, Furface 的密钥只能调 /v1/analyze 与 /v1/recognize。

请求格式

入图两种方式,二选一:

/v1/recognize 额外需要 boxes(JSON 数组,元素为 {x, y, width, height},坐标按响应中 imgW/imgH 的解码空间,最多 100 个)。

签名算法

每个请求携带四个头:

Header内容
X-Ffs-Key密钥 ID(ffs_ 开头,公开可入日志)
X-Ffs-TimestampUnix 秒。允许与服务器偏移 ±300s
X-Ffs-Nonce随机串,≤32 字符,窗口内不可重复
X-Ffs-Sign签名(hex 小写)

签名构造(六段以换行符 \n 连接):

StringToSign =
  METHOD            # 大写,如 POST
  path              # 如 /v1/analyze
  canonical_query   # query 参数按 key 排序后 k=v&k=v 重拼,无则空串
  sha256(body)      # 请求体的 SHA-256 hex;空体对空字节算
  timestamp         # 与 X-Ffs-Timestamp 一致
  nonce             # 与 X-Ffs-Nonce 一致

X-Ffs-Sign = hex(HMAC-SHA256(secret_key, StringToSign))

Python 示例

import hashlib, hmac, time, uuid, requests

KEY_ID = "ffs_xxxxxxxx"          # 控制台创建密钥时获得
SECRET = "<你的 Secret,仅创建时显示一次>"

def sign_headers(method: str, path: str, body: bytes) -> dict:
    ts = str(int(time.time()))
    nonce = uuid.uuid4().hex[:16]
    sts = "\n".join([
        method.upper(), path, "",              # 无 query 时第三段为空串
        hashlib.sha256(body).hexdigest(),
        ts, nonce,
    ])
    sig = hmac.new(SECRET.encode(), sts.encode(), hashlib.sha256).hexdigest()
    return {
        "X-Ffs-Key": KEY_ID, "X-Ffs-Timestamp": ts,
        "X-Ffs-Nonce": nonce, "X-Ffs-Sign": sig,
    }

body = b'{"imageUrl": "https://example.com/photo.jpg"}'
r = requests.post(
    "https://furface.furryfans.cn/v1/analyze",
    data=body,
    headers={**sign_headers("POST", "/v1/analyze", body),
             "Content-Type": "application/json"},
)
print(r.json())

错误响应

失败返回 {"ok": false, "error": {"code", "message", ...}}, 按 code 分类处理:

codeHTTP含义与处理
sign-mismatch401签名不匹配。响应附 string_to_sign_template,对照检查拼接顺序
timestamp-expired401时钟偏移超限。响应附 server_time,可自动校准
nonce-replayed401nonce 重复。换新 nonce 重试
key-revoked401密钥已吊销。重试无意义
wrong-service403密钥不属于该服务。在对应服务下创建密钥
payment-required402今日免费额度用尽且余额不足
image-too-large413图片超 20MB

计费