SDK隐私政策
Hi,您好,欢迎使用有道智云PDF格式转换高级版 API接口服务。
本文档主要针对需要集成HTTP API的技术开发工程师,详细描述PDF格式转换能力相关的技术内容。
如果您有与我们商务合作的需求,可以通过以下方式联系我们:
商务邮箱: AIcloud_Business@corp.youdao.com
如果您对文档内容有任何疑问,可以通过以下几种方式联系我们:
客服QQ:1906538062
智云翻译技术交流QQ 1群: 652880659
智云翻译技术交流QQ 2群: 669384425
智云翻译技术交流QQ 3群: 807539209
智云翻译技术交流QQ 4群: 936752411
联系邮箱: zhiyun@corp.youdao.com
温馨提示:
注:
基础版和高级版接口完全独立,因此高级版上传的文件,转换进度只能通过高级版 API 查询(基础版同理)。- 基础版和高级版
转换任务及结果均仅保留7天,转换成功后请及时获取并保存结果。
PDF 格式转换接口提供有道的 PDF 转换服务。您只需要通过调用 PDF 转换 API,传入文档的 Base64 编码,就可以将 PDF 文档格式进行转换。
请求流程:upload->query
https://openapi.youdao.com/file_convert/v2
| 规则 | 描述 |
|---|---|
| 传输方式 | HTTPS |
| 字符编码 | 统一使用UTF-8 编码 |
所有接口都遵循统一的响应格式:
| 参数名 | 类型 | 描述 |
|---|---|---|
| code | integer | 响应码,200表示成功,其他表示失败 |
| msg | string | 响应消息,成功时为"success",失败时为错误描述 |
| data | object | 响应数据,具体结构见各接口说明 |
POST /upload
| 参数名 | 类型 | 必填 | 描述 |
|---|---|---|---|
| appKey | string | 是 | 应用标识 |
| salt | string | 是 | 随机字符串 |
| curtime | string | 是 | 时间戳 |
| sign | string | 是 | 签名 |
| signType | string | 是 | 签名类型,仅支持v3 |
| q | string | 是 | 文档的Base64编码,编码后大小不能超过40M |
| fileName | string | 是 | 文件名(带后缀名),文件名长度不能超过100个字符 |
| fileType | string | 是 | 源文件类型(大小写敏感),目前仅支持 pdf |
| targetFileType | string | 是 | 目标文件类型(大小写敏感),支持 docx、pptx、xlsx、jpeg、jpg、png 注:目标文件类型为图片类型( targetFileType = jpeg、jpg 或 png)时,结果是以zip文件的形式返回 |
签名生成方法如下:
sign = sha256(
应用ID+input+salt+curtime+应用密钥)其中,input的计算方式为:
input=q 字符串(当q 长度小于等于20) 或input=q 前10个字符前10个字符+q 长度+q 后十个字符(当q 长度大于20)
| 参数名 | 类型 | 描述 |
|---|---|---|
| flownumber | string | 任务流水号 |
{
"code": "0",
"message": "success",
"data": {
"flownumber": "BAE670950ACE4C9E941A81B2959CXXXX"
},
"requestId": "1580715c-cf43-44d3-bb80-5dd28d1cXXXX",
"successful": true
}
POST /query
| 参数名 | 类型 | 必填 | 描述 |
|---|---|---|---|
| appKey | string | 是 | 应用标识 |
| salt | string | 是 | 随机字符串 |
| curtime | string | 是 | 时间戳 |
| sign | string | 是 | 签名 |
| signType | string | 是 | 签名类型,仅支持v3 |
| flownumber | string | 是 | 任务流水号 |
签名生成方法如下:
sign = sha256(
应用ID+input+salt+curtime+应用密钥)其中,input的计算方式为:
input=flownumber字符串(当flownumber长度小于等于20)。 或input=flownumber前10个字符前10个字符+flownumber长度+flownumber后十个字符(当flownumber长度大于20)
| 参数名 | 类型 | 描述 |
|---|---|---|
| status | integer | 任务状态码 |
| statusString | string | 任务状态描述 |
| resultUrl | string | 结果文件下载地址,仅任务完成时存在 |
| 状态码 | 描述 |
|---|---|
| 1 | 任务创建完成,初始化状态 |
| 2 | 文件转换中 |
| 4 | 转换完成 |
| -2 | 转换失败 |
{
"code": "0",
"message": "success",
"data": {
"status": 4,
"statusString": "已完成",
"resultUrl": "https://xxx.nos-jd.163yun.com/xxx"
},
"requestId": "d99436d1-7445-44d3-a8e5-e711774aXXXX",
"successful": true
}
| 支持格式 | 文件大小 |
|---|---|
| 40M内(编码后) |
| 错误码 | 含义 |
|---|---|
| 101 | 缺少必填的参数,首先确保必填参数齐全,然后,确认参数书写是否正确。 |
| 102 | 不支持的语言类型 |
| 103 | 翻译文本过长 |
| 104 | 不支持的API类型 |
| 105 | 不支持的签名类型 |
| 106 | 不支持的响应类型 |
| 107 | 不支持的传输加密类型 |
| 108 | 应用ID无效,注册账号,登录后台创建应用和实例并完成绑定,可获得应用ID和应用密钥等信息 |
| 109 | batchLog格式不正确 |
| 110 | 无相关服务的有效实例,应用没有绑定服务实例,可以新建服务实例,绑定服务实例。注:某些服务的翻译结果发音需要tts实例,需要在控制台创建语音合成实例绑定应用后方能使用。 |
| 111 | 开发者账号无效 |
| 112 | 请求服务无效 |
| 113 | q不能为空 |
| 114 | 不支持的图片传输方式 |
| 201 | 解密失败,可能为DES,BASE64,URLDecode的错误 |
| 202 | 签名检验失败,如果确认应用ID和应用密钥的正确性,仍返回202,一般是编码问题。请确保翻译文本 q 为UTF-8编码. |
| 203 | 访问IP地址不在可访问IP列表 |
| 205 | 请求的接口与应用的平台类型不一致,确保接入方式(Android SDK、IOS SDK、API)与创建的应用平台类型一致。如有疑问请参考入门指南 |
| 206 | 因为时间戳无效导致签名校验失败 |
| 207 | 重放请求 |
| 301 | 辞典查询失败 |
| 302 | 翻译查询失败 |
| 303 | 服务端的其它异常 |
| 304 | 会话闲置太久超时 |
| 401 | 账户已经欠费停 |
| 402 | offlinesdk不可用 |
| 411 | 访问频率受限,请稍后访问 |
| 412 | 长请求过于频繁,请稍后访问 |
| 1001 | 无效的OCR类型 |
| 1002 | 不支持的OCR image类型 |
| 1003 | 不支持的OCR Language类型 |
| 1004 | 识别图片过大 |
| 1201 | 图片base64解密失败 |
| 1301 | OCR段落识别失败 |
| 1411 | 访问频率受限 |
| 1412 | 超过最大识别字节数 |
| 2003 | 不支持的语言识别Language类型 |
| 2004 | 合成字符过长 |
| 2005 | 不支持的音频文件类型 |
| 2006 | 不支持的发音类型 |
| 2201 | 解密失败 |
| 2301 | 服务的异常 |
| 2411 | 访问频率受限,请稍后访问 |
| 2412 | 超过最大请求字符数 |
| 3001 | 不支持的语音格式 |
| 3002 | 不支持的语音采样率 |
| 3003 | 不支持的语音声道 |
| 3004 | 不支持的语音上传类型 |
| 3005 | 不支持的语言类型 |
| 3006 | 不支持的识别类型 |
| 3007 | 识别音频文件过大 |
| 3008 | 识别音频时长过长 |
| 3009 | 不支持的音频文件类型 |
| 3010 | 不支持的发音类型 |
| 3201 | 解密失败 |
| 3301 | 语音识别失败 |
| 3302 | 语音翻译失败 |
| 3303 | 服务的异常 |
| 3411 | 访问频率受限,请稍后访问 |
| 3412 | 超过最大请求字符数 |
| 4001 | 不支持的语音识别格式 |
| 4002 | 不支持的语音识别采样率 |
| 4003 | 不支持的语音识别声道 |
| 4004 | 不支持的语音上传类型 |
| 4005 | 不支持的语言类型 |
| 4006 | 识别音频文件过大 |
| 4007 | 识别音频时长过长 |
| 4201 | 解密失败 |
| 4301 | 语音识别失败 |
| 4303 | 服务的异常 |
| 4411 | 访问频率受限,请稍后访问 |
| 4412 | 超过最大请求时长 |
| 5001 | 无效的OCR类型 |
| 5002 | 不支持的OCR image类型 |
| 5003 | 不支持的语言类型 |
| 5004 | 识别图片过大 |
| 5005 | 不支持的图片类型 |
| 5006 | 文件为空 |
| 5201 | 解密错误,图片base64解密失败 |
| 5301 | OCR段落识别失败 |
| 5411 | 访问频率受限 |
| 5412 | 超过最大识别流量 |
| 9001 | 不支持的语音格式 |
| 9002 | 不支持的语音采样率 |
| 9003 | 不支持的语音声道 |
| 9004 | 不支持的语音上传类型 |
| 9005 | 不支持的语音识别 Language类型 |
| 9301 | ASR识别失败 |
| 9303 | 服务器内部错误 |
| 9411 | 访问频率受限(超过最大调用次数) |
| 9412 | 超过最大处理语音长度 |
| 10001 | 无效的OCR类型 |
| 10002 | 不支持的OCR image类型 |
| 10004 | 识别图片过大 |
| 10201 | 图片base64解密失败 |
| 10301 | OCR段落识别失败 |
| 10411 | 访问频率受限 |
| 10412 | 超过最大识别流量 |
| 11001 | 不支持的语音识别格式 |
| 11002 | 不支持的语音识别采样率 |
| 11003 | 不支持的语音识别声道 |
| 11004 | 不支持的语音上传类型 |
| 11005 | 不支持的语言类型 |
| 11006 | 识别音频文件过大 |
| 11007 | 识别音频时长过长,最大支持30s |
| 11201 | 解密失败 |
| 11301 | 语音识别失败 |
| 11303 | 服务的异常 |
| 11411 | 访问频率受限,请稍后访问 |
| 11412 | 超过最大请求时长 |
| 12001 | 图片尺寸过大 |
| 12002 | 图片base64解密失败 |
| 12003 | 引擎服务器返回错误 |
| 12004 | 图片为空 |
| 12005 | 不支持的识别图片类型 |
| 12006 | 图片无匹配结果 |
| 13001 | 不支持的角度类型 |
| 13002 | 不支持的文件类型 |
| 13003 | 表格识别图片过大 |
| 13004 | 文件为空 |
| 13301 | 表格识别失败 |
| 15001 | 需要图片 |
| 15002 | 图片过大(1M) |
| 15003 | 服务调用失败 |
| 17001 | 需要图片 |
| 17002 | 图片过大(1M) |
| 17003 | 识别类型未找到 |
| 17004 | 不支持的识别类型 |
| 17005 | 服务调用失败 |
| 18001 | 需要参数 |
| 18002 | 需要流水号 |
| 18003 | 需要文件名 |
| 18004 | 需要文件类型 |
| 18005 | 需要源语言 |
| 18006 | 需要目标语言 |
| 18007 | 需要翻译文件 |
| 18008 | 上传文件失败 |
| 18009 | 错误的流水号 |
| 18010 | 未完成 |
| 18011 | 转换失败 |
| 18012 | 找不到文件 |
| 18013 | 需要文件下载类型 |
| 18014 | 不支持的语言 |
| 18015 | 不支持的文件类型 |
| 18016 | 不支持的下载类型 |
| 18017 | 文件过大 |
| 340001 | PDF 文件格式错误 |
| 340002 | PDF 文件保存失败 |
| 340003 | 流水号flownumber不存在或已过期 |
| 340004 | 不支持的源文件类型 |
python = 3.11
import base64
import hashlib
import time
import uuid
import requests
import os
# === 请填写你自己的本地文件地址 ===
LOCAL_FILE_PATH = '请填写你自己的本地文件地址'
# === 请填写你自己的应用ID和密钥 ===
APP_KEY = "你的应用ID"
APP_SECRET = "你的应用密钥"
# === 高级版 API 基础URL ===
BASE_URL = "https://openapi.youdao.com/file_convert/v2"
UPLOAD_URL = f"{BASE_URL}/upload"
QUERY_URL = f"{BASE_URL}/query"
def truncate(q: str) -> str:
"""根据文档规则生成 input 字符串"""
if len(q) <= 20:
return q
return q[:10] + str(len(q)) + q[-10:]
def sha256_digest(s: str) -> str:
"""生成 SHA256 签名"""
return hashlib.sha256(s.encode("utf-8")).hexdigest()
def gen_sign(q_or_flownumber: str) -> tuple:
"""生成签名所需参数:salt, curtime, sign"""
salt = str(uuid.uuid4())
curtime = str(int(time.time()))
input_str = truncate(q_or_flownumber)
sign_str = APP_KEY + input_str + salt + curtime + APP_SECRET
sign = sha256_digest(sign_str)
return salt, curtime, sign
def upload_pdf(file_path: str, target_type="docx"):
if not os.path.exists(file_path):
raise FileNotFoundError(file_path)
with open(file_path, "rb") as f:
file_base64 = base64.b64encode(f.read()).decode("utf-8")
salt, curtime, sign = gen_sign(file_base64)
# 注意 multipart/form-data 传参方式
form_data = {
"appKey": (None, APP_KEY),
"salt": (None, salt),
"curtime": (None, curtime),
"sign": (None, sign),
"signType": (None, "v3"),
"q": (None, file_base64),
"fileName": (None, os.path.basename(file_path)),
"fileType": (None, "pdf"),
"targetFileType": (None, target_type),
}
print("正在以 multipart/form-data 上传文件...")
resp = requests.post(UPLOAD_URL, files=form_data, timeout=120)
print(f"HTTP状态: {resp.status_code}")
print(resp.text)
result = resp.json()
if result.get("code") == "0" and result.get("data"):
flownumber = result["data"]["flownumber"]
print(f"上传成功,任务流水号: {flownumber}")
return flownumber
else:
raise Exception(f"上传失败: {result}")
def query_task(flownumber: str):
"""查询任务状态(multipart/form-data 方式)"""
salt, curtime, sign = gen_sign(flownumber)
form_data = {
"appKey": (None, APP_KEY),
"salt": (None, salt),
"curtime": (None, curtime),
"sign": (None, sign),
"signType": (None, "v3"),
"flownumber": (None, flownumber),
}
print(f"查询任务状态: {flownumber}")
resp = requests.post(QUERY_URL, files=form_data, timeout=30)
print(f"HTTP状态: {resp.status_code}")
print(resp.text)
try:
result = resp.json()
except Exception:
raise Exception(f"返回结果无法解析为JSON: {resp.text}")
if result.get("code") != "0":
raise Exception(f"查询失败: {result}")
return result
def wait_for_result(flownumber: str, interval=5, timeout=300):
"""轮询任务状态直到完成或失败"""
print("查询任务进度中...")
start_time = time.time()
while time.time() - start_time < timeout:
result = query_task(flownumber)
data = result.get("data", {})
status = data.get("status")
status_str = data.get("statusString", "")
print(f"任务状态: {status} ({status_str})")
if status == 4:
url = data.get("resultUrl")
print(f"转换完成,下载地址: {url}")
return url
elif status == -2:
raise Exception("转换失败")
time.sleep(interval)
raise TimeoutError("任务超时未完成")
def download_result(result_url: str, save_path: str):
"""下载转换后的结果文件"""
print("正在下载结果...")
resp = requests.get(result_url)
with open(save_path, "wb") as f:
f.write(resp.content)
print(f"文件已保存到: {save_path}")
if __name__ == "__main__":
# === 示例使用 ===
# 输出的Word文件名
output_file = "result.docx"
flownumber = upload_pdf(LOCAL_FILE_PATH, target_type="docx")
result_url = wait_for_result(flownumber)
# 保存文件到本地
download_result(result_url, output_file)