diff --git a/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.mp4 b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.mp4 new file mode 100644 index 0000000..56268f4 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.mp4 differ diff --git a/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.wav b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.wav new file mode 100644 index 0000000..2fa6b22 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.wav differ diff --git a/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.mp4 b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.mp4 new file mode 100644 index 0000000..92c9205 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.mp4 differ diff --git a/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.wav b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.wav new file mode 100644 index 0000000..6c2f396 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.wav differ diff --git a/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.mp4 b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.mp4 new file mode 100644 index 0000000..5967eb4 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.mp4 differ diff --git a/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.wav b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.wav new file mode 100644 index 0000000..51d23f7 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.wav differ diff --git a/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.mp4 b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.mp4 new file mode 100644 index 0000000..6161d07 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.mp4 differ diff --git a/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.wav b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.wav new file mode 100644 index 0000000..690ccda Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.wav differ diff --git a/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.mp4 b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.mp4 new file mode 100644 index 0000000..d04afd3 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.mp4 differ diff --git a/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.wav b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.wav new file mode 100644 index 0000000..09bca9d Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.wav differ diff --git a/reports/bridge-005-moss-junhao-20260919/index.html b/reports/bridge-005-moss-junhao-20260919/index.html new file mode 100644 index 0000000..7f585a0 --- /dev/null +++ b/reports/bridge-005-moss-junhao-20260919/index.html @@ -0,0 +1,13 @@ +005 · MOSS Junhao 讲解对比 + +

此目录为本机旧素材试渲染,请查看 已校验 v2 素材的新旧对比预览

005 液压泵应急切换 · 新旧讲解对比

本机旧素材试渲染(非验收版本) · MOSS-TTS-Nano / Junhao · 1.0倍速 · 3:4。五个步骤沿用原讲解文稿,当前为独立预览,线上讲解未替换。

第 1 步 · 根据故障现象确定是哪一个液压泵发生故障

第1步,确定故障液压泵。根据故障现象确定发生故障的液压泵。

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

第 2 步 · 断开架桥车取力器

第2步,断开架桥车取力器。将架桥车取力器断开。

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

第 3 步 · 将架桥车备胎斜上方链接两个红色滤油器的球阀打开

第3步,打开互救球阀。打开备胎上方两个红色滤油器之间的连通球阀,手柄由垂直管道转为平行管道。

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

第 4 步 · 重新联通取力器

第4步,重新接通取力器。将架桥车取力器重新接通。

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

第 5 步 · 打开辅助控制盒内的“互救”开关

第5步,打开辅助控制盒互救开关。打开辅助控制盒盖,再打开互救开关,进入单泵作业状态。

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

\ No newline at end of file diff --git a/reports/bridge-005-moss-junhao-20260919/original-step-01.mp4 b/reports/bridge-005-moss-junhao-20260919/original-step-01.mp4 new file mode 100644 index 0000000..f627c15 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/original-step-01.mp4 differ diff --git a/reports/bridge-005-moss-junhao-20260919/original-step-02.mp4 b/reports/bridge-005-moss-junhao-20260919/original-step-02.mp4 new file mode 100644 index 0000000..b79c9d4 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/original-step-02.mp4 differ diff --git a/reports/bridge-005-moss-junhao-20260919/original-step-03.mp4 b/reports/bridge-005-moss-junhao-20260919/original-step-03.mp4 new file mode 100644 index 0000000..323db9e Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/original-step-03.mp4 differ diff --git a/reports/bridge-005-moss-junhao-20260919/original-step-04.mp4 b/reports/bridge-005-moss-junhao-20260919/original-step-04.mp4 new file mode 100644 index 0000000..2d0aea9 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/original-step-04.mp4 differ diff --git a/reports/bridge-005-moss-junhao-20260919/original-step-05.mp4 b/reports/bridge-005-moss-junhao-20260919/original-step-05.mp4 new file mode 100644 index 0000000..8499d40 Binary files /dev/null and b/reports/bridge-005-moss-junhao-20260919/original-step-05.mp4 differ diff --git a/reports/bridge-005-moss-junhao-20260919/result.json b/reports/bridge-005-moss-junhao-20260919/result.json new file mode 100644 index 0000000..7719fe8 --- /dev/null +++ b/reports/bridge-005-moss-junhao-20260919/result.json @@ -0,0 +1,62 @@ +{ + "profile": { + "agent": "测试虚拟教员", + "slug": "dh-ffcaecf8b65d", + "avatar": "教员1", + "providerAvatarId": "a1000000000000000000000000000005", + "voice": "MOSS · Junhao", + "engine": "MOSS-TTS-Nano", + "speed": 1.0, + "width": 480, + "height": 640, + "avatarManifestSha256": "7bcdedf502015b52ec230d404cbd6be53b7a40ed74e20fbe618de74ed2b38dc8" + }, + "steps": [ + { + "number": 1, + "title": "根据故障现象确定是哪一个液压泵发生故障", + "text": "第1步,确定故障液压泵。根据故障现象确定发生故障的液压泵。", + "video": "TASK-VIRTUAL-005-step-01-MOSS-Junhao.mp4", + "audio": "TASK-VIRTUAL-005-step-01-MOSS-Junhao.wav", + "duration": 9.2, + "videoSha256": "c9417a84696b07def80a4d33644f7cd13c4273724ded495bc1c98bed72bf6778" + }, + { + "number": 2, + "title": "断开架桥车取力器", + "text": "第2步,断开架桥车取力器。将架桥车取力器断开。", + "video": "TASK-VIRTUAL-005-step-02-MOSS-Junhao.mp4", + "audio": "TASK-VIRTUAL-005-step-02-MOSS-Junhao.wav", + "duration": 6.4, + "videoSha256": "b098e2d007f5eea7f0d9aed66697bd643f24c55b76409982183a01a7bec1f039" + }, + { + "number": 3, + "title": "将架桥车备胎斜上方链接两个红色滤油器的球阀打开", + "text": "第3步,打开互救球阀。打开备胎上方两个红色滤油器之间的连通球阀,手柄由垂直管道转为平行管道。", + "video": "TASK-VIRTUAL-005-step-03-MOSS-Junhao.mp4", + "audio": "TASK-VIRTUAL-005-step-03-MOSS-Junhao.wav", + "duration": 11.4, + "videoSha256": "ae6e3b218a449edd334a3904cc75f4db28ee24d6aee5b925ec93779be64230e7" + }, + { + "number": 4, + "title": "重新联通取力器", + "text": "第4步,重新接通取力器。将架桥车取力器重新接通。", + "video": "TASK-VIRTUAL-005-step-04-MOSS-Junhao.mp4", + "audio": "TASK-VIRTUAL-005-step-04-MOSS-Junhao.wav", + "duration": 7.0, + "videoSha256": "b17425fc91befc848f3396fba19f290760bcf3b8778830fe425197a2f584360a" + }, + { + "number": 5, + "title": "打开辅助控制盒内的“互救”开关", + "text": "第5步,打开辅助控制盒互救开关。打开辅助控制盒盖,再打开互救开关,进入单泵作业状态。", + "video": "TASK-VIRTUAL-005-step-05-MOSS-Junhao.mp4", + "audio": "TASK-VIRTUAL-005-step-05-MOSS-Junhao.wav", + "duration": 9.88, + "videoSha256": "5a4d2cbe5b26012349154636dafcb3aef1d65798671faf3eef53a7d63d492071" + } + ], + "publishedBindingsChanged": false +} \ No newline at end of file diff --git a/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.mp4 b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.mp4 new file mode 100644 index 0000000..eefd2dd Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.mp4 differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.wav b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.wav new file mode 100644 index 0000000..2fa6b22 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.wav differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.mp4 b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.mp4 new file mode 100644 index 0000000..e370eb1 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.mp4 differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.wav b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.wav new file mode 100644 index 0000000..6c2f396 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-02-MOSS-Junhao.wav differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.mp4 b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.mp4 new file mode 100644 index 0000000..6eee046 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.mp4 differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.wav b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.wav new file mode 100644 index 0000000..51d23f7 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-03-MOSS-Junhao.wav differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.mp4 b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.mp4 new file mode 100644 index 0000000..a6f4b07 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.mp4 differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.wav b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.wav new file mode 100644 index 0000000..690ccda Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-04-MOSS-Junhao.wav differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.mp4 b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.mp4 new file mode 100644 index 0000000..7d905a1 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.mp4 differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.wav b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.wav new file mode 100644 index 0000000..09bca9d Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-05-MOSS-Junhao.wav differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/frame-step-01.jpg b/reports/bridge-005-moss-junhao-v2-20260919/frame-step-01.jpg new file mode 100644 index 0000000..0084b2d Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/frame-step-01.jpg differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/index.html b/reports/bridge-005-moss-junhao-v2-20260919/index.html new file mode 100644 index 0000000..1bc9536 --- /dev/null +++ b/reports/bridge-005-moss-junhao-v2-20260919/index.html @@ -0,0 +1,13 @@ +005 · MOSS Junhao 讲解对比 + +

005 液压泵应急切换 · 新旧讲解对比

教员1 · v2素材 · MOSS-TTS-Nano / Junhao · 1.0倍速 · 3:4。五个步骤沿用原讲解文稿,当前为独立预览,线上讲解未替换。

第 1 步 · 根据故障现象确定是哪一个液压泵发生故障

第1步,确定故障液压泵。根据故障现象确定发生故障的液压泵。

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

第 2 步 · 断开架桥车取力器

第2步,断开架桥车取力器。将架桥车取力器断开。

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

第 3 步 · 将架桥车备胎斜上方链接两个红色滤油器的球阀打开

第3步,打开互救球阀。打开备胎上方两个红色滤油器之间的连通球阀,手柄由垂直管道转为平行管道。

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

第 4 步 · 重新联通取力器

第4步,重新接通取力器。将架桥车取力器重新接通。

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

第 5 步 · 打开辅助控制盒内的“互救”开关

第5步,打开辅助控制盒互救开关。打开辅助控制盒盖,再打开互救开关,进入单泵作业状态。

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

\ No newline at end of file diff --git a/reports/bridge-005-moss-junhao-v2-20260919/original-step-01.mp4 b/reports/bridge-005-moss-junhao-v2-20260919/original-step-01.mp4 new file mode 100644 index 0000000..f627c15 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/original-step-01.mp4 differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/original-step-02.mp4 b/reports/bridge-005-moss-junhao-v2-20260919/original-step-02.mp4 new file mode 100644 index 0000000..b79c9d4 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/original-step-02.mp4 differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/original-step-03.mp4 b/reports/bridge-005-moss-junhao-v2-20260919/original-step-03.mp4 new file mode 100644 index 0000000..323db9e Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/original-step-03.mp4 differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/original-step-04.mp4 b/reports/bridge-005-moss-junhao-v2-20260919/original-step-04.mp4 new file mode 100644 index 0000000..2d0aea9 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/original-step-04.mp4 differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/original-step-05.mp4 b/reports/bridge-005-moss-junhao-v2-20260919/original-step-05.mp4 new file mode 100644 index 0000000..8499d40 Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/original-step-05.mp4 differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/playback-validation.json b/reports/bridge-005-moss-junhao-v2-20260919/playback-validation.json new file mode 100644 index 0000000..7353a73 --- /dev/null +++ b/reports/bridge-005-moss-junhao-v2-20260919/playback-validation.json @@ -0,0 +1,37 @@ +[ + { + "width": 480, + "height": 640, + "duration": 9.24, + "playing": true, + "error": null + }, + { + "width": 480, + "height": 640, + "duration": 6.48, + "playing": true, + "error": null + }, + { + "width": 480, + "height": 640, + "duration": 11.4, + "playing": true, + "error": null + }, + { + "width": 480, + "height": 640, + "duration": 6.96, + "playing": true, + "error": null + }, + { + "width": 480, + "height": 640, + "duration": 9.96, + "playing": true, + "error": null + } +] \ No newline at end of file diff --git a/reports/bridge-005-moss-junhao-v2-20260919/preview-page.png b/reports/bridge-005-moss-junhao-v2-20260919/preview-page.png new file mode 100644 index 0000000..96568eb Binary files /dev/null and b/reports/bridge-005-moss-junhao-v2-20260919/preview-page.png differ diff --git a/reports/bridge-005-moss-junhao-v2-20260919/result.json b/reports/bridge-005-moss-junhao-v2-20260919/result.json new file mode 100644 index 0000000..21d6db9 --- /dev/null +++ b/reports/bridge-005-moss-junhao-v2-20260919/result.json @@ -0,0 +1,62 @@ +{ + "profile": { + "agent": "测试虚拟教员", + "slug": "dh-ffcaecf8b65d", + "avatar": "教员1", + "providerAvatarId": "a1000000000000000000000000000005", + "voice": "MOSS · Junhao", + "engine": "MOSS-TTS-Nano", + "speed": 1.0, + "width": 480, + "height": 640, + "avatarManifestSha256": "8155a21af68b60ea024c7591c8ad454aa9884a2c7d22cb069c16bb192bc4e122" + }, + "steps": [ + { + "number": 1, + "title": "根据故障现象确定是哪一个液压泵发生故障", + "text": "第1步,确定故障液压泵。根据故障现象确定发生故障的液压泵。", + "video": "TASK-VIRTUAL-005-step-01-MOSS-Junhao.mp4", + "audio": "TASK-VIRTUAL-005-step-01-MOSS-Junhao.wav", + "duration": 9.24, + "videoSha256": "39fe0da650f4ee162c6106073509415bbbb869a3657e145d69acd1b32fdf8195" + }, + { + "number": 2, + "title": "断开架桥车取力器", + "text": "第2步,断开架桥车取力器。将架桥车取力器断开。", + "video": "TASK-VIRTUAL-005-step-02-MOSS-Junhao.mp4", + "audio": "TASK-VIRTUAL-005-step-02-MOSS-Junhao.wav", + "duration": 6.48, + "videoSha256": "74ea5f713a855136d7152dcadc7d97523556e229181e58a593a975a5f5550af6" + }, + { + "number": 3, + "title": "将架桥车备胎斜上方链接两个红色滤油器的球阀打开", + "text": "第3步,打开互救球阀。打开备胎上方两个红色滤油器之间的连通球阀,手柄由垂直管道转为平行管道。", + "video": "TASK-VIRTUAL-005-step-03-MOSS-Junhao.mp4", + "audio": "TASK-VIRTUAL-005-step-03-MOSS-Junhao.wav", + "duration": 11.4, + "videoSha256": "ad2495509abf63328e7832fc471059e66b37f93d37276499e97682af1238163c" + }, + { + "number": 4, + "title": "重新联通取力器", + "text": "第4步,重新接通取力器。将架桥车取力器重新接通。", + "video": "TASK-VIRTUAL-005-step-04-MOSS-Junhao.mp4", + "audio": "TASK-VIRTUAL-005-step-04-MOSS-Junhao.wav", + "duration": 6.96, + "videoSha256": "e91ea2f247d9ceadb2c4a5c5e0e516609891be19572a4f08271b7a9aad611095" + }, + { + "number": 5, + "title": "打开辅助控制盒内的“互救”开关", + "text": "第5步,打开辅助控制盒互救开关。打开辅助控制盒盖,再打开互救开关,进入单泵作业状态。", + "video": "TASK-VIRTUAL-005-step-05-MOSS-Junhao.mp4", + "audio": "TASK-VIRTUAL-005-step-05-MOSS-Junhao.wav", + "duration": 9.96, + "videoSha256": "2663e8ec475e2b12eaa9daa4d5cce94fe6360d3ea7f14f3a6fef3ad36073c1ab" + } + ], + "publishedBindingsChanged": false +} \ No newline at end of file diff --git a/reports/bridge-005-moss-refined-20260920/README.md b/reports/bridge-005-moss-refined-20260920/README.md new file mode 100644 index 0000000..8c11492 --- /dev/null +++ b/reports/bridge-005-moss-refined-20260920/README.md @@ -0,0 +1,13 @@ + + +### 2026-09-20 讲解连贯性与口型复核 + +005 第一步旧 MOSS 原始 WAV 在 -38dB 阈值下存在约 1.69s、2.77s 长静音。成片音轨与源 WAV 的估计整体偏移约 29ms;尚无证据表明双播放时钟是主要原因。相同音频按 48kHz 与 16kHz 输入得到不同的 WASM blendshape 轨迹,录制时采样帧率约 25fps。生成入口现统一转换为此前验证样片使用的 16kHz、单声道、PCM16 WAV,播放和口型使用同一转换结果;重采样不改变音高和时长。 + +独立第一步样片改用连贯文稿,在 -48dB、至少 0.65s 的长静音内部缩短留白至 0.32s,非静音区间保留;处理规则尚未全局应用到 MOSS 或其他脚本。浏览器播放、解码和重采样单测通过,不代表逐字口型和发音已通过人工验收。未更改已发布任务视频。 + +样片:TASK-VIRTUAL-005-step-01-Junhao-refined.mp4;对比页 index.html。音频 5.582s,成片 5.76s,480×640。 + +ASR 辅助复核识别出完整操作句,存在“故障现象”同音字误识别;ASR 不能代替人工听感和口型评估。 + +额外 greedy 采样实验触发上游 codec 内存分配失败及降级,不采用;当前样片使用正常完成的 seed42 采样结果。 diff --git a/reports/bridge-005-moss-refined-20260920/TASK-VIRTUAL-005-step-01-Junhao-refined.mp4 b/reports/bridge-005-moss-refined-20260920/TASK-VIRTUAL-005-step-01-Junhao-refined.mp4 new file mode 100644 index 0000000..b2d558c Binary files /dev/null and b/reports/bridge-005-moss-refined-20260920/TASK-VIRTUAL-005-step-01-Junhao-refined.mp4 differ diff --git a/reports/bridge-005-moss-refined-20260920/TASK-VIRTUAL-005-step-01-Junhao-refined.wav b/reports/bridge-005-moss-refined-20260920/TASK-VIRTUAL-005-step-01-Junhao-refined.wav new file mode 100644 index 0000000..aeb3f53 Binary files /dev/null and b/reports/bridge-005-moss-refined-20260920/TASK-VIRTUAL-005-step-01-Junhao-refined.wav differ diff --git a/reports/bridge-005-moss-refined-20260920/index.html b/reports/bridge-005-moss-refined-20260920/index.html new file mode 100644 index 0000000..d059a5f --- /dev/null +++ b/reports/bridge-005-moss-refined-20260920/index.html @@ -0,0 +1 @@ +005第一步讲解修正版

005 · 第一步讲解复核

教员1 v2 · MOSS Junhao。修正版使用连贯句式、压缩长静音、统一16kHz口型输入。仍为独立试片,待人工确认口型和发音。

本次修正版

第一步,根据故障现象,确认是哪一个液压泵发生故障。

试听未处理的新语音

上次版本

\ No newline at end of file diff --git a/reports/bridge-005-moss-refined-20260920/natural-unedited.wav b/reports/bridge-005-moss-refined-20260920/natural-unedited.wav new file mode 100644 index 0000000..325d702 Binary files /dev/null and b/reports/bridge-005-moss-refined-20260920/natural-unedited.wav differ diff --git a/reports/bridge-005-moss-refined-20260920/preview.png b/reports/bridge-005-moss-refined-20260920/preview.png new file mode 100644 index 0000000..980bb2e Binary files /dev/null and b/reports/bridge-005-moss-refined-20260920/preview.png differ diff --git a/reports/bridge-005-moss-refined-20260920/previous.mp4 b/reports/bridge-005-moss-refined-20260920/previous.mp4 new file mode 100644 index 0000000..eefd2dd Binary files /dev/null and b/reports/bridge-005-moss-refined-20260920/previous.mp4 differ diff --git a/reports/bridge-005-moss-refined-20260920/result.json b/reports/bridge-005-moss-refined-20260920/result.json new file mode 100644 index 0000000..2141f1e --- /dev/null +++ b/reports/bridge-005-moss-refined-20260920/result.json @@ -0,0 +1,160 @@ +{ + "text": "第一步,根据故障现象,确认是哪一个液压泵发生故障。", + "voice": "MOSS Junhao", + "seed": 42, + "cuts": [ + { + "start": 0.581562, + "end": 1.949187, + "keptSeconds": 0.32 + }, + { + "start": 3.084229, + "end": 4.454417, + "keptSeconds": 0.32 + } + ], + "inputDuration": 7.68, + "preparedDuration": 5.5821875, + "lipInputRate": 16000, + "metadata": { + "streams": [ + { + "index": 0, + "codec_name": "h264", + "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", + "profile": "High", + "codec_type": "video", + "codec_tag_string": "avc1", + "codec_tag": "0x31637661", + "width": 480, + "height": 640, + "coded_width": 480, + "coded_height": 640, + "closed_captions": 0, + "film_grain": 0, + "has_b_frames": 2, + "sample_aspect_ratio": "1:1", + "display_aspect_ratio": "3:4", + "pix_fmt": "yuv420p", + "level": 30, + "color_range": "tv", + "color_space": "bt470bg", + "chroma_location": "left", + "field_order": "progressive", + "refs": 1, + "is_avc": "true", + "nal_length_size": "4", + "id": "0x1", + "r_frame_rate": "25/1", + "avg_frame_rate": "25/1", + "time_base": "1/12800", + "start_pts": 0, + "start_time": "0.000000", + "duration_ts": 73728, + "duration": "5.760000", + "bit_rate": "336540", + "bits_per_raw_sample": "8", + "nb_frames": "144", + "extradata_size": 49, + "disposition": { + "default": 1, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0, + "non_diegetic": 0, + "captions": 0, + "descriptions": 0, + "metadata": 0, + "dependent": 0, + "still_image": 0 + }, + "tags": { + "language": "eng", + "handler_name": "VideoHandler", + "vendor_id": "[0][0][0][0]", + "encoder": "Lavc61.3.100 libx264" + } + }, + { + "index": 1, + "codec_name": "aac", + "codec_long_name": "AAC (Advanced Audio Coding)", + "profile": "LC", + "codec_type": "audio", + "codec_tag_string": "mp4a", + "codec_tag": "0x6134706d", + "sample_fmt": "fltp", + "sample_rate": "48000", + "channels": 2, + "channel_layout": "stereo", + "bits_per_sample": 0, + "initial_padding": 0, + "id": "0x2", + "r_frame_rate": "0/0", + "avg_frame_rate": "0/0", + "time_base": "1/48000", + "start_pts": 1008, + "start_time": "0.021000", + "duration_ts": 268888, + "duration": "5.601833", + "bit_rate": "128656", + "nb_frames": "263", + "extradata_size": 5, + "disposition": { + "default": 1, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0, + "non_diegetic": 0, + "captions": 0, + "descriptions": 0, + "metadata": 0, + "dependent": 0, + "still_image": 0 + }, + "tags": { + "language": "eng", + "handler_name": "SoundHandler", + "vendor_id": "[0][0][0][0]" + } + } + ], + "format": { + "filename": "E:\\work\\edit_3d\\unreal_tran\\ute2e\\reports\\bridge-005-moss-refined-20260920\\TASK-VIRTUAL-005-step-01-Junhao-refined.mp4", + "nb_streams": 2, + "nb_programs": 0, + "nb_stream_groups": 0, + "format_name": "mov,mp4,m4a,3gp,3g2,mj2", + "format_long_name": "QuickTime / MOV", + "start_time": "0.000000", + "duration": "5.760000", + "size": "339220", + "bit_rate": "471138", + "probe_score": 100, + "tags": { + "major_brand": "isom", + "minor_version": "512", + "compatible_brands": "isomiso2avc1mp41", + "encoder": "Lavf61.1.100" + } + } + }, + "publishedBindingsChanged": false +} \ No newline at end of file diff --git a/tools/bridge-005-moss-preview-check.cjs b/tools/bridge-005-moss-preview-check.cjs new file mode 100644 index 0000000..8e1e0e6 --- /dev/null +++ b/tools/bridge-005-moss-preview-check.cjs @@ -0,0 +1,26 @@ +const fs = require('node:fs'); +const path = require('node:path'); +const { pathToFileURL } = require('node:url'); +const { chromium } = require('@playwright/test'); +(async()=>{ + const dir=path.resolve(__dirname,'../reports/bridge-005-moss-junhao-v2-20260919'); + const browser=await chromium.launch({headless:true,channel:'chrome'}); + try { + const page=await browser.newPage({viewport:{width:1280,height:1000}}); + await page.goto(pathToFileURL(path.join(dir,'index.html')).href); + if(await page.locator('video').count()!==10) throw new Error('Expected five pairs of videos'); + const results=[]; + for(let step=0;step<5;step++){ + const video=page.locator('video').nth(step*2); + await video.scrollIntoViewIfNeeded(); + await video.evaluate(v=>v.play()); + await page.waitForFunction(index=>{const v=document.querySelectorAll('video')[index];return v.currentTime>.15&&!v.paused&&!v.error},step*2); + results.push(await video.evaluate(v=>({width:v.videoWidth,height:v.videoHeight,duration:v.duration,playing:!v.paused,error:v.error?.code||null}))); + await video.evaluate(v=>v.pause()); + } + await page.evaluate(()=>scrollTo(0,0)); + await page.screenshot({path:path.join(dir,'preview-page.png')}); + fs.writeFileSync(path.join(dir,'playback-validation.json'),JSON.stringify(results,null,2)); + console.log('PASS: five new videos played, five original comparisons present',results); + } finally {await browser.close()} +})().catch(e=>{console.error(e.message);process.exitCode=1}); diff --git a/tools/bridge-005-moss-preview.py b/tools/bridge-005-moss-preview.py new file mode 100644 index 0000000..6dbd9e2 --- /dev/null +++ b/tools/bridge-005-moss-preview.py @@ -0,0 +1,127 @@ +"""Generate an isolated five-step preview using the workshop's avatar and Junhao.""" +from pathlib import Path +import hashlib +import html +import json +import shutil +import subprocess +import sys +import threading +import time +import argparse + +import httpx +from sqlalchemy import select + +ROOT = Path(__file__).resolve().parents[3] +sys.path.insert(0, str(ROOT / 'ai_person/ai_person_api')) +from app.config import get_settings +from app.persistence.database import get_session_factory +from app.persistence.agent_models import Agent, AgentAvatar, AgentVoice +from app.persistence.asset_models import Avatar, CapabilityAsset +from app.schemas.open_platform import GenerationCommand +from app.services.moss_tts_service import MossTtsService +from app.services.open_generation_worker import OpenGenerationWorker + +REPORT = ROOT / 'unreal_tran/ute2e/reports/bridge-005-moss-junhao-v2-20260919' +WEB = ROOT / 'unreal_tran/unreal_tran_web' + + +def read_manifest(name): + source = (WEB / 'src/features/virtual-training-scripts' / name).read_text('utf-8') + return json.loads(source.split('export default', 1)[1].strip().rstrip(';')) + + +def digest(path): + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def main(): + REPORT.mkdir(parents=True, exist_ok=True) + settings = get_settings() + parser = argparse.ArgumentParser() + parser.add_argument('--service-url', required=True, help='Renderer with the validated v2 avatar') + args = parser.parse_args() + settings = settings.model_copy(update={'service_base_url': args.service_url}) + with httpx.Client(trust_env=False, timeout=30) as client: + widget = client.get('http://127.0.0.1:6180/api/auth/v1/system-config/public').json()['data']['digitalHumanWidget'] + with get_session_factory()() as db: + agent = db.scalar(select(Agent).where(Agent.slug == widget['agentSlug'], Agent.is_delete == 0)) + relation = db.scalar(select(AgentAvatar).where(AgentAvatar.agent_id == agent.id).order_by(AgentAvatar.is_default.desc(), AgentAvatar.sort_order)) + avatar = db.get(Avatar, relation.avatar_id) + voice = db.scalar(select(CapabilityAsset).where(CapabilityAsset.asset_code == 'builtin-voice-moss-junhao')) + assert db.scalar(select(AgentVoice).where(AgentVoice.agent_id == agent.id, AgentVoice.capability_id == voice.id)), 'Junhao is not selected in the linked agent' + avatar_id, voice_id = str(avatar.id), str(voice.id) + provider_avatar = avatar.provider_avatar_id + profile = {'agent': agent.agent_name, 'slug': agent.slug, 'avatar': avatar.avatar_name, + 'providerAvatarId': provider_avatar, 'voice': voice.asset_name, 'engine': 'MOSS-TTS-Nano', + 'speed': float(agent.voice_speed), 'width': 480, 'height': 640} + manifest = client.get(str(settings.service_base_url).rstrip('/')+f'/api/v1/avatars/{provider_avatar}/assets/manifest.json') + manifest.raise_for_status() + profile['avatarManifestSha256'] = hashlib.sha256(manifest.content).hexdigest() + expected = json.loads((ROOT / 'ai_person/ai_person_service/builtin_avatars/instructors-v2.json').read_text('utf-8'))['instructors'][0] + assert profile['avatarManifestSha256'] == expected['bundle_sha256']['manifest.json'], 'Renderer does not have the approved v2 avatar' + pack = next(p for p in read_manifest('narration-manifest.js')['scripts'] if p['code'] == 'TASK-VIRTUAL-005') + old_pack = next(p for p in read_manifest('narration-video-manifest.js')['scripts'] if p['code'] == 'TASK-VIRTUAL-005') + renderer = OpenGenerationWorker(None, settings, None, None) + engine = MossTtsService(settings) + rows = [] + try: + for step in pack['steps']: + number = step['number'] + stem = f'TASK-VIRTUAL-005-step-{number:02}-MOSS-Junhao' + audio, video = REPORT / f'{stem}.wav', REPORT / f'{stem}.mp4' + capture = REPORT / f'{stem}.webm' + if video.exists(): + raise RuntimeError('Output exists; use a new report folder to preserve comparisons') + print(f'Step {number}: synthesizing Junhao', flush=True) + previous_audio = REPORT.parent / 'bridge-005-moss-junhao-20260919' / audio.name + if previous_audio.exists(): + import wave + shutil.copyfile(previous_audio, audio) + with wave.open(str(audio)) as wav: + generated = {'duration': wav.getnframes() / wav.getframerate()} + else: + generated = engine.synthesize(step['text'], voice_code='Junhao', speed=profile['speed']) + source = engine.output_path(generated['id']) + shutil.copyfile(source, audio) + source.unlink() + print(f'Step {number}: rendering avatar, audio {generated["duration"]:.2f}s', flush=True) + command = GenerationCommand(title=f'005 第{number}步 MOSS Junhao', text=step['text'], + avatarId=avatar_id, voiceId=voice_id, speed=profile['speed'], width=480, height=640, subtitles=False) + renderer.capture(command, provider_avatar, audio, None, capture, threading.Event()) + subprocess.run([settings.ffmpeg_binary, '-hide_banner', '-loglevel', 'error', '-y', '-i', str(capture), + '-r', '25', '-c:v', 'libx264', '-preset', 'veryfast', '-crf', '20', '-pix_fmt', 'yuv420p', + '-c:a', 'aac', '-b:a', '128k', '-movflags', '+faststart', str(video)], check=True) + info = json.loads(subprocess.run([settings.ffprobe_binary, '-v', 'error', '-show_streams', '-show_format', + '-of', 'json', str(video)], capture_output=True, text=True, check=True).stdout) + v = next(s for s in info['streams'] if s['codec_type'] == 'video') + a = next(s for s in info['streams'] if s['codec_type'] == 'audio') + assert (v['width'], v['height'], v['codec_name']) == (480, 640, 'h264') + assert a['codec_name'] == 'aac' + assert abs(float(info['format']['duration']) - generated['duration']) < 0.7 + subprocess.run([settings.ffmpeg_binary, '-v', 'error', '-i', str(video), '-f', 'null', '-'], check=True) + previous = next(s for s in old_pack['steps'] if s['number'] == number) + old = WEB / 'public' / previous['url'].lstrip('/') + if old.is_file(): shutil.copyfile(old, REPORT / f'original-step-{number:02}.mp4') + row = {'number': number, 'title': step['expectedTitle'], 'text': step['text'], 'video': video.name, + 'audio': audio.name, 'duration': float(info['format']['duration']), 'videoSha256': digest(video)} + rows.append(row) + (REPORT / 'result.json').write_text(json.dumps({'profile': profile, 'steps': rows, 'publishedBindingsChanged': False}, ensure_ascii=False, indent=2), 'utf-8') + print(f'Step {number}: complete ({row["duration"]:.2f}s)', flush=True) + finally: + engine.close() + cards = [] + for row in rows: + cards.append(f'''

第 {row['number']} 步 · {html.escape(row['title'])}

{html.escape(row['text'])}

+

新版 · MOSS Junhao

单独试听新语音

+

原版 · VITS

''') + page = '''005 · MOSS Junhao 讲解对比 + +

005 液压泵应急切换 · 新旧讲解对比

教员1 · v2素材 · MOSS-TTS-Nano / Junhao · 1.0倍速 · 3:4。五个步骤沿用原讲解文稿,当前为独立预览,线上讲解未替换。

''' + ''.join(cards) + '''''' + (REPORT / 'index.html').write_text(page, 'utf-8') + print('Preview ready: '+str(REPORT / 'index.html'), flush=True) + + +if __name__ == '__main__': + main() diff --git a/tools/bridge-005-refined-sample.py b/tools/bridge-005-refined-sample.py new file mode 100644 index 0000000..6388630 --- /dev/null +++ b/tools/bridge-005-refined-sample.py @@ -0,0 +1,50 @@ +from pathlib import Path +import sys,json,subprocess,re,threading,hashlib,shutil +import numpy as np +import soundfile as sf +import httpx + +ROOT=Path(__file__).resolve().parents[3] +sys.path.insert(0,str(ROOT/'ai_person/ai_person_api')) +from app.config import get_settings +from app.schemas.open_platform import GenerationCommand +from app.services.open_generation_worker import OpenGenerationWorker + +out=ROOT/'unreal_tran/ute2e/reports/bridge-005-moss-refined-20260920' +out.mkdir(parents=True,exist_ok=True) +source=ROOT/'ai_person/outputs/moss-integration-check/step1-refined/natural-42.wav' +audio,sr=sf.read(source) +detect=subprocess.run(['ffmpeg','-hide_banner','-i',str(source),'-af','silencedetect=noise=-48dB:d=0.65','-f','null','-'],capture_output=True,text=True,check=True) +starts=re.findall(r'silence_start: ([0-9.]+)',detect.stderr) +ends=re.findall(r'silence_end: ([0-9.]+)',detect.stderr) +pieces=[];last=0;cuts=[] +for start,end in zip(starts,ends): + start,end=float(start),float(end) + a,b=round((start+.16)*sr),round((end-.16)*sr) + if b<=a:continue + pieces.append(audio[last:a]);last=b;cuts.append({'start':start,'end':end,'keptSeconds':.32}) +pieces.append(audio[last:]) +prepared=np.concatenate(pieces) +wav=out/'TASK-VIRTUAL-005-step-01-Junhao-refined.wav' +sf.write(wav,prepared,sr,subtype='PCM_16') +shutil.copyfile(source,out/'natural-unedited.wav') +settings=get_settings().model_copy(update={'service_base_url':'http://1.14.103.234:8123'}) +avatar='a1000000000000000000000000000005' +with httpx.Client(trust_env=False,timeout=30) as client: + response=client.get(str(settings.service_base_url)+f'/api/v1/avatars/{avatar}/assets/manifest.json');response.raise_for_status() + expected=json.loads((ROOT/'ai_person/ai_person_service/builtin_avatars/instructors-v2.json').read_text('utf-8'))['instructors'][0]['bundle_sha256']['manifest.json'] + assert hashlib.sha256(response.content).hexdigest()==expected +text='第一步,根据故障现象,确认是哪一个液压泵发生故障。' +command=GenerationCommand(title='005 第一步 Junhao 连贯性修正版',text=text,avatarId='55',voiceId='49',speed=1,width=480,height=640,subtitles=False) +worker=OpenGenerationWorker(None,settings,None,None) +capture=out/'capture.webm';video=out/'TASK-VIRTUAL-005-step-01-Junhao-refined.mp4' +print('pause cleanup:',cuts,'duration:',len(prepared)/sr,flush=True) +worker.capture(command,avatar,wav,None,capture,threading.Event()) +subprocess.run(['ffmpeg','-v','error','-y','-i',str(capture),'-r','25','-c:v','libx264','-crf','20','-preset','veryfast','-pix_fmt','yuv420p','-c:a','aac','-b:a','128k','-movflags','+faststart',str(video)],check=True) +subprocess.run(['ffmpeg','-v','error','-i',str(video),'-f','null','-'],check=True) +probe=json.loads(subprocess.run(['ffprobe','-v','error','-show_streams','-show_format','-of','json',str(video)],capture_output=True,text=True,check=True).stdout) +assert abs(float(probe['format']['duration'])-len(prepared)/sr)<.7 +shutil.copyfile(out.parent/'bridge-005-moss-junhao-v2-20260919/TASK-VIRTUAL-005-step-01-MOSS-Junhao.mp4',out/'previous.mp4') +(out/'result.json').write_text(json.dumps({'text':text,'voice':'MOSS Junhao','seed':42,'cuts':cuts,'inputDuration':len(audio)/sr,'preparedDuration':len(prepared)/sr,'lipInputRate':16000,'metadata':probe,'publishedBindingsChanged':False},ensure_ascii=False,indent=2),'utf-8') +(out/'index.html').write_text('''005第一步讲解修正版

005 · 第一步讲解复核

教员1 v2 · MOSS Junhao。修正版使用连贯句式、压缩长静音、统一16kHz口型输入。仍为独立试片,待人工确认口型和发音。

本次修正版

第一步,根据故障现象,确认是哪一个液压泵发生故障。

试听未处理的新语音

上次版本

''','utf-8') +print('completed',video,flush=True)