ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Operit 构建期自动同步 STT 模型 assets:manifest 驱动、SHA-256 校验的 Gradle 生成资产管线

Operit 构建期自动同步 STT 模型 assets:manifest 驱动、SHA-256 校验的 Gradle 生成资产管线 AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆【免费下载链接】OperitThe most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent项目地址https://gitcode.com/gh_mirrors/op/Operit点击查看免费下载导读本文讲解 Operit 如何将默认的 Sherpa NCNN 本地语音识别STT模型与 Silero VAD 模型的准备过程从开发者手动准备 Google Drive 归档改造为Gradle 在构建期按受版本控制的 manifest 自动下载、校验并注入 APK。你将掌握syncSttModelAssets任务背后的 manifest 格式、下载与完整性校验实现、生成 assets 目录与mainsource set 的接线方式以及为什么校验失败会直接中止构建。该方案是 Operit STT 模型构建期自动准备计划的第二步整体计划见 STT 模型构建期自动准备。一、旧实现等待人工准备的 Google Drive 归档在本次改造之前Operit 的完整 Android 构建依赖从 Google Drive 下载一个models.zip归档Gradle 只读取预先手工放入src/main/assets/models的模型文件模型缺失时构建只能等待开发者手动下载 Google Drive 归档并解压到位模型来源、revision 和文件 hash 没有任何受版本控制的声明构建输入缺乏逐文件版本与完整性记录。这种做法的痛点在于CI 与贡献者都被迫依赖一份外部归档模型一旦被误删、过期或损坏构建便无法自愈也说不清当前打进 APK 的到底是哪个 commit 的模型。二、新设计manifest 驱动的生成 assets 流水线新实现把模型准备完全收归构建系统核心思路是清单即事实、校验即门槛syncSttModelAssets任务读取受版本控制的 stt-model-assets.properties将文件下载到app/build/generated/stt-model-assets下载后立即校验文件大小与 SHA-256校验不通过则构建失败生成目录通过syncMainAssets汇聚后作为mainsource set 的额外 assets 目录参与打包preBuild依赖同步任务因此所有 Android 打包入口release、debug、clone、nightly 及各类 merge 任务都使用完全相同的模型输入。从源码结构看这一流水线由三个角色协作manifest声明输入→syncSttModelAssets下载与校验→syncMainAssets sourceSet 接线注入 APK。三、模型来源清单六字段 manifest 详解清单文件 app/config/stt-model-assets.properties 定义了八个输入文件。每行字段以|分隔头部注释明确了字段顺序# target asset path | source URL | byte size | SHA-256 | source description | license note目标 assets 路径来源字节大小SHA-256前缀说明models/silero_vad.onnxsafestack/silero-vad8a63e2e86cf654d7ba19fbedbccce5ff55de3c6012896037ed98ddb…Silero VAD 16k 模型与既有 assets 完全相同models/sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-13/decoder_jit_trace-pnnx.ncnn.bincsukuangfj/sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-1305945efc40afe4b572542f01104ca5c413a9f6e16412296dc4df2d8…解码器权重…/decoder_jit_trace-pnnx.ncnn.param同上 commit439cb88f589…解码器结构…/encoder_jit_trace-pnnx.ncnn.bin同上 commit1273640564ed65f05…编码器权重最大文件约 127 MB…/encoder_jit_trace-pnnx.ncnn.param同上 commit16188897ad0954…编码器结构…/joiner_jit_trace-pnnx.ncnn.bin同上 commit73507240e6c4370…连接器权重…/joiner_jit_trace-pnnx.ncnn.param同上 commit49046c339f3…连接器结构…/tokens.txt同上 commit56317a8e0e4ec…词表关键点revision 固定Sherpa NCNN 模型固定到 commit05945efc40afe4b572542f01104ca5c413a9f6e1Silero VAD 固定到8a63e2e86cf654d7ba19fbedbccce5ff55de3c60。由于 Hugging Face 的resolve/commit/pathURL 不可变每个条目的 source URL 都可以直接构造出确定性的下载地址见 模型来源清单。许可备注Silero VAD 标注MITSherpa NCNN 各文件标注upstream license not declared in model metadata即上游模型元数据未声明许可证接入方需自行评估。八个文件全部位于models/前缀之下其中 7 个属于models/sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-13/与运行时加载路径一一对应。四、syncSttModelAssets 任务实现剖析任务本体定义在 app/build.gradle.kts。先是三个关键路径声明val sttModelAssetsManifestFile layout.projectDirectory.file(config/stt-model-assets.properties) val generatedSttModelAssetsDir layout.buildDirectory.dir(generated/stt-model-assets) val generatedMainAssetsDir layout.buildDirectory.dir(generated/main-assets)随后是任务注册build.gradle.ktsval syncSttModelAssets by tasks.registering { description Downloads and verifies generated assets for local STT recognition. group build setup inputs.file(sttModelAssetsManifestFile) outputs.dir(generatedSttModelAssetsDir) outputs.upToDateWhen { false } ... }outputs.upToDateWhen { false }意味着该任务每次构建都会重新执行校验逻辑——这是有意为之即使文件已在生成目录中也要保证其内容仍与 manifest 声明一致防止缓存掩盖损坏。4.1 manifest 解析与路径安全校验parseSttModelAssetManifestbuild.gradle.kts逐行读取清单跳过空行与#注释要求每行恰好 6 个字段并对目标路径做三重防御require(!targetPath.startsWith(/) !targetPath.contains(..) !targetPath.contains(\\)) { Invalid STT model asset target path: $targetPath }即目标路径既不能是绝对路径也不能包含..或反斜杠。这保证了 manifest 中声明的路径无法逃逸到生成目录之外。4.2 下载与校验失败即中止下载流程downloadSttModelAssetbuild.gradle.kts的要点使用HttpURLConnection设置connectTimeout 30_000、readTimeout 120_000并携带User-Agent: Operit Android build STT asset sync先写入同目录下的文件名.download临时文件HTTP 响应码不在 200–299 之间时直接require失败下载完成后立即调用verifySttModelAssetbuild.gradle.kts校验file.length() expectedBytes且sha256(file) expectedSha256通过后才用Files.move原子替换为目标文件。主循环build.gradle.kts的判定逻辑是若已有文件校验通过则跳过下载否则删除旧文件重新下载并在同步结束后再次require(verifySttModelAsset(...))兜底。任何一次校验失败都会让 Gradle 抛出异常从而中止构建——这与文档验收标准模型下载失败或内容不匹配会中止构建完全一致。4.3 清理任务输出只含 manifest 声明的文件同步末尾build.gradle.kts对生成目录做自底向上扫描删除不在expectedFiles集合中的残留文件stale asset删除同步后变空的子目录。因此syncSttModelAssets的输出集合与 manifest 声明精确相等满足验收标准任务输出仅包含 manifest 中定义的 assets。五、生成目录接线syncMainAssets 与 sourceSets生成目录本身不会自动进入 APK需要通过syncMainAssets汇聚build.gradle.ktsval syncMainAssets by tasks.registering(Sync::class) { description Assembles application assets with verified generated STT model files. group build setup dependsOn(syncSttModelAssets) from(src/main/assets) { exclude(models/**) } from(generatedSttModelAssetsDir) into(generatedMainAssetsDir) }它把原有src/main/assets中除models/**之外的所有资源与校验过的生成模型文件一起合并到build/generated/main-assets。随后 main source set 的 assets 目录被整体指向该生成目录build.gradle.ktssourceSets { getByName(main) { assets.setSrcDirs(listOf(generatedMainAssetsDir.get().asFile)) } }最后是任务依赖接线build.gradle.ktstasks.named(preBuild) { dependsOn(syncMainAssets) dependsOn(verifyExternallyBuiltNativeLibraries) } tasks.matching { it.name.matches(Regex(merge.*Assets)) }.configureEach { dependsOn(syncMainAssets) }preBuild是 Android 构建的公共前驱任务所有打包变体必然经过它同时所有merge*Assets任务也显式依赖syncMainAssets确保 assets merge 阶段拿到的始终是同步完成后的目录。六、运行时加载保持不变models/ 路径契约构建期改造刻意没有触碰运行时代码。从 SherpaSpeechProvider.kt 的源码可以看到识别器初始化仍以models/sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-13作为 assets 源路径val modelDirName sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-13 val assetModelDir models/$modelDirName val targetDir File(OperitPaths.sherpaNcnnModelsDir(context), modelDirName) localModelDir AssetCopyUtils.copyAssetDirRecursive(context, assetModelDir, targetDir)即运行时从 assets 复制模型到应用私有目录再以文件路径创建识别器VAD 侧则通过OnnxSileroVad(context context, ...)使用models/silero_vad.onnx。由于 manifest 中的目标路径与旧models/布局完全一致APK 内模型路径保持为models/sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-13/...运行时行为零改动——这正是文档验收标准运行时 assets 路径无需改动的实现保证。七、与 CI 及文档迁移的衔接作为计划第三步CI 与文档迁移CI 的完整 Android profile 不再下载和解包models.zip只保留三个非模型归档libs.zip、subpack.zip、jniLibs.zipSTT assets 由 Gradle 构建自动准备。相应地README 与编译、贡献指南如 BUILDING.md、CONTRIBUTING.md不再要求开发者手动处理模型归档。一个需要明确的适用前提首次构建或缓存失效重建时构建机必须能够访问固定的 Hugging Face 模型来源manifest 中记录的 commit 级 URL后续构建由于生成目录已被校验缓存不再重复下载。syncSttModelAssets每次仍会重跑校验逻辑但文件已存在且校验通过时不会发起网络请求。八、验证方式在仓库根目录Android 工程在app/模块可执行./gradlew :app:syncSttModelAssets该命令会按 app/config/stt-model-assets.properties 准备并校验生成目录随后执行./gradlew :app:assembleRelease等任意打包任务时preBuild会自动触发同步。可用以下方式核对产物检查app/build/generated/stt-model-assets/下八个文件与 manifest 中字节大小、SHA-256 一致解包 APK确认assets/models/silero_vad.onnx与assets/models/sherpa-ncnn-streaming-zipformer-bilingual-zh-en-2023-02-13/下七个文件存在故意篡改 manifest 中任一文件的大小或哈希后重建构建会因校验失败而中止——这是该机制自愈能力的最直观验证。小结Operit 通过受版本控制的 manifest 构建期下载校验 生成 assets 目录接线这一组合将 STT 模型的准备从人工环节彻底自动化来源固定到 commit 级 revision文件以大小和 SHA-256 双重校验输出与声明严格一致任何不匹配都会让构建立即失败而运行时的models/加载路径保持不变。这套模式对任何构建期需要引入大型外部二进制资产的 Android 项目都具有直接的参考价值。赞分享AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆【免费下载链接】OperitThe most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent项目地址https://gitcode.com/gh_mirrors/op/Operit点击查看免费下载相关推荐猫抓插件使用指南如何免费完成资源嗅探与网页视频下载猫抓插件使用指南如何免费完成资源嗅探与网页视频下载 猫抓Cat Catch是一款免费开源的浏览器资源嗅探扩展它会把当前网页加载过的视频、音频、图片等资源AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆GUI 自动化如何快速掌握WzComparerR2冒险岛数据提取的终极指南如何快速掌握WzComparerR2冒险岛数据提取的终极指南 WzComparerR2是一款专为《冒险岛》游戏设计的强大开源数据提取工具能够解析游戏WZ文件AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆GUI 自动化nullclaw 的 Vendored SQLite 3.51.0 集成确定性构建与 SHA-256 完整性校验实践nullclaw 的 Vendored SQLite 3.51.0 集成确定性构建与 SHA 256 完整性校验实践 本指南以 nullclaw 仓库中的 v人工智能AI Agent大模型自主智能体工具调用RAGAgent 记忆MCP ClientsAgent 沙箱多智能体语音上一篇如何在5分钟内搭建career-ops从安装到生成第一份专业简历的超简单指南 下一篇最完整LLMSherpa入门指南从安装到实现PDF布局解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进