不知道大家关注没有 Rokid 的眼镜啊,最近可是超级的火,我也是第一时间去看了新品发布会,里面有许多的功能还是很震撼的。

人超级多,也遇见了好多的老熟人,当然也有自己比较关注的 up 主 Tim。

当然说回来,我们也来聊一个 Rokid 眼镜上的一些应用开发,毕竟它能给我们带来哪些创新性体验,才是我们更关注的。
在官方的 SDK 中有个提词器场景,实则官方 SDK 实则已经把提词器能力封装得比较完整了,当然我们在这个基础上,在增加点“小玩意”,列如“自动跟读滚动”~!

一、为什么我开始折腾“自动跟读滚动”
做内容的人应该都有过类似的崩溃体验:
- 要么是提词器滚得太快,被迫狂读;
- 要么就是滚得太慢,自己说完一句还要在那里干等着字幕挪下去。
在 Rokid 的 AR 眼镜上,这个问题更明显——屏幕就在眼前,一旦节奏不对,很容易被打乱思路。
Rokid 的 GlassesSDK 里,实则已经把提词器能力封装得比较完整了:既包括基础的“打开场景 + 下发文案”,也包括基于 ASR 结果的 AI 实时滚动能力。
这篇文章就按照我自己的实战过程,从 0 到 1 带你把提词器场景跑起来,然后结合 GlassesSDK 文档里给出的接口,做一个“让提词跟着我说话走”的自动跟读 Demo,顺便聊聊还能玩出哪些新花样。

二、先对照 GlassesSDK 文档,把提词器能力说清楚

在 GlassesSDK 文档里,提词器是一个独立的 CXR 场景(scene),核心接口正是你给到的这几组:
1)打开 / 关闭提词器场景
fun openOrCloseWordTips(toOpen: Boolean): ValueUtil.CxrStatus? {
return CxrApi.getInstance()
.controlScene(ValueUtil.CxrSceneType.WORD_TIPS, toOpen, null)
}
- 对应文档里的 controlScene(ValueUtil.CxrSceneType.WORD_TIPS, openOrClose, null)。
- 返回值是 ValueUtil.CxrStatus,常见取值:REQUEST_SUCCEED / REQUEST_WAITING / REQUEST_FAILED。
2)发送提词器内容(脚本文本)
private val sendCallback = object : SendStatusCallback {
override fun onSendSucceed() {
/* 文案下发成功 */
}
override fun onSendFailed(p0: ValueUtil.CxrSendErrorCode?) {
/* 记录错误码 */
}
}
fun setWordTipsText(text: String, fileName: String): ValueUtil.CxrStatus? {
return CxrApi.getInstance().sendStream(
ValueUtil.CxrStreamType.WORD_TIPS,
text.toByteArray(),
fileName,
sendCallback
)
}
3)配置提词器场景参数
fun configWordTipsText(
textSize: Float,
lineSpace: Float,
mode: String,
startPointX: Int,
startPointY: Int,
width: Int,
height: Int
): ValueUtil.CxrStatus? {
return CxrApi.getInstance().configWordTipsText(
textSize, lineSpace, mode,
startPointX, startPointY,
width, height
)
}
- mode 支持 “normal” 和 “ai”,后者就是文档里提到的“AI 模式,ASR 触发自动滚动”。
4)发送提词器 ASR 结果(AI 实时滚动的关键)
fun sendWordTipsAsrContent(content: String): ValueUtil.CxrStatus? {
return CxrApi.getInstance().sendAsrContent(content)
}
- 文档里的描述是:当模式为 “ai” 时,如果 ASR 结果触达当前画面尾部的几个字符,提词器会自动上滑。
- 所以这个接口不是“控制滚动速度”的,而是把“已经说出来的话”同步过去,让 SDK 自己做对齐和滚动判断。
理解完这四块之后,你再回头看 GlassesSDK 文档,就会发现:官方给出的实则是一套比较完整的“场景 + 数据流 + 模式配置 + ASR 同步”能力,我们要做的,只是基于这些接口配出一个顺畅的业务链路。
三、从 0 到 1:一个最小可用的 Rokid 提词器 Demo
下面这段 Kotlin 代码是我自己在 Demo 工程里的写法,基本就是对上面几个接口做了一层业务封装:
class TeleprompterManager {
private val sendCallback = object : SendStatusCallback {
override fun onSendSucceed() {
/* 这里可以做一些 UI 提示 */
}
override fun onSendFailed(error: ValueUtil.CxrSendErrorCode?) {
/* 打日志排查 */
}
}
fun open() {
val status = openOrCloseWordTips(true)
// 提议对 status 做判断,避免在 REQUEST_WAITING 状态下频繁请求
}
fun close() {
openOrCloseWordTips(false)
}
fun updateScript(text: String, fileName: String = "speech.txt") {
setWordTipsText(text, fileName)
}
fun configNormalMode(
textSize: Float = 26f,
lineSpace: Float = 1.4f,
startPointX: Int,
startPointY: Int,
width: Int,
height: Int
) {
configWordTipsText(
textSize,
lineSpace,
"normal",
startPointX,
startPointY,
width,
height
)
}
}
在 AR 眼镜上调试的时候,提议一开始先把文字区域画得小一点、靠下边缘一些,避免完全挡住视线。
等用户习惯了之后,再通过配置给他一个“沉浸式”的全屏提词体验。
四、关键一跳:把 GlassesSDK 里的 AI 实时滚动用起来
根据文档,configWordTipsText 的 mode 参数是整个“自动跟读滚动”的开关:
- “normal”:普通模式,不关联 ASR,主要依赖定速或手动滚动;
- “ai”:AI 模式,结合 sendWordTipsAsrContent 的内容,当识别文本触达当前画面尾部时自动上滑。
所以要让提词器“跟着我说话走”,必备的两步就是:
- 先把模式配置成 “ai”;
- 在语音识别有新结果时,调用 sendWordTipsAsrContent 把文本同步过去。
示例代码:
fun configAiMode(
textSize: Float = 26f,
lineSpace: Float = 1.4f,
startPointX: Int,
startPointY: Int,
width: Int,
height: Int
): ValueUtil.CxrStatus? {
return configWordTipsText(
textSize,
lineSpace,
"ai", // 开启 AI 模式
startPointX,
startPointY,
width,
height
)
}
fun onAsrResultChanged(asrText: String) {
// 这里的 asrText 一般是“当前已说出的全部内容”或者到当前句子的累积文本
sendWordTipsAsrContent(asrText.trim())
}
这里有几个和文档强相关的细节:
- 提议按“累积文本”发送,而不是只发最后几个词,这样更容易和脚本做对齐;
- 不要在 REQUEST_WAITING 状态下频繁调用,避免把 SDK 拍“懵”;
- ASR 文本在发送前做一点清洗(去掉多余空格、重复标点),可以减少误判滚动。
五、接上语音识别:完整的“自动跟读滚动”链路
从 GlassesSDK 的角度看,它只关心一件事:你能不能持续地把“已经识别出的文本”通过 sendWordTipsAsrContent 传过来,至于这个文本是来自 Rokid 自己的语音服务,还是来自第三方云 ASR,SDK 并不做限制。
下面是一个简化版的伪代码结构,重点在“如何把 ASR 结果整理之后喂给提词器”:
class AutoScrollTeleprompter(
private val teleprompterManager: TeleprompterManager,
private val asrClient: AsrClient // 你自己的语音识别封装
) {
private val sb = StringBuilder()
fun start(script: String) {
teleprompterManager.open()
teleprompterManager.updateScript(script)
teleprompterManager.configAiMode(
textSize = 28f,
lineSpace = 1.5f,
startPointX = 100,
startPointY = 200,
width = 800,
height = 600
)
asrClient.start(object : AsrListener {
override fun onPartialResult(text: String) {
sb.clear()
sb.append(text.trim())
sendWordTipsAsrContent(sb.toString())
}
override fun onFinalResult(text: String) {
// 最终结果可以用来做“对读评分”等分析
}
override fun onError(code: Int, msg: String?) {
// 错误处理
}
})
}
fun stop() {
asrClient.stop()
teleprompterManager.close()
}
}

六、实战玩法:做一个“演讲练习助手”后面的实战与扩展
光是自动滚动实则还不够“好玩”,结合 ASR,我们可以顺手把“练稿子”这件事做得更智能一点。
我在自己的 Demo 里做了一个简单的“演讲练习助手”:
- 提词器负责展示完整稿子,并跟着你读自动滚动;
- ASR 负责记录你实际说了什么;
- 结束后做一次对比,给你一些“很接地气”的反馈,列如:
- 哪几句话跳读了;
- 哪些词你常常读错或卡顿;
- 当前语速是偏快还是偏慢。
一个很粗暴但好用的实现方式是按句子对齐:
- 按照标点把原稿切成句子列表 scriptSentences;
- 把 ASR 的 finalResult 也做一次简单切分;
- 用一个很轻量的“类似度”算法(列如基于分词的重合度)去匹配。
伪代码大致是这样:
data class SentenceCheckResult(
val original: String,
val spoken: String?,
val similarity: Float
)
fun analyse(script: String, spokenText: String): List<SentenceCheckResult> {
val scriptSentences = splitToSentences(script)
val spokenSentences = splitToSentences(spokenText)
val results = mutableListOf<SentenceCheckResult>()
var j = 0
for (i in scriptSentences.indices) {
val s = scriptSentences[i]
var bestIdx = -1
var bestSim = 0f
for (k in j until spokenSentences.size) {
val sim = similarity(s, spokenSentences[k])
if (sim > bestSim) {
bestSim = sim
bestIdx = k
}
}
val spoken = if (bestIdx >= 0) spokenSentences[bestIdx] else null
if (bestIdx >= 0) j = bestIdx + 1
results.add(SentenceCheckResult(s, spoken, bestSim))
}
return results
}
后面你可以在眼镜上或者配套 App 里,把这些结果可视化出来,列如:
- 类似度 < 0.6 的句子用红色标记,提示“提议再练两遍”;
- 全文平均语速、总时长、停顿分布,用一个简单的图表展示。
对于常常要录公开课、直播或企业宣传片的同学来说,这种“自助练稿 + 自动跟读”的体验,真的比拿着稿子对着镜头硬背舒服太多。
七、基于当前 SDK 能做的几种创新玩法
前面说的演讲助手,只是“自动跟读滚动”的一个典型用法。
结合目前提词器相关的几个接口,实则还可以挖出不少玩法:
1. 远程导演模式
- 提词器场景依然跑在眼镜上;
- 导演在另一端用平板 / PC 改稿;
- 通过网络把最新文案同步到服务端,再由服务端调用 sendStream 下发到 Rokid;
- 实拍过程中,导演可以临时插一句提示、加一个备注,下一秒就出目前演员眼前。
2. 多语言对照提词
- 用一份脚本生成中英文两份文本;
- 通过排版控制,让英文小号字体显示在下方或侧边;
- 结合 ASR 只对中文做自动滚动,英文只是跟随展示作为对照。
3. 会议 / 培训中的“现场提醒条”
- 不是传统意义上的全文提词,而是在眼镜的一小块区域滚动关键信息;
- 列如:下一页 PPT 的重点、即将要问的问题、时间提醒;
- 通过 configWordTipsText 把提词区域收得比较小,就可以变成一个“隐形便签条”。
4. 拍摄安全提示 / 法务提示场景
- 在录制对外视频时,让拍摄者在开头自动读一段合规提示;
- 系统用 ASR 校验是否的确 读完了关键条目,才允许开始正式录制;
- 这里同样可以用 sendWordTipsAsrContent 的文本对齐结果做一个简单的检查。
这些玩法本质上都没有超出当前 SDK 提供的能力,只是把“提词内容 + 布局 + ASR 结果”这三块重新拼了一下。
从工程实现角度来说,你完全可以先封装一层自己的 TeleprompterService,把 CxrApi 的细节藏在里面,对业务层暴露的是更高层的概念:
- TeleprompterSceneConfig(布局、字体、模式);
- ScriptSegment(脚本片段,多语言、类别标签);
- AsrSyncStrategy(如何把 ASR 文本映射到脚本)。
八、开发中踩到的一些坑
最后简单记几条我在调试过程中踩过的坑,给后面折腾的同学省点时间:
1.不要无脑高频调用 controlScene
- SDK 里已经明确提到有 REQUEST_WAITING 这个状态;
- 如果频繁 open / close,很容易在状态切换时卡住场景;
- 提议在业务层自己维护一个状态机,只有判断的确 是“场景已关闭”时才去调用 open。
2.sendStream 的编码问题
- 最好明确指定 UTF-8,避免在某些环境下出现乱码;
- 另外,fileName 可以当作一个轻量级的脚本 ID,用来区分不同的文案版本。
3.configWordTipsText 的坐标和尺寸
- 不同设备分辨率、FOV 略有差异,最好做一层适配;
- 可以先根据设备的物理分辨率算一个“逻辑安全区域”,把提词器放在其中;
- 不要一上来就全屏,尤其是在需要看清现实环境的场景。
4.ASR 的延迟和闪烁
- 如果 ASR 是云端识别,网络波动时很容易出现先静止一会儿,然后一次性滚很大一段的情况;
- 可以在业务层做一个“节流 + 缓冲”:收到长段结果时分段发送给 sendAsrContent,让滚动看起来更自然。
5.异常处理
- CxrStatus 里的 REQUEST_FAILED 必定要打详细日志,否则后期排查问题会超级不舒服;
- sendStream 的失败回调里,可以做一次降级,列如提示用户重新加载脚本。
这些细节在 Demo 阶段可能感觉不明显,但一旦你把这个功能交给真正的主播、讲师、运营同学去用,就会立刻感受到“工程质量”的差距。
九、最后的小总结
GlassesSDK 给提词器做的 “ai” 模式,本质上是把“字幕滚动”这件事从一个纯 UI 动画,升级成了一个和语音识别紧密联动的能力。
按照文档,把 openOrCloseWordTips / setWordTipsText / configWordTipsText / sendWordTipsAsrContent 几个接口串起来,实则已经能比较完整地说明:“当前 GlassesSDK 里给出的提词器接口和 AI 实时滚动部分,如何在实际项目里落地”。
剩下的,就是结合自己的业务,把它变成一个真正有价值的功能:可以是演讲练习助手,可以是远程导演工具,也可以是带安全校验的合规提示提词。
如果你也做了自己的玩法,欢迎在论坛里交流,一起把提词器打造成 GlassesSDK 生态里的“标配能力”。





