HappyOysterEngine 负责配置 Open Platform host 与模型、更新百炼临时 API Key token,并创建 Travel 会话。 Travel 是 createTravel() 返回的会话对象,调用 travel.start() 后才会进入并启动会话。
核心名词概念
名词 | 含义 | 备注 |
|---|---|---|
token | 百炼临时 api-key token:在浏览器、移动 App 等不可信环境中调用百炼模型服务时,通过安全的后端服务生成临时 API Key,避免永久 API Key 泄露。SDK 以 HTTP Bearer 方式携带该 token 请求 Open Platform。 | |
ticket | HappyOyster 世界体验凭证:三方服务端通过 AK 鉴权(网关 Header)调用此接口,换取一个短时效的体验凭证( |
方法概览
本 SDK 主要对象如下:
HappyOysterEngine
API | 描述 |
|---|---|
| 创建 Engine 实例。 |
| 更新后续 Open Platform API 请求使用的百炼临时 api-key token。 |
| 创建一次 Travel 会话。 |
| 当前 SDK 版本号。 |
| 当前 SDK 包名、版本和包渠道。 |
Travel
API | 描述 |
|---|---|
| 启动当前 Travel 会话。 |
| 订阅会话状态变化。 |
| 订阅首帧 URL 生成通知。 |
| 订阅进入会话后即可获得的会话元信息。 |
| 订阅会话运行时错误。 |
| 判断当前是否可以调用指定动作。 |
| 获取已返回的会话元信息;尚未返回时为 |
| 发送实时操控指令。 |
| 发送实时导演或提示词内容。 |
| 暂停当前会话。 |
| 恢复已暂停的会话。 |
| 将 Directing 会话回退到指定秒数。 |
| 结束当前会话并释放相关资源。 |
其他导出
导出 | 描述 |
|---|---|
| SDK 对外暴露的错误码常量对象。 |
| 判断未知错误是否为 SDK 标准错误。 |
Types |
|
示例
import { HappyOysterEngine, isSdkError } from '@happy-oyster/js-sdk'
const engine = new HappyOysterEngine({
APIHost: 'open-platform.example.com',
model: 'happyoyster-1.0-adventure', // 必填;此处以 Adventure 模型为例
token: 'bailian-temporary-api-key-token',
logLevel: 'warn',
streamReadyTimeout: 15_000,
})
const videoElement = document.getElementById('player') as HTMLVideoElement
const travel = engine.createTravel({
ticket: 'travel-ticket',
videoElement,
maxExperienceTimeSec: 90,
})
const unsubscribeStatus = travel.on('statusChanged', (status) => {
console.log('Travel status:', status)
})
const unsubscribeFirstFrame = travel.on('firstFrameGenerated', (firstFrame) => {
console.log('First frame URL:', firstFrame)
})
const unsubscribeInfo = travel.on('travelInfoReady', (info) => {
console.log('Travel info is ready before RTC playback:', info)
})
const unsubscribeError = travel.onError((error) => {
console.error('Travel error:', error)
})
try {
const { encryptedTravelId, mode, creationModel, firstFrame, maxExperienceTimeSec, aspectRatio } = await travel.start()
// Adventure(模式 1)
await travel.sendCommand({
translation: 'Front',
rotation: 'Mouse_Left',
interaction: 'Jump',
})
// Directing(模式 2)或角色演绎(模式 3;非 scriptlist)
await travel.sendInstruct({ content: '镜头转向城堡,主角开始奔跑' })
await travel.pause()
await travel.resume()
} catch (err) {
if (isSdkError(err)) {
console.error('SDK error:', err.code, err.message)
} else {
console.error('Unexpected error:', err)
}
} finally {
unsubscribeStatus()
unsubscribeFirstFrame()
unsubscribeInfo()
unsubscribeError()
await travel.end()
}
engine.updateToken('new-bailian-temporary-api-key-token')
HappyOysterEngine
HappyOysterEngine 是 Web SDK 的入口对象,用于配置 Open Platform host、维护后续请求使用的百炼临时 api-key token,并创建 Travel 会话。
说明一个 Engine 实例同一时间只管理一个 active Travel(当前限制)。如果需要开始新的会话,请先结束当前 Travel。
设置 token(构造时或通过 updateToken())后,SDK 内部会自动拉取功能开关(Feature Gate)。该能力用于远程关停 SDK 或强制升级旧版本;请求失败时 SDK 会 fail-open,不阻塞正常体验。
API | 描述 |
|---|---|
| 创建 Engine 实例,配置必填的 API host、模型及可选的 token 和日志等级。 |
| 更新后续 Open Platform 请求使用的百炼临时 api-key token。 |
| 创建一次尚未启动的 Travel 会话。 |
new HappyOysterEngine
创建一个 HappyOysterEngine 实例。
签名
new HappyOysterEngine(config: SDKConfig)
参数
SDKConfig
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
APIHost | string | 是 | Open Platform API host,必须是裸 host,例如 |
model | string | 是 | 要使用的 Open Platform 模型标识。必填,无默认值;在 Engine 创建时固定,其所有 Travel 共用此配置。 |
token | string | 否 | 构造时设置的百炼临时 api-key token。也可之后通过 |
logLevel | LogLevel | 否 | SDK 日志等级,默认 |
streamReadyTimeout | number | 否 | 等待 |
model 应填写模型标识,例如 Adventure 模型 happyoyster-1.0-adventure;实际值应与目标服务环境一致。SDK 不会根据体验 mode 自动选择模型,也不会解析 ticket 推断模型。
一个 Engine 固定对应 APIHost + model,可复用于同一服务和模型的多次 Travel。切换任一配置前,先结束当前 Travel,再使用目标配置的 Engine;世界创建和 ticket 签发也应指向同一服务目标。
返回值
返回 HappyOysterEngine 实例。
错误
config 缺失,或 APIHost、model、token、logLevel、streamReadyTimeout 类型/取值不合法时,会同步抛出 SdkError,错误码为 ErrorCode.INVALID_ARGUMENT(10010001)。APIHost 传入完整 URL、空字符串或带路径的字符串都属于非法入参。
model 为必填项,必须是去除首尾空白后非空的字符串;null、非字符串和纯空白字符串均为非法值。省略或传 undefined 同样会报参数错误;SDK 不提供默认模型。
updateToken
更新后续 Open Platform API 请求使用的百炼临时 api-key token。
签名
updateToken(token: string): void
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
token | string | 是 | 百炼临时 api-key token。传入空白字符串会清空当前 token。 |
返回值
无返回值。
错误
token 不是字符串时,会同步抛出 SdkError,错误码为 ErrorCode.INVALID_ARGUMENT(10010001)。
createTravel
创建一次 Travel 会话实例,但不启动会话。
签名
createTravel(config: CreateTravelConfig): Travel
参数
CreateTravelConfig
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
ticket | string | 是 | 用于之后启动 Travel 的 ticket。 |
videoElement | HTMLVideoElement | 是 | 用于渲染会话视频的 |
maxExperienceTimeSec | 60 | 90 | 120 | 否 | Adventure 最大体验时间,单位秒;Directing 和角色演绎会忽略该字段,省略时由服务端使用默认值。 |
返回值
返回已创建但尚未启动的 Travel 会话对象。调用方需要再执行 await travel.start() 才会正式进入会话并等待视频可播放。
每个 HappyOysterEngine 实例同一时间只允许存在一个 active Travel。如需创建下一次 Travel,请先调用 await travel.end()。
错误
createTravel() 会在以下情况同步抛出 SdkError:
ErrorCode | 描述 |
|---|---|
|
|
| 当前已有进行中的 Travel,需先调用 |
启动阶段的错误由 travel.start() 暴露。
Travel
Travel 表示一次由 HappyOysterEngine.createTravel() 创建的会话。创建后会话尚未启动,调用 travel.start() 后,SDK 会进入会话并等待视频可播放。
Travel 提供会话启动、暂停、恢复、回退、结束、实时操控指令和提示词发送能力,也提供状态变化和运行时错误订阅。
方法
方法 | 描述 |
|---|---|
| 启动当前 Travel 会话。 |
| 订阅会话状态变化。 |
| 订阅首帧 URL 生成通知。 |
| 订阅进入会话后即可获得的会话元信息。 |
| 订阅会话运行时错误。 |
| 判断当前是否可以调用指定动作。 |
| 获取已返回的会话元信息;尚未返回时为 |
| 发送实时操控指令。 |
| 发送实时导演或提示词内容。 |
| 暂停当前会话。 |
| 恢复已暂停的会话。 |
| 将当前会话回退到指定秒数。 |
| 结束当前会话并释放相关资源。 |
状态
状态 | 描述 |
|---|---|
| 会话尚未启动。 |
| 会话正在启动并等待视频可播放。 |
| 会话正在运行。 |
| 会话已暂停,可继续恢复或回退。 |
| 会话已正常结束并释放资源。 |
事件
通过 travel.on(event, handler) 订阅事件。订阅方法返回取消订阅函数。
事件 | 回调 | 描述 |
|---|---|---|
statusChanged | (status: TravelStatus) => void | 会话状态变化。 |
firstFrameGenerated | (firstFrame: string) => void | 在 |
travelInfoReady | (info: TravelInfo) => void | enter-travel 返回后、RTC 连接前触发。可通过 |
error | (error: unknown) => void | 会话运行时错误。 |
Travel.can
判断当前状态和会话能力下是否可以调用指定动作。
签名
can(action: TravelAction): boolean
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
action | TravelAction | 是 | 要检查的动作: |
返回值
返回 boolean。true 表示当前可以调用该动作;false 表示当前状态、模式或会话能力不满足前置条件。
可用条件
action | 可用条件 |
|---|---|
| Travel 仍为 |
|
|
|
|
|
|
|
|
|
|
| Travel 未关闭。 |
错误
当前方法不会主动抛出业务错误;未知动作会返回 false。
Travel.start
启动当前 Travel 会话。
签名
start(): Promise<StartTravelResult>
参数
无参数。
返回值
返回 Promise<StartTravelResult>。Promise 在会话启动完成、视频可播放后 resolve。
enter-travel 返回后,SDK 会在连接 RTC 前触发 travelInfoReady。晚订阅方可调用 travel.getInfo();尚未返回时为 null。若响应中含非空 firstFrame,仍会紧随该事件触发 firstFrameGenerated。
StartTravelResult
字段 | 类型 | 描述 |
|---|---|---|
encryptedTravelId | string | 当前 Travel 会话 ID。 |
mode | number | 会话模式: |
creationModel | string | 世界创建模型,常见值为 |
firstFrame | string | null | 首帧图片 URL;服务端未返回时为 |
maxExperienceTimeSec | 60 | 90 | 120 | null | Adventure 最大体验时间(秒);Directing、角色演绎或服务端未返回该字段时为 |
aspectRatio | "9:16" | "16:9" | null | 角色演绎画幅;其他模式或服务端未返回该字段时为 |
错误
start() 会在以下情况 reject,并触发 error 事件。可通过 isSdkError(err) 判断,并读取 err.code 与 err.message。
ErrorCode | 描述 |
|---|---|
| SDK 功能开关关闭( |
| 无法启动:当前状态不允许、Open Platform 未配置,或进入会话失败 |
| 无法启动:服务端返回的会话配置不完整 |
| 无法启动:建立视频流连接失败,或 SDK 功能开关请求失败 |
| 无法启动:等待视频流就绪超时(取 |
| 无法启动:等待视频可播放超时(受 |
| Open Platform 参数、资源或服务端错误 |
Travel.on("statusChanged")
订阅会话状态变化。
签名
on("statusChanged", handler: (status: TravelStatus) => void): () => void
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
handler | (status: TravelStatus) => void | 是 | 状态变化时调用的回调。 |
返回值
返回取消订阅函数。TravelStatus 取值为 idle / prepare / running / paused / completed。
错误
当前方法不会主动抛出业务错误。
Travel.on("firstFrameGenerated")
订阅首帧 URL 生成通知。
签名
on("firstFrameGenerated", handler: (firstFrame: string) => void): () => void
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
handler | (firstFrame: string) => void | 是 | 首帧 URL 可用时调用的回调。 |
返回值
返回取消订阅函数。
行为
仅在 travel.start() 过程中触发。SDK 调用 Open Platform enter-travel 并拿到非空 firstFrame 后立即 emit,通常发生在 statusChanged("prepare") 之后、start() resolve 和视频可播放之前。若响应未返回首帧 URL,则不会触发。
错误
当前方法不会主动抛出业务错误。
Travel.onError
订阅会话运行时错误。
签名
onError(handler: (error: unknown) => void): () => void
参数
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
handler | (error: unknown) => void | 是 | 运行时错误发生时调用的回调。 |
返回值
返回取消订阅函数。错误对象可通过 isSdkError 收窄为 SdkError。
错误
当前方法不会主动抛出业务错误。
Travel.sendCommand
发送实时操控指令。
签名
sendCommand(params: AdventureCommand): Promise<void>
参数
AdventureCommand
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
translation | string | 否 | 移动方向。未传时按 |
rotation | string | 否 | 视角旋转。未传时按 |
interaction | string | 否 | 交互动作。未传时按 |
控制指令参考
translation — 移动方向
描述角色的移动方向,支持 8 个方向及组合。
值 | 方向 |
|---|---|
| 前 |
| 后 |
| 左 |
| 右 |
| 左前 |
| 右前 |
| 左后 |
| 右后 |
| 静止 |
rotation — 视角旋转
模拟鼠标方向的视角转动,支持 8 个方向。
值 | 方向 |
|---|---|
| 上 |
| 下 |
| 左 |
| 右 |
| 左上 |
| 右上 |
| 左下 |
| 右下 |
| 无 |
interaction — 交互动作
值 | 动作 |
|---|---|
| 跳跃 |
| 攻击 |
| 蹲下 |
| 冲刺 |
| 无 |
返回值
返回 Promise<void>。指令提交完成后 resolve。
错误
sendCommand() 会在以下情况 reject:
ErrorCode | 描述 |
|---|---|
|
|
| 当前状态/会话模式不允许发送指令,或视频流侧指令发送失败 |
Travel.sendInstruct
发送实时导演或提示词内容。
签名
sendInstruct(params: InstructData): Promise<void>
参数
InstructData
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
content | string | 是 | 要发送的提示词内容。 |
返回值
返回 Promise<void>。Open Platform 接收并处理完成后 resolve。
错误
sendInstruct() 会在以下情况 reject,并触发 error 事件:
ErrorCode | 描述 |
|---|---|
| 会话尚未启动 |
| 发送实时导演指令失败 |
| Open Platform 参数、资源或服务端错误 |
Travel.pause
暂停当前会话。
签名
pause(): Promise<void>
参数
无参数。
返回值
返回 Promise<void>。视频停止播放后 resolve。
错误
pause() 会在以下情况 reject:
ErrorCode | 描述 |
|---|---|
| 当前状态、会话模式或会话能力不允许暂停,或暂停请求失败 |
| 等待 backend 上报视频流状态为 paused 超时(15 秒) |
| Open Platform 参数、资源或服务端错误 |
Travel.resume
恢复已暂停的会话。
签名
resume(): Promise<void>
参数
无参数。
返回值
返回 Promise<void>。视频恢复可播放后 resolve。
错误
resume() 会在以下情况 reject:
ErrorCode | 描述 |
|---|---|
| 当前状态、会话模式或会话能力不允许恢复,或恢复请求失败 |
| 等待视频恢复可播放超时(15 秒) |
| Open Platform 参数、资源或服务端错误 |
Travel.rewind
将当前会话回退到指定秒数。
签名
rewind(params: RewindTravelParams): Promise<RewindTravelResult>
参数
RewindTravelParams
字段 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
rewindToSec | number | 是 | 要回退到的秒数,仅支持 4 的整数倍(如 |
返回值
返回 Promise<RewindTravelResult>。回退完成并恢复播放后 resolve。
RewindTravelResult
字段 | 类型 | 描述 |
|---|---|---|
resumedAtSec | number | 服务端实际恢复播放的秒数。 |
错误
rewind() 会在以下情况 reject,并触发 error 事件:
ErrorCode | 描述 |
|---|---|
| 会话尚未启动 |
| 无法回退:须先暂停且视频已停止播放,或回退请求/重连 RTC 失败 |
| 回退后等待视频恢复超时(15 秒) |
| Open Platform 参数、资源或服务端错误 |
Travel.end
结束当前会话并释放相关资源。
签名
end(): Promise<void>
参数
无参数。
返回值
返回 Promise<void>。清理流程结束后 resolve。
错误
清理过程中的错误不会向调用方抛出;end() 会尽量完成资源释放。
错误处理
SDK 通过 Promise reject 或 error 事件暴露运行时错误。错误对象为 SdkError,可通过 isSdkError(err) 判断,并读取 err.code 与 err.message。
Open Platform 返回的可识别错误会映射到 10000001–10000012 区间;err.message 为平台返回的说明文案。各 Travel 方法特有的错误码见对应 API 的错误小节。
ErrorCode 一览
错误码分段约定:
100000xx:Open Platform 映射错误1001xxxx:Engine 客户端错误1002xxxx:Travel 客户端错误
code | name | 描述 |
|---|---|---|
|
| 请求参数无效(Open Platform 返回) |
|
| 资源不存在(Travel 不存在 / 不归属 / 跨 workspace / 产物未就绪) |
|
| 世界不存在、已删除或不属于当前开发者 |
|
| 系统错误 |
|
| ticket 无效或已过期 |
|
| ticket 已使用(一次性凭证) |
|
| 世界状态非 ready,不可进入 |
|
| 推理资源分配失败(席位不足、推流创建失败、Session 初始化失败等) |
|
| 当前接口仅允许主 API Key(临时 API Key 不可用) |
|
| 输入内容违规(内容安审拦截) |
|
| 输入图片版权 / IP 违规 |
|
| 请求与当前资源状态冲突 |
|
| SDK 客户端入参校验失败(非 Open Platform 映射) |
|
| SDK 功能开关关闭 |
|
| 已有进行中的 Travel |
|
| 播放中视频流断流 |
|
| 启动会话请求失败 |
|
| 启动时视频流配置缺失 |
|
| 视频流连接失败 |
|
| 等待视频流就绪超时 |
|
| 等待视频可播放超时 |
|
| 暂停请求失败 |
|
| 等待视频暂停超时 |
|
| 恢复请求失败 |
|
| 等待视频恢复超时 |
|
| 回退请求失败 |
|
| 回退后等待视频恢复超时 |
|
| 发送实时操控指令失败 |
|
| 发送实时导演指令失败 |
|
| 结束会话请求失败 |
其他导出
Runtime exports
导出 | 类型 | 描述 |
|---|---|---|
| class | SDK client,负责配置 Open Platform、更新 token 和创建 Travel。 |
| string | 当前 SDK 版本号。 |
| SDKMetadata | 当前 SDK 包名、版本和包渠道。 |
| const | SDK 对外暴露的错误码常量对象。 |
| function | 判断未知错误是否为 SDK 标准错误。 |
ErrorCode
SDK 对外暴露的错误码常量对象。调用方可以用它和 SdkError.code 做稳定比较,避免在业务代码里散落数字字面量。
import { ErrorCode } from '@happy-oyster/js-sdk'
isSdkError
判断未知错误是否为 SDK 标准错误。返回 true 后,TypeScript 会把错误收窄为 SdkError,可以安全读取 code 与 message。
isSdkError(error: unknown): error is SdkError
try {
await travel.start()
} catch (err) {
if (isSdkError(err) && err.code === ErrorCode.OPEN_PLATFORM_TICKET_INVALID) {
// Request a new Travel ticket, then create a new Travel.
}
}
公开类型
以下类型从 package entry 导出,可直接从 @happy-oyster/js-sdk 引入。它们只在 TypeScript 编译期存在,不会产生运行时代码。
类型 | 描述 |
|---|---|
|
|
| SDK 日志等级: |
| SDK 包元信息: |
| SDK 包渠道: |
|
|
|
|
| 在 |
| 角色演绎画幅: |
|
|
| SDK 本地会话状态: |
|
|
|
|
|
|
|
|
|
|
| 包含 |
| 运行时 |
|
|