文件与项目

文件与项目

任务可以带附件,交付的文件保存在任务所在的项目里。上传附件分三步:申请上传、把文件直传到返回的地址、完成上传,得到的文件 ID 放进新建任务或发消息的 file_ids。任务交付的文件可以获取下载地址,也可以读取其中的文字;项目接口用来查看已有项目和其中的文件。这些接口只能访问密钥代表的身份下的文件,其他人的文件一律返回 404。

上传附件

单个附件最大 32 MiB,超过时返回 413 和 error.file_too_large。

  1. 调用 POST /v1/uploads,传入文件名 name(带扩展名,1 到 255 个字,不能含 / 或 \)、字节数 size 和内容的 SHA-256 sha256(64 位小写十六进制),可选传入 mime(最多 100 个可打印的 ASCII 字符),不传时按文件名判断。
  2. 返回中含 upload 时,用 multipart/form-data 把文件 POST 到 upload.url:先把 upload.fields 里的字段原样放进表单,最后放名为 file 的文件内容。这一步发往存储服务,不要带 Authorization 请求头。返回中不含 upload 时,表示服务端已有相同内容,跳过这一步。
  3. 调用 POST /v1/uploads/complete,传入第一步返回的 token,得到文件对象,其中的 id 即文件 ID。

附件上传后 48 小时内未用在任务中,会被自动清理。

import hashlib
import os
from pathlib import Path

import requests

API = "https://api.favonis.com/v1"
headers = {"Authorization": f"Bearer {os.environ['FAVONIS_API_KEY']}"}

path = Path("销售数据.xlsx")
content = path.read_bytes()

prepared = requests.post(f"{API}/uploads", headers=headers, timeout=30, json={
    "name": path.name,
    "size": len(content),
    "sha256": hashlib.sha256(content).hexdigest(),
}).json()

if "upload" in prepared:
    upload = prepared["upload"]
    requests.post(
        upload["url"], data=upload["fields"], files={"file": (path.name, content)}, timeout=120
    ).raise_for_status()

file = requests.post(f"{API}/uploads/complete", headers=headers, timeout=30,
                     json={"token": prepared["token"]}).json()
print(file["id"])

requests 在表单中会先写 data 里的字段,再写 files,正好满足第 2 步的顺序。用其他语言时,请确认文件是表单的最后一项。

下载文件

GET /v1/files/{id} 返回文件信息(id、name、size、mime、created_at、updated_at)和下载地址 download_url。下载地址 2 小时内有效,到期时间是 download_expires_at,到期前用 GET 下载,不需要带密钥。

curl https://api.favonis.com/v1/files/$FILE_ID \
  -H "Authorization: Bearer $FAVONIS_API_KEY"

任务结果里的 result.files 是这一轮交付的文件,同一个文件交付多次只列一次,version_id 是最后交付的版本。GET /v1/files/{id} 返回的是文件的当前版本:任务结束后这个文件再被修改时,下载到的是修改后的内容。

读取文字

只需要文件里的文字时,用 GET /v1/files/{id}/content,不必下载再解析。Word 文档、Excel 表格、PowerPoint 幻灯片这类文件会先转成文字;图片等本身不含文字的文件,以及文字提取失败的文件,返回空的 text,请用下载地址获取。

{
	"id": "0196a3f9-1d27-7e05-a8c4-3b6f2d91e0a8",
	"name": "季度复盘.docx",
	"text": "# 第三季度销售复盘\n\n……",
	"truncated": true,
	"next_offset": 298731
}

每次从查询参数 offset 指定的字节位置起,最多返回 10 万字。truncated 为 true 时之后仍有内容,把返回的 next_offset 作为 offset 传回,读取下一段。offset 按字节计,请以 next_offset 为准,不要按字数推算。

文件刚上传或刚交付时,文字可能仍在提取中,这时返回 409 和 error.file_not_ready,稍后重试。

项目和项目文件

GET /v1/projects 列出你在 Favonis 中创建的项目,最近编辑的在前,每项有 id、name、created_at、updated_at。新建任务时传入 project_id,Favonis 在这个项目里工作,能读写项目里的文件。新建任务时未指定项目的是独立任务,不在这个列表中。

GET /v1/projects/{id}/files 列出项目里一个文件夹的直接子项,path 指定文件夹在项目里的路径(例如 reports/2026),不传时是根目录。任务的 project_id 也可以传入这里,独立任务同样适用。

{
	"data": [
		{
			"name": "reports",
			"path": "reports",
			"kind": "folder",
			"updated_at": "2026-11-06T09:30:12Z"
		},
		{
			"name": "季度复盘.pptx",
			"path": "季度复盘.pptx",
			"kind": "file",
			"file_id": "0196a412-0c5e-7a63-91f8-4d2b7e6c3a10",
			"updated_at": "2026-11-06T09:31:47Z"
		}
	]
}

kind 是 file 或 folder,只有文件带 file_id,可以用它下载或读取文字。