yichong-web
v0.6.0
Published
YiChong Web 后端 SDK:完整公共 API、Replicate、R2 上传、AI、用量与账户接口
Readme
yichong-web
开发文档:飞书开发指南与 API 速查 · 本地文档源稿。接口、版本或接入状态变更时同步维护。
供 Imgkits、TeachAny、Transmonkey 使用的 TypeScript / ESM 后端工具包。开放 [email protected] 中网站可用的 24 个方法,包括 Replicate、Cloudflare R2 上传、AI、用量、账户状态和配置;Canva 宿主专用的身份接口不开放。运行时仅依赖 yichong-api,不依赖 Vue、Nuxt、React 或 Canva SDK。
现有登录代码和 Pinia store 继续提供用户 ID、业务 JWT、渠道与语言。账户请求另外读取当前 passport 和鉴权渠道。SDK 只执行显式调用的底层接口,不组织登录流程、保存票据、计算消费或刷新账户,不读取路由和 localStorage。每个方法读取调用时的最新上下文,不缓存初始化时的用户或 JWT。
安装与验证
当前版本 0.6.0 移除 Canva 宿主专用的 account.handleUserLoginByCanvaId、account.getPassport、canvaIdentity.getUserIds 以及 accountPassport / canvaIdentity 服务配置(三个网站均未使用);0.5.0 新增任务等待 waitForPrediction、上传保留期 retention、getPredictionOutputUrl / isAbortError 与上报 sdkVersion,精确依赖 [email protected];0.4.0 新增 TTS 和行为统计。使用 Node.js 22 或 24 做常规开发:
cd yichong-web
npm ci
npm run check
npm pack在需要升级的网站目录执行:
npm install [email protected] --save-exact所有接口通过正式 npm 依赖 [email protected] 复用公共实现,npm 会自动安装 API 包。公共层以现有 Canva 接口为参考;yichong-canva2 保持原有独立实现。公开包保留 import ... from 'yichong-api',不内嵌 dist/shared-api/ 或引用本地源码目录。
构建脚本清理 dist,只编译 Web 源码,生成 ESM 和类型声明。API 发布后,在本目录执行 npm ci 即可开发,不需要任何相邻源码目录。check 包含类型检查、模拟传输测试,以及实际 tarball 的 npm 依赖自动安装、入口和类型消费者检查。安装检查使用本机临时 registry 和空缓存,仅向本机读取候选包,不依赖未发布版本的线上 registry。工具包创建或重构不会自动升级三个网站的依赖。
从现有 Nuxt / Pinia 接入
以 Imgkits 为例,在 Nuxt 插件中创建客户端。不要在模块顶层创建共享用户单例;SSR 时每个 Nuxt 请求使用自己的实例。
import { createWebClient } from 'yichong-web'
import { userStore } from '~/stores/user'
export default defineNuxtPlugin((nuxtApp) => {
const store = userStore()
const client = createWebClient({
getContext: () => ({
uid: store.user?.id,
platformUid: store.user?.google_uid || store.user?.id,
jwt: store.jwt,
appChannel: 'imgkits',
locale: String(nuxtApp.$i18n.locale.value),
}),
})
return { provide: { yichongWeb: client } }
})三个网站现有公共请求的默认 app_channel 分别为 imgkits、teachany、trans_monkey;独立产品可在 getter 中显式返回自己的渠道。app_channel 是请求归属,Channel: ai 是模型服务的认证通道,两者不同。不要从页面显示名推断渠道。platform 缺省为 web,platformUid 缺省回退到 uid;SDK 不要求 Canva ID。
locale 默认 en,现有 jp、zh、zh_TW 分别映射为 ja、zh-CN、zh-TW。时区可通过 timezone 传入;省略时取当前运行环境的 IANA 时区,失败回退 UTC。上下文附加到 SDK 自有服务请求的 uid / platform_uid / platform / app_channel / timezone query;语言只通过 Accept-Language 发送。
replicateBaseUrl 默认 https://api.imgkits.com,uploadBaseUrl 默认 https://ai.imgkits.com,旧配置继续有效。所有端点也可通过 services 分别配置;同一服务两种配置都存在时,旧的 replicateBaseUrl / uploadBaseUrl 优先。fetch 可以注入原生 fetch 兼容的传输,不是返回已解析对象的 $fetch。Replicate、Chat、内容提取要求 uid 和业务 JWT;文本审核要求 JWT。上传签名保持原有 node-nauth 合同,允许缺省 uid,由网站保留自己的登录前置条件。
完整接口与服务配置
以下 24 个方法均可直接从 createWebClient() 返回值调用。参数/响应类型均可从 yichong-web 导入;apiContracts 和 defaultServices 也从包入口导出,分别提供路径协议和默认地址;0.5.0 起另导出 getPredictionOutputUrl 和 isAbortError。
| 分组 | 客户端方法 | services 配置项 / 默认地址 |
| --- | --- | --- |
| Replicate(5) | createPrediction、createSpecifyPrediction、getPrediction、cancelPrediction、waitForPrediction | replicate / https://api.imgkits.com |
| 上传(5) | generatePresignedUrl、initiateUpload、getUploadUrl、completeUpload、uploadFile | upload / https://ai.imgkits.com |
| 文本审核(1) | textCheck | moderation / 未配置时跟随 replicate |
| 内容提取(1) | contentExtract | content / https://ai.imgkits.com |
| 大模型(1) | chat | chat / https://ai.imgkits.com |
| 音视频转录(2) | createVtt、getVttStatus | vtt / https://api.imgkits.com |
| 语音合成(2) | createTextToSpeech、getTextToSpeechResult | tts / https://ai.imgkits.com |
| 行为统计(1) | reportUsage | usageReporting.endpoint / https://log.aibabygenerator.io/api/report |
| 用量(3) | reduceFreeCnt、addMonthlyUsage、addFreeUsageCnt | account / https://usa.imgkits.com |
| 账户(1) | account.getUserStatusByPassport | account / https://usa.imgkits.com |
| 站点配置(1) | siteConfig.getAppVersion | siteConfig / https://usa.imgkits.com |
| 错误上报(1) | reportError | reporting / https://report.imgkits.com |
services 支持反向代理路径前缀,例如 { account: 'https://usa.imgkits.com/product' }。WebApiServices、WebReportingConfig 和 AccountCredentials 提供对应的配置类型。
Canva 版的 canvaid-login、canva-passport 和 getUserIdByAppid 依赖 Canva ID 或 Canva 宿主令牌,网站拿不到,因此不在 Web 客户端上;apiContracts 仍原样导出公共库的完整合同表,仅供查阅。网站的 passport 继续由现有登录层通过 /api/user/passport(google_uid)取得,再经 getAccountCredentials 传入。Imgkits 的 OCR、支付、3D 生成等其他业务端点,以及普通网站的 Google 登录流程,不因开放这些方法就自动接入。升级依赖后,网站仍需逐项把原有业务入口适配到 SDK。
任务等待、上传保留期与上报版本(0.5.0 起)
0.5.0 精确依赖 [email protected],与 yichong-canva2 2.5.1 的 API 对齐:
import { getPredictionOutputUrl, isAbortError } from 'yichong-web'
const controller = new AbortController()
try {
const { data: id } = await client.createSpecifyPrediction({ owner, name, input })
const task = await client.waitForPrediction({ id }, { signal: controller.signal })
const url = getPredictionOutputUrl(task.output)
const saved = await client.uploadFile({ file, retention: 'day30' })
} catch (error) {
if (!isAbortError(error)) showError(error)
}waitForPrediction只重复调用getPrediction,Web 查询正文继续补user_id。默认每 3 秒查询、最多 60 次、总预算 180 秒;failed/canceled/aborted抛prediction_failed,用完抛prediction_timeout,主动取消抛aborted。不会自动取消后端任务、重复创建或消费。已有轮询与任务恢复逻辑的页面无需改用。uploadFile的retention: 'temp' | 'day30'选择自动命名前缀,默认temp_;不能与objectName同时传入。Imgkits 的utils/uploadR2.js现有命名规则不变。reporting.sdkVersion可写入错误诊断的sdk_version;reporting.robot会参与脱敏。
TTS 与行为统计(0.4.0 起)
直接调用 client.createTextToSpeech({ text, voice?, emotion?, speed?, language?, refer_audio?, refer_audio_text? }) 与 client.getTextToSpeechResult({ jobId })。服务地址由 services.tts 覆盖,默认 https://ai.imgkits.com。创建正文的 guid 自动取当前系统 uid,不传 app_id 或手动身份字段;JWT 可选,有有效值才发送。text 最多 5000 个 Unicode 字符,speed 范围 0.5–2.0。
两方法返回完整 { code: 0, msg, data };status 为 0 等待、2 处理中、10 完成、-1 失败,创建也可能立即返回失败。完成后的 data.result 为音频 URL 或 null。默认单次 60 秒,支持 { timeoutMs, signal },不自动重试、轮询或重复扣费;后端已有 TTS 字符用量处理。创建超时不代表后端未创建或未计费,不要直接重放创建。
void client.reportUsage({ sum_key: 'voice_select', title: '选择音色', data: { voice: 'Arrogant_Miss' } }) 兼容现有 GET 统计接口。创建客户端时可配置 usageReporting: { enabled, endpoint, appKey } 与 getUsageReportingMetadata: () => ({ session_id, app_version })。Web 端只显式记录业务事件,不自动监听路由或创建网站会话。
统计允许登录前调用,不发送 JWT、passport 或 cookie。返回 Promise<boolean>,失败返回 false、不抛错、不阻塞业务。默认每次 4 秒,网络/超时/429/5xx 最多重试一次,同事件复用 UUID。只传固定属性、计数、耗时、错误码;不要传用户文本、完整 input/output、文件 URL、凭据或原始错误。
Chat、审核与内容提取
const check = await client.textCheck({ text: prompt })
if (!check.data.allowed) {
// 在页面提示审核结果,并停止当前业务流程。
return
}
const extracted = await client.contentExtract({ type: 'link', url: publicUrl })
const reply = await client.chat({
payload: { messages: [{ role: 'user', content: extracted.data.content }] },
})
console.log(reply.data.result)三个接口均使用业务 JWT 和 Channel: ai,返回完整 { code: 0, msg, data }。textCheck 返回 allowed / decision / categories 等原始审核结果;contentExtract 接收公开 HTTP(S) 地址,type 为 file / video / link,本地文件应先上传;chat 返回完整文本,不自动解析文本内的 JSON,也不提供流式增量。默认等待预算分别为 60 秒、360 秒、360 秒,均支持第二参数的 signal / timeoutMs。
音视频转录
const task = await client.createVtt({
audio: 'https://media.example/audio.mp3',
// 视频改用 video: 'https://media.example/video.mp4'
})
const status = await client.getVttStatus({ jobId: task.data.jobId })
if (status.data.status === 10 && status.data.result) {
const segments = JSON.parse(status.data.result)
console.log(segments)
}创建使用 POST /get-vtt/create,查询使用 POST /get-vtt/status。默认地址为 https://api.imgkits.com,可通过 services.vtt 覆盖(支持路径前缀);后端需已部署通用路由及相应网关转发。
创建只传 audio 或 video 的公开 HTTP(S) 地址,userId 自动取当前 getContext().uid。身份、业务 JWT、Channel: ai、语言与时区沿用 Web 上下文;查询正文只传 jobId。可选参数 ifRender: 0 | 1、email、env 按后端原名传递,普通使用省略 env。
返回完整 { code, msg, data };data.status 为 0 / 2 时继续等待,为 10 时成功,为 -1 时由页面显示任务失败。data.result 是字幕片段数组的 JSON 字符串,不是 WEBVTT/SRT 文件。单次请求默认超时 60 秒,支持第二参数 { timeoutMs, signal };上传、轮询和扣费时机由业务组织,SDK 不自动执行。取消请求只停止等待,不取消后端任务。
用量与账户底层请求
在已有客户端配置中增加凭据 getter,值从网站现有登录层读取:
const client = createWebClient({
getContext: readCurrentRequestContext, // 返回 uid、jwt、appChannel、locale 等
getAccountCredentials: () => ({
accessChannel: readCurrentAccountChannel(),
passport: readCurrentPassport(),
}),
})
// 以下是独立操作示例;一次消费按原业务规则选择一种接口。
await client.reduceFreeCnt({ cnt: 1 })
// 或 client.addMonthlyUsage({ cnt: 1 })
// 或 client.addFreeUsageCnt({ cnt: 1 })
const status = await client.account.getUserStatusByPassport()
// 网站继续按账户服务的业务字段处理 status、更新原有 store。示例中的 readCurrent... 函数由网站现有 store / 登录层提供。appChannel 是请求归属(如 imgkits),accessChannel 是账号票据所属渠道(如 imgkit 或插件专用渠道),两者不能直接互相替代。消费接口使用 X-Access-Channel / X-Access-Ticket,不会把 JWT 当作 passport。
用量接口返回原始 { ok: 0, msg, ... },默认等待 30 秒;失败不自动重试,避免重复记账。SDK 不选择套餐、不修改本地积分,也不自动刷新账户。未提供当前票据或 uid 时,用量请求会在本地报 account_not_ready。
账户状态查询返回后端原始对象,不因为 HTTP 200 就判定登录成功;需要账户渠道和当前 passport,默认等待 30 秒。SDK 不登录、不申请或保存 passport,不处理 Google Drive state。网站仍负责读取业务结果、更新登录状态和处理过期。
站点配置与错误上报
const config = await client.siteConfig.getAppVersion({ key: 'your-existing-config-key' })
console.log(config.version)站点配置无需 JWT 或 passport;成功时解析 data.value 的 JSON 对象,后端 success 为假时返回 {}。查询键沿用网站已有配置,SDK 不猜测或添加前缀。
上报需要单独配置通道,不会随其他 API 自动触发:
const client = createWebClient({
getContext: readCurrentRequestContext,
getAccountCredentials: readCurrentAccountCredentials,
reporting: {
appId: 'imgkits',
version: 1,
getToken: readCurrentReportingToken,
// getSecrets: () => [需要额外脱敏的现有凭据],
},
})
try {
await client.reportError({ error, source: 'api', stage: 'create_prediction' })
} catch (reportError) {
// 独立处理上报失败,保留原业务错误。
}使用现有上报专用令牌,不能以 JWT/passport 替代,也不内置固定凭据。上报正文会脱敏当前 JWT、passport、上报令牌及 getSecrets 提供的值;不会把业务认证头或公共 query 加到上报请求。该浏览器通道令牌会进入前端运行环境,不应视作服务端秘密。返回 { success: true, data },其中 data.status=ignored 代表 Worker 忽略了该条报告;默认等待 10 秒。未配置时显式调用报 reporting_not_ready,其他接口照常可用。
Replicate
| 方法 | 后端 POST 路径 | 响应 |
| --- | --- | --- |
| createPrediction({ version, input, debug? }) | /replicate/createPrediction | { code: 0, msg, data: taskId } |
| createSpecifyPrediction({ owner, name, input, ... }) | /replicate/createSpecifyPrediction | 同上 |
| getPrediction({ id }) | /replicate/getPrediction | { code: 0, msg, data: { id, status, output, ... } } |
| cancelPrediction({ id }) | /replicate/cancelPrediction | 原始响应包或供应商任务对象 |
创建和查询自动从当前上下文填入 user_id。业务不得覆盖身份字段。指定模型创建保留 video_type / video_catalog / catalog_model_id / primary_provider / execution_chain / provider_requests;video_catalog=\"schema_v2\" 且提供非空 provider_requests 时可省略顶层 input。模型、输入、供应商顺序和返回数据不改写。
const { $yichongWeb: client } = useNuxtApp()
const created = await client.createSpecifyPrediction({
owner: 'your-confirmed-owner',
name: 'your-confirmed-model',
input: { prompt: 'your prompt' },
})
const result = await client.getPrediction({ id: created.data })
if (result.data.status === 'succeeded') {
// 按当前模型合同处理 result.data.output;可能是字符串、数组或对象。
}每个方法只请求一次,不自动轮询、创建重试、上报或扣费。查询到 failed / canceled 返回任务状态,由业务决定如何展示;HTTP / 业务失败则抛 ApiError。业务轮询首次 succeeded 后立即停止,保留原任务恢复与消费规则。cancelPrediction 是显式后端操作,部分供应商只清理网关状态,不能保证上游任务停止。
本版不封装模型目录、/replicate/ai-image/* 或 /replicate/ai-video/* 意图接口。目录任务继续使用原来的对应查询端点,不要切换到普通 getPrediction。
R2 Upload
| 方法 | 签名服务 POST 路径 |
| --- | --- |
| generatePresignedUrl({ objectName, bucketName? }) | /api/generate-presigned-url |
| initiateUpload({ objectName, bucketName?, contentType? }) | /upload/initiate-upload |
| getUploadUrl({ objectName, uploadId, partNumber, bucketName? }) | /upload/get-upload-url |
| completeUpload({ objectName, uploadId, parts, bucketName? }) | /upload/complete-upload |
上述方法保留服务端原始字段,如 UploadId、ETag、endpointBaseUrl。整套上传无需前端存储密钥,不带业务 JWT 或 passport。文件字节直接 PUT 到返回的签名 URL,URL 原样使用,不附加公共参数或业务认证头。
业务优先使用完整上传方法:
const uploaded = await client.uploadFile({
file,
onUploadProgress: ({ loaded, total }) => {
if (total) progress.value = loaded / total
},
}, { signal: controller.signal })
// uploaded = { url: '公开资源地址', key: '对象名', endpointBaseUrl: '公开基地址' }- 小于 100 MiB 使用单次 PUT;达到 100 MiB 自动分片。
multipart: true可强制小文件分片,false 不关闭大文件自动分片。 - 桶默认
video。对象名默认temp_{app_channel}_{本地日期}_{32位随机}.{后缀},沿用现有上传命名。fileName用于后缀,objectName可保留业务所需的原有前缀和对象键。 - 单次上传的公开 URL 来自签名响应的
endpointBaseUrl。分片优先取初始化响应;旧响应缺失时,用同一对象/桶再申请一次普通签名,只读取公开基地址。合并响应返回最新地址时以它为准,不从 S3 Location 或签名 host 猜测地址。 - 单次上传传进度回调时使用浏览器 XHR,
loaded/total单位为字节;分片为已完成片数/总片数。100% 后仍须等待响应或合并成功,只有 Promise 完成才能使用结果。 - 分片 PUT 必须能读取 ETag。切换用户或渠道、取消、进度回调异常会停止后续上传步骤;同用户刷新 JWT 不影响上传。
- 默认总等待预算为单次 120 秒、分片 30 分钟,包含签名、上传、读取响应与合并,不按片重置。第二参数的
timeoutMs可覆盖。 - 不自动重试或恢复,不提供服务端分片清理;取消本地传输不等于删除已上传数据。本版不包含 OSS、URL 转存或 Google Drive 导入。
错误与取消
import { ApiError } from 'yichong-web'
try {
await client.getPrediction({ id: taskId }, { signal, timeoutMs: 30_000 })
} catch (error) {
if (error instanceof ApiError) {
if (error.code === 'aborted') return
// error.message / userMessage 优先保留后端文案。
// code、status、data、retryAfter 可用于原有界面处理。
}
}常见 SDK 错误码:invalid_request / account_not_ready / reporting_not_ready / invalid_response / timeout / aborted / network_error / account_changed / missing_etag / upload_progress_failed。模型和消费接口的 HTTP/业务失败抛出错误;账户旧协议保留原始 JSON,由网站判断业务结果。SDK 不发起自动登录、刷新账户或重放付费请求。取消使用 ApiError.code === 'aborted' 判断。
源码在独立的 frontend/web/yichong-web 目录。上传协议与现有 Web/Canva 上传实现对齐;没有改写 Canva 包,也没有在三站批量替换旧调用。
发布与升级
本次配套版本为 [email protected] 与它精确依赖的 [email protected]。先发布 API,再发布 Web;npm 版本号发布后不可重复使用。
后续公共 API 升级时,先发布 API,再更新本包的精确依赖、版本及 lockfile,运行 npm run check 后发布 Web。npm 可能在发布后短暂返回 404,需等待版本可查询后再升级网站。网站仍然只需安装 yichong-web。
