声纹仅留 CAM++(用户拍板:eres2net 系识别效果太差整体退役):speakerModels 单条;initFastSpeakerModel 删除;单模型单空间——fastReady=false 时全部 fast 路径自动回落准确注册表(0.5/0.42 更严),滚动/快检/权威判定共用 CAM++;deferredNaming 镜像计算门控跳过;代价=每次滚动检查换 CAM++ 推理(检查线程串行,1s 节拍下可承受);设备 eres2net 两文件已无引用可删
This commit is contained in:
parent
dea9622245
commit
12f008a4c1
|
|
@ -159,12 +159,11 @@ class MainActivity : AppCompatActivity() {
|
||||||
// Embedding model candidates, tried in order. Place one in the external
|
// Embedding model candidates, tried in order. Place one in the external
|
||||||
// models dir (preferred) or at the ROOT of assets/. Download:
|
// models dir (preferred) or at the ROOT of assets/. Download:
|
||||||
// https://github.com/k2-fsa/sherpa-onnx/releases/tag/speaker-recongition-models
|
// https://github.com/k2-fsa/sherpa-onnx/releases/tag/speaker-recongition-models
|
||||||
|
// 仅 CAM++(2026-09-16 用户拍板:eres2net 系识别效果太差,整体退役)。
|
||||||
|
// 单模型单空间:滚动/快检/权威判定共用 CAM++;fastReady()=false 时所有
|
||||||
|
// fast 路径自动回落准确注册表(阈值 0.5/0.42,更严更稳)
|
||||||
private val speakerModels = listOf(
|
private val speakerModels = listOf(
|
||||||
// 主选:CAM++ 7.1M,中英训练,3D-Speaker 榜单 EER 优于 eres2net 系,
|
|
||||||
// v1.13 声纹提取器架构无关(读 ONNX 元数据),换文件即生效
|
|
||||||
"3dspeaker_speech_campplus_sv_zh_en_16k-common_advanced.onnx",
|
"3dspeaker_speech_campplus_sv_zh_en_16k-common_advanced.onnx",
|
||||||
"3dspeaker_speech_eres2netv2_sv_zh-cn_16k-common.onnx", // accurate fallback
|
|
||||||
"3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx", // smaller/faster
|
|
||||||
)
|
)
|
||||||
private var activeSpeakerModel: String? = null
|
private var activeSpeakerModel: String? = null
|
||||||
private val speakerThreshold = 0.5f
|
private val speakerThreshold = 0.5f
|
||||||
|
|
@ -464,9 +463,6 @@ class MainActivity : AppCompatActivity() {
|
||||||
initOfflineRecognizer()
|
initOfflineRecognizer()
|
||||||
setStatus(getString(R.string.loading_speaker))
|
setStatus(getString(R.string.loading_speaker))
|
||||||
initSpeakerIdentification()
|
initSpeakerIdentification()
|
||||||
if (speakersEnabled) {
|
|
||||||
initFastSpeakerModel()
|
|
||||||
}
|
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
modelsLoaded = true
|
modelsLoaded = true
|
||||||
if (!historyMode) recordButton.isEnabled = true
|
if (!historyMode) recordButton.isEnabled = true
|
||||||
|
|
@ -1232,23 +1228,6 @@ class MainActivity : AppCompatActivity() {
|
||||||
activeSpeakerModel = null
|
activeSpeakerModel = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// E:轻量声纹模型(eres2net base,列表末位)专供滚动换人检测,推理快 ~4 倍。
|
|
||||||
// 找不到该文件(或准确模型本来就是 base)时跳过,滚动检测自动回退准确模型。
|
|
||||||
// 注:换 CAM++ 主选后 fast 空间暂仍用 base(独立 registry 镜像,互不污染);
|
|
||||||
// CAM++ 足够小,后续想让它兼职 fast 只需把末位换成同文件。
|
|
||||||
private fun initFastSpeakerModel() {
|
|
||||||
val fastName = speakerModels.last()
|
|
||||||
if (activeSpeakerModel == fastName) return // 准确模型已是 base
|
|
||||||
try {
|
|
||||||
SpeakerRecognition.initFastExtractor(
|
|
||||||
null, speakerModelFile(fastName).absolutePath
|
|
||||||
)
|
|
||||||
Log.i(TAG, "fast speaker model ready: $fastName")
|
|
||||||
} catch (t: Throwable) {
|
|
||||||
Log.i(TAG, "fast model '$fastName' not found, rolling falls back to v2")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击行首说话人标签(ClickableSpan)→ 命名或改名。
|
// 点击行首说话人标签(ClickableSpan)→ 命名或改名。
|
||||||
// internalKey:该行的内部声纹键("S0"/真名);null=归属未定,提示稍后再命名。
|
// internalKey:该行的内部声纹键("S0"/真名);null=归属未定,提示稍后再命名。
|
||||||
private fun showNameSpeakerDialog(internalKey: String?) {
|
private fun showNameSpeakerDialog(internalKey: String?) {
|
||||||
|
|
@ -1860,9 +1839,11 @@ class MainActivity : AppCompatActivity() {
|
||||||
uiHandler.post { adoptSwitchLabel(serial, name) }
|
uiHandler.post { adoptSwitchLabel(serial, name) }
|
||||||
}
|
}
|
||||||
name == null || score < verdictFallbackMin -> {
|
name == null || score < verdictFallbackMin -> {
|
||||||
// 确认无人:发新号 + 双空间注册(纯净素材)
|
// 确认无人:发新号注册(纯净素材);fastReady=false(单 CAM++)时
|
||||||
val fastEmb = SpeakerRecognition.computeEmbeddingFast(
|
// 镜像无意义,跳过额外计算
|
||||||
samples, sampleRateInHz)
|
val fastEmb = if (SpeakerRecognition.fastReady()) {
|
||||||
|
SpeakerRecognition.computeEmbeddingFast(samples, sampleRateInHz)
|
||||||
|
} else null
|
||||||
val label = SpeakerRecognition.nextAutoLabel().also {
|
val label = SpeakerRecognition.nextAutoLabel().also {
|
||||||
SpeakerRecognition.registry.addAuto(it, acc)
|
SpeakerRecognition.registry.addAuto(it, acc)
|
||||||
if (fastEmb != null) {
|
if (fastEmb != null) {
|
||||||
|
|
|
||||||
|
|
@ -221,9 +221,10 @@ class SpeakerRegistry {
|
||||||
// Singleton holder shared by the UI thread, recording thread and the rolling
|
// Singleton holder shared by the UI thread, recording thread and the rolling
|
||||||
// speaker-check thread.
|
// speaker-check thread.
|
||||||
//
|
//
|
||||||
// 双模型方案(E):准确模型(eres2netv2)负责 endpoint 权威判定与注册;
|
// 单模型方案(2026-09-16 用户拍板):仅 CAM++;eres2net 系整体退役。
|
||||||
// 轻量模型(eres2net base,可选)只负责滚动换人检测(推理快 ~4 倍)。
|
// fastReady()=false 时:computeEmbeddingFast 回落 CAM++,滚动检索直接走
|
||||||
// ⚠ 两个模型的 embedding 不互通:各自配一份 registry,注册时双写镜像。
|
// 准确注册表(speakerThreshold 0.5 / verdictFallbackMin 0.42)。镜像注册
|
||||||
|
// 机制保留但不再有调用者(fastEmb 门控后恒 null)。
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
object SpeakerRecognition {
|
object SpeakerRecognition {
|
||||||
@Volatile private var _extractor: SpeakerEmbeddingExtractor? = null
|
@Volatile private var _extractor: SpeakerEmbeddingExtractor? = null
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue