diff --git a/dataset/audio/converter.py b/dataset/audio/converter.py new file mode 100644 index 0000000000000000000000000000000000000000..fbf9fe1562fa509686073eee912f8cf2752b987a --- /dev/null +++ b/dataset/audio/converter.py @@ -0,0 +1,31 @@ +import subprocess +import imageio_ffmpeg + +input_file = "test1.m4a" +output_file = "test1.wav" +ffmpeg_path = imageio_ffmpeg.get_ffmpeg_exe() + +cmd = [ + ffmpeg_path, + "-y", # 覆盖输出文件 + "-i", input_file, # 输入文件 + "-ar", "16000", # 采样率 + "-ac", "1", # 单声道 + output_file +] + +print(f"🎬 正在转换: {input_file} -> {output_file}") +res = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + +# 输出 stderr 日志(FFmpeg 输出信息都在 stderr) +stderr = res.stderr.decode() +print("------ FFmpeg stderr ------") +print(stderr) +print("----------------------------") + +# 检查是否生成成功 +import os +if os.path.exists(output_file): + print(f"✅ 成功生成 {output_file}") +else: + print("❌ 转换失败,请检查上面的错误信息") diff --git a/dataset/audio/segments/test1_segment_1.wav b/dataset/audio/segments/test1_segment_1.wav new file mode 100644 index 0000000000000000000000000000000000000000..4941a1051934bd98ebea963b5d09cab8c713e968 --- /dev/null +++ b/dataset/audio/segments/test1_segment_1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:877aee33d778b34af2f0b819ac822d80316e97b73cb3823c1f436dbef8efcb0e +size 35564 diff --git a/dataset/audio/segments/test1_segment_10.wav b/dataset/audio/segments/test1_segment_10.wav new file mode 100644 index 0000000000000000000000000000000000000000..1c7c57a43aad68f20052b27ae0073452cdf003b8 --- /dev/null +++ b/dataset/audio/segments/test1_segment_10.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3135d983a5260d846e6cf165583efa3a0ef379bd86c885e678a63b41f66f548b +size 48044 diff --git a/dataset/audio/segments/test1_segment_11.wav b/dataset/audio/segments/test1_segment_11.wav new file mode 100644 index 0000000000000000000000000000000000000000..4c56dcd9c723e1dcf82832cde17b5a30e011bdc9 --- /dev/null +++ b/dataset/audio/segments/test1_segment_11.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9a966cbb2e82ebd278692adad509a18061306b73b715fc4a93468c27ed61627b +size 111404 diff --git a/dataset/audio/segments/test1_segment_12.wav b/dataset/audio/segments/test1_segment_12.wav new file mode 100644 index 0000000000000000000000000000000000000000..b46e8924e0bef2e56eb41c55ff66d869ee0ae15e --- /dev/null +++ b/dataset/audio/segments/test1_segment_12.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52cfbcdc17cc5f190df467310f1a91c89e27f79662b2ce13f4ff5ec07015afec +size 71084 diff --git a/dataset/audio/segments/test1_segment_2.wav b/dataset/audio/segments/test1_segment_2.wav new file mode 100644 index 0000000000000000000000000000000000000000..c66190a32c1a88109969ffb7347f36ff335e1b6f --- /dev/null +++ b/dataset/audio/segments/test1_segment_2.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81375721eb3a532941083c9781f53f5e0f1ccbe1ef4108f98a019de400f5c564 +size 117164 diff --git a/dataset/audio/segments/test1_segment_3.wav b/dataset/audio/segments/test1_segment_3.wav new file mode 100644 index 0000000000000000000000000000000000000000..842df518ad536636ade95bde9b089b912c75fb8f --- /dev/null +++ b/dataset/audio/segments/test1_segment_3.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd6120ff04e7365640b9e3a1fb062bc1c31ce0dc54904bd27e25ac5a0b068cde +size 149804 diff --git a/dataset/audio/segments/test1_segment_4.wav b/dataset/audio/segments/test1_segment_4.wav new file mode 100644 index 0000000000000000000000000000000000000000..b78f03680c642701d463b55c1be08eac0d67911e --- /dev/null +++ b/dataset/audio/segments/test1_segment_4.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99bc0d18ffd0d10742b8d6b5450e537eccd1497c2247e714fa8efe6beb602abd +size 41324 diff --git a/dataset/audio/segments/test1_segment_5.wav b/dataset/audio/segments/test1_segment_5.wav new file mode 100644 index 0000000000000000000000000000000000000000..1cdc367099ef147aa75598a35afa1db84bb9c091 --- /dev/null +++ b/dataset/audio/segments/test1_segment_5.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a9e2196db3537028898b87442f074523251b33219302e6eb8518fb33396c30bd +size 122924 diff --git a/dataset/audio/segments/test1_segment_6.wav b/dataset/audio/segments/test1_segment_6.wav new file mode 100644 index 0000000000000000000000000000000000000000..8d4cd3c5dd8faebd38687f2501ec57aeeafcce1d --- /dev/null +++ b/dataset/audio/segments/test1_segment_6.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e929f7966a425a559b7442a2914cb99b0df74f1d02938264642dc71f160fc383 +size 113324 diff --git a/dataset/audio/segments/test1_segment_7.wav b/dataset/audio/segments/test1_segment_7.wav new file mode 100644 index 0000000000000000000000000000000000000000..8fdcea3f9b4c2b4c297d026595aeafd398716997 --- /dev/null +++ b/dataset/audio/segments/test1_segment_7.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65d800356647c415d80e59fac63db01df31ce51a497aacf43f98aa0e6ec468cb +size 77804 diff --git a/dataset/audio/segments/test1_segment_8.wav b/dataset/audio/segments/test1_segment_8.wav new file mode 100644 index 0000000000000000000000000000000000000000..0a5fdbd182a54211a10114b8b4034e75dadbcc36 --- /dev/null +++ b/dataset/audio/segments/test1_segment_8.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1c574a7c20332f85c6260febf6eae232473a798404ca29f1b54ac39e5b2d35c +size 91244 diff --git a/dataset/audio/segments/test1_segment_9.wav b/dataset/audio/segments/test1_segment_9.wav new file mode 100644 index 0000000000000000000000000000000000000000..ccd6d9c7beddf93c3986ae470876acdafd730b71 --- /dev/null +++ b/dataset/audio/segments/test1_segment_9.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f943b20eb3aafa0befb884f5d125e0596d3f419d8a3c5546ff3cf878603c36b8 +size 67244 diff --git a/dataset/audio/temp/test1_segments_20250423_133311.json b/dataset/audio/temp/test1_segments_20250423_133311.json new file mode 100644 index 0000000000000000000000000000000000000000..7f30f1d12f45217a42b355ad3c55afd4dfd65035 --- /dev/null +++ b/dataset/audio/temp/test1_segments_20250423_133311.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_133311", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/dataset/audio/temp/test1_segments_20250423_140123.json b/dataset/audio/temp/test1_segments_20250423_140123.json new file mode 100644 index 0000000000000000000000000000000000000000..2d5e3e2fc05c443388acfddd237c86e03624856e --- /dev/null +++ b/dataset/audio/temp/test1_segments_20250423_140123.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_140123", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/dataset/audio/temp/test1_segments_20250423_140325.json b/dataset/audio/temp/test1_segments_20250423_140325.json new file mode 100644 index 0000000000000000000000000000000000000000..30e78c3d8fe3df73c8d2e2923f78757c2b839aa4 --- /dev/null +++ b/dataset/audio/temp/test1_segments_20250423_140325.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_140325", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/dataset/audio/temp/test1_segments_20250423_140503.json b/dataset/audio/temp/test1_segments_20250423_140503.json new file mode 100644 index 0000000000000000000000000000000000000000..b9f1ce57d5c00b6a088111c0ed7266604f08db7b --- /dev/null +++ b/dataset/audio/temp/test1_segments_20250423_140503.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_140503", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/dataset/audio/temp/test1_segments_20250423_140556.json b/dataset/audio/temp/test1_segments_20250423_140556.json new file mode 100644 index 0000000000000000000000000000000000000000..ef1839b7cce409fcd9cd8c0be3975a1c28f82467 --- /dev/null +++ b/dataset/audio/temp/test1_segments_20250423_140556.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_140556", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/dataset/audio/test1.m4a b/dataset/audio/test1.m4a new file mode 100644 index 0000000000000000000000000000000000000000..2a0989bcb87a64e8d1803e92785d7703d5aed73e --- /dev/null +++ b/dataset/audio/test1.m4a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d6786ff56dc79183c1f66df16699fb97b3efdc9819184241772e70e89f36b875 +size 1389154 diff --git a/dataset/audio/test1.wav b/dataset/audio/test1.wav new file mode 100644 index 0000000000000000000000000000000000000000..62120a778e60cb63c7168c4f39a498d1f8772ff3 --- /dev/null +++ b/dataset/audio/test1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02f25859f79b85109154b534742128605c7ea34e1154f9d17d21c302a67b92b3 +size 1749070 diff --git a/dataset/transcripts/test1.json b/dataset/transcripts/test1.json new file mode 100644 index 0000000000000000000000000000000000000000..0a5212d8aad56486fbb69e8f85a5aab95ec3ca8e --- /dev/null +++ b/dataset/transcripts/test1.json @@ -0,0 +1,4 @@ +{ + "felo_transcript": "第一单元,音频数据处理。\n单元简介。\n所有音频或语音相关的任务都需要使用音频文件在我们深入了解这些任务之前我们需要了解音频文件的实际内容以及如何利用音频文件本单元将为你介绍的呃本单元将为你介绍与音频数据相关的基本概念包括波形采样率和频谱图你会学习到如何使用音频数据集包括音频数据加载音频数据预处理以及高效加载大规模音频数据集的\n完成本单元的学习后,你会掌握基础的音频相关术语,并且掌握针对不同应用的音频数据处理工具。\n本单元的知识会成为后面章节的基础。", + "transcript": "第1单元:音频数据处理\n单元简介\n所有音频或语音相关的任务都需要使用音频文件。在我们深入了解这些任务之前,我们需要了解音频文件的实际内容以及如何利用音频文件。\n本单元将为你介绍与音频数据相关的基本概念,包括波形、采样率和频谱图。你会学习到如何使用音频数据集,包括音频数据加载、音频数据预处理,以及高效加载大规模音频数据集的流式加载方法。\n完成本单元的学习后,你会掌握基础的音频相关术语,并且掌握针对不同应用的音频数据处理工具。本单元的知识会成为后面章节的基础" +} \ No newline at end of file diff --git a/dataset/transcripts/test1_segment_1_20250423_133335.json b/dataset/transcripts/test1_segment_1_20250423_133335.json new file mode 100644 index 0000000000000000000000000000000000000000..0f16a1f57c940d3903a3523690876ee198106d65 --- /dev/null +++ b/dataset/transcripts/test1_segment_1_20250423_133335.json @@ -0,0 +1,150 @@ +{ + "audio_file": "../dataset/audio/segments\\test1_segment_1.wav", + "timestamp": "20250423_133335", + "segments": [ + { + "text": "音频数据处理", + "start_time": 0.0, + "end_time": 1.16, + "confidence": 0.8830433189868927, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "所有音频或语言相关的任务都需要使用音频", + "start_time": 0.0, + "end_time": 3.72, + "confidence": 0.7980242520570755, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "在我们先辱了解这些任务之前", + "start_time": 0.0, + "end_time": 1.6400000000000001, + "confidence": 0.9636461660265923, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "我们需要了解音频文件的实际内容", + "start_time": 1.6400000000000001, + "end_time": 4.0, + "confidence": 0.9636461660265923, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "以及如何", + "start_time": 4.0, + "end_time": 4.8, + "confidence": 0.9636461660265923, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本来员将会你介绍的", + "start_time": 0.0, + "end_time": 1.28, + "confidence": 0.8996343165636063, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本单元将为你介绍于音频数据相关的基本概念", + "start_time": 0.0, + "end_time": 3.92, + "confidence": 0.6721383035182953, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "包括剝形、採揚、綠和平、布圖", + "start_time": 0.0, + "end_time": 2.0, + "confidence": 0.7332137525081635, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "你會學習到如何使用音頻", + "start_time": 2.0, + "end_time": 3.6, + "confidence": 0.7332137525081635, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "包括音频数位加载", + "start_time": 0.0, + "end_time": 1.4000000000000001, + "confidence": 0.8692675232887268, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "音频数据处理", + "start_time": 1.4000000000000001, + "end_time": 2.4, + "confidence": 0.8692675232887268, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "高效加载大规模音频数一级的流适加载方", + "start_time": 0.0, + "end_time": 2.88, + "confidence": 0.9492924958467484, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "完成本單元的學習後,你會找", + "start_time": 0.0, + "end_time": 2.0, + "confidence": 0.9920552605763078, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "基础的音频相关数", + "start_time": 0.0, + "end_time": 1.6, + "confidence": 0.8243299126625061, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "并且掌握针对不同应用的音频数据处理工具", + "start_time": 0.0, + "end_time": 3.52, + "confidence": 0.9778542779386044, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本单元的支持会成为后面章节的", + "start_time": 0.0, + "end_time": 2.0, + "confidence": 0.920660175383091, + "verified": false, + "verified_text": null, + "verification_notes": null + } + ] +} \ No newline at end of file diff --git a/dataset/transcripts/test1_segment_1_20250423_140126.json b/dataset/transcripts/test1_segment_1_20250423_140126.json new file mode 100644 index 0000000000000000000000000000000000000000..d8e9c9de610c08823a9da541fb4e0e9b2280bdbc --- /dev/null +++ b/dataset/transcripts/test1_segment_1_20250423_140126.json @@ -0,0 +1,159 @@ +{ + "audio_file": "../dataset/audio/segments\\test1_segment_1.wav", + "timestamp": "20250423_140126", + "segments": [ + { + "text": "音频数据处理", + "start_time": 0.0, + "end_time": 1.16, + "confidence": 0.906494140625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "所有音频或语言相关的任务都需要使用音频", + "start_time": 0.0, + "end_time": 3.72, + "confidence": 0.7564697265625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "在我们先入了解这些任务之前", + "start_time": 0.0, + "end_time": 1.6400000000000001, + "confidence": 0.939605712890625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "我们需要了解音频文件的实际内容", + "start_time": 1.6400000000000001, + "end_time": 4.0, + "confidence": 0.939605712890625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "以及如何", + "start_time": 4.0, + "end_time": 4.8, + "confidence": 0.939605712890625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本台語言將為你介紹的", + "start_time": 0.0, + "end_time": 1.28, + "confidence": 0.907470703125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本单元将为你介绍于音频数据相关的基本概念", + "start_time": 0.0, + "end_time": 3.92, + "confidence": 0.66796875, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "包括剝形、採用、綠和平補土", + "start_time": 0.0, + "end_time": 2.0, + "confidence": 0.708251953125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "你會學習到如何使用音頻", + "start_time": 2.0, + "end_time": 3.6, + "confidence": 0.708251953125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "包括音频数位加载", + "start_time": 0.0, + "end_time": 1.4000000000000001, + "confidence": 0.86474609375, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "音频数据处理", + "start_time": 1.4000000000000001, + "end_time": 2.4, + "confidence": 0.86474609375, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "高效加载大规模音频数级的流适加载方", + "start_time": 0.0, + "end_time": 2.88, + "confidence": 0.956787109375, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "完成本單元的學期後", + "start_time": 0.0, + "end_time": 1.44, + "confidence": 0.9926719665527344, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "你會找", + "start_time": 1.44, + "end_time": 2.12, + "confidence": 0.9926719665527344, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "基础的音频相关数", + "start_time": 0.0, + "end_time": 1.6, + "confidence": 0.7969970703125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "并且掌握针对不同应用的音频数据处理工具", + "start_time": 0.0, + "end_time": 3.52, + "confidence": 0.9851303100585938, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本单元的支持会成为后面章节的", + "start_time": 0.0, + "end_time": 2.0, + "confidence": 0.930908203125, + "verified": false, + "verified_text": null, + "verification_notes": null + } + ] +} \ No newline at end of file diff --git a/dataset/transcripts/test1_segment_1_20250423_140600.json b/dataset/transcripts/test1_segment_1_20250423_140600.json new file mode 100644 index 0000000000000000000000000000000000000000..1924d8daa7e5f6c1a04437c94bee8da72dfd8c4f --- /dev/null +++ b/dataset/transcripts/test1_segment_1_20250423_140600.json @@ -0,0 +1,159 @@ +{ + "audio_file": "../dataset/audio/segments\\test1_segment_1.wav", + "timestamp": "20250423_140600", + "segments": [ + { + "text": "音频数据处理", + "start_time": 4.56, + "end_time": 5.72, + "confidence": 0.906494140625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "所有音频或语言相关的任务都需要使用音频", + "start_time": 8.4, + "end_time": 12.120000000000001, + "confidence": 0.7564697265625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "在我们先入了解这些任务之前", + "start_time": 13.11, + "end_time": 14.75, + "confidence": 0.939605712890625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "我们需要了解音频文件的实际内容", + "start_time": 14.75, + "end_time": 17.11, + "confidence": 0.939605712890625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "以及如何", + "start_time": 17.11, + "end_time": 17.91, + "confidence": 0.939605712890625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本台語言將為你介紹的", + "start_time": 19.77, + "end_time": 21.05, + "confidence": 0.907470703125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本单元将为你介绍于音频数据相关的基本概念", + "start_time": 21.63, + "end_time": 25.549999999999997, + "confidence": 0.66796875, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "包括剝形、採用、綠和平補土", + "start_time": 26.28, + "end_time": 28.28, + "confidence": 0.708251953125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "你會學習到如何使用音頻", + "start_time": 28.28, + "end_time": 29.880000000000003, + "confidence": 0.708251953125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "包括音频数位加载", + "start_time": 30.42, + "end_time": 31.860000000000003, + "confidence": 0.86474609375, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "音频数据处理", + "start_time": 31.860000000000003, + "end_time": 32.86, + "confidence": 0.86474609375, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "高效加载大规模音频数级的流适加载方", + "start_time": 33.54, + "end_time": 36.42, + "confidence": 0.956787109375, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "完成本单元的学期后", + "start_time": 37.8, + "end_time": 39.199999999999996, + "confidence": 0.9926719665527344, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "你会找", + "start_time": 39.199999999999996, + "end_time": 40.0, + "confidence": 0.9926719665527344, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "基础的音频相关数", + "start_time": 40.86, + "end_time": 42.46, + "confidence": 0.7969970703125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "并且掌握针对不同应用的音频数据处理工具", + "start_time": 43.05, + "end_time": 46.57, + "confidence": 0.9851303100585938, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本单元的支持会成为后面章节的", + "start_time": 47.49, + "end_time": 49.49, + "confidence": 0.930908203125, + "verified": false, + "verified_text": null, + "verification_notes": null + } + ] +} \ No newline at end of file diff --git a/vad/README.md b/vad/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4212e29242d428d6585b33362f6474255509c0fa --- /dev/null +++ b/vad/README.md @@ -0,0 +1,152 @@ +# 音频数据集处理工具 + +本工具用于处理音频数据集,支持音频切割、转录和人工验证功能。 + +## 功能特性 + +### 1. 音频处理和切割 +- 基于振幅和VAD(Voice Activity Detection)的音频切割 +- 自动过滤无效的短音频片段 +- 保存切割后的音频片段到指定目录 + +### 2. 音频转录 +- 使用faster-whisper模型进行音频转录 +- 支持批量处理音频片段 +- 保存带时间戳的转录文本 + +### 3. 人工验证界面 +- 交互式验证转录结果 +- 支持修改转录文本 +- 添加验证注释 +- 保存验证状态 + +## 项目结构 + +``` +faster-whisper-small/ +├── vad/ # VAD音频处理工具目录 +│ ├── audio_processor.py # 音频处理核心代码 +│ ├── audio_transcriber.py# 音频转录核心代码 +│ ├── main.py # 命令行入口 +│ └── README.md # 使用说明文档 +├── dataset/ # 数据集目录 +│ ├── audio/ # 存放原始音频文件 +│ │ └── segments/ # 存放切割后的音频片段 +│ └── transcripts/ # 存放转录和验证结果 +├── ct2_model/ # faster-whisper模型文件 +└── whisper_processor/ # whisper处理器文件 +``` + +## 使用方法 + +### 1. 安装依赖 + +```bash +pip install -r requirements.txt +``` + +### 2. 处理新的音频文件 + +```bash +# 在项目根目录下运行 +python vad/main.py process dataset/audio/test1.wav +``` + +这个命令会: +1. 将音频切割成多个片段 +2. 对每个片段进行转录 +3. 提供交互式界面进行验证 +4. 保存结果到JSON文件 + +### 3. 验证已有的转录结果 + +```bash +# 在项目根目录下运行 +python vad/main.py verify dataset/transcripts/your_transcript.json +``` + +## 参数调整 + +可以通过修改 `vad/audio_processor.py` 中的参数来优化切割效果: + +```python +processor = AudioProcessor( + vad_level=2, # VAD灵敏度 (0-3) + min_silence_duration=0.5, # 最小静音持续时间(秒) + min_speech_duration=0.3, # 最小语音片段长度(秒) + amplitude_threshold=0.01 # 振幅阈值 +) +``` + +## 输出文件格式 + +### 1. 音频片段 +切割后的音频片段保存为WAV格式,采样率为16kHz,命名格式为: +``` +{原文件名}_segment_{序号}.wav +``` + +### 2. 转录结果 +转录结果保存为JSON格式,包含以下信息: +```json +{ + "audio_file": "dataset/audio/meeting_001.wav", + "timestamp": "20250422_182233", + "segments": [ + { + "text": "今天的会议主要讨论两个议题。", + "start_time": 0.0, + "end_time": 2.5, + "confidence": 0.92, + "verified": true, + "verified_text": null, + "verification_notes": "转录正确" + }, + { + "text": "第一个是项目进度报告。", + "start_time": 2.8, + "end_time": 4.6, + "confidence": 0.88, + "verified": true, + "verified_text": "第一个是项目进度汇报", + "verification_notes": "纠正:'报告'改为'汇报'" + }, + { + "text": "第二个是下个月的工作计划", + "start_time": 5.0, + "end_time": 7.2, + "confidence": 0.95, + "verified": false, + "verified_text": null, + "verification_notes": null + } + ] +} +``` + +这个示例展示了: +1. 已验证且正确的片段(第一个) +2. 已验证且需要修正的片段(第二个) +3. 未验证的片段(第三个) + +使用以下命令验证此转录: +```bash +python vad/main.py verify dataset/transcripts/meeting_001_20250422_182233.json +``` + +## 注意事项 + +1. 音频文件要求: + - 支持常见音频格式(WAV, MP3, M4A等) + - 建议使用16kHz采样率 + - 如果是多声道音频会自动转换为单声道 + +2. 性能考虑: + - 转录速度取决于CPU性能和音频长度 + - 较长的音频文件会被自动切割成小片段处理 + +3. 后续优化方向: + - 优化切割策略 + - 添加批量处理功能 + - 改进语义重组算法 + - 添加GUI界面 diff --git a/vad/__init__.py b/vad/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..635721d98073586b04f0139f8da4e54ca12b4991 --- /dev/null +++ b/vad/__init__.py @@ -0,0 +1,10 @@ +""" +VAD音频处理工具包 + +提供音频切割、转录和验证功能。 +""" + +from .audio_processor import AudioProcessor, AudioSegment +from .audio_transcriber import AudioTranscriber, TranscriptionResult + +__all__ = ['AudioProcessor', 'AudioSegment', 'AudioTranscriber', 'TranscriptionResult'] diff --git a/vad/__pycache__/__init__.cpython-312.pyc b/vad/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..560c4e3078769974f0526df069925bd37e00113f Binary files /dev/null and b/vad/__pycache__/__init__.cpython-312.pyc differ diff --git a/vad/__pycache__/audio_processor.cpython-312.pyc b/vad/__pycache__/audio_processor.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8593498df4dba52762340bd31f230835885ed0ce Binary files /dev/null and b/vad/__pycache__/audio_processor.cpython-312.pyc differ diff --git a/vad/__pycache__/audio_transcriber.cpython-312.pyc b/vad/__pycache__/audio_transcriber.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..394314e3711095b8dc4670071ef48a9ab1a32905 Binary files /dev/null and b/vad/__pycache__/audio_transcriber.cpython-312.pyc differ diff --git a/vad/__pycache__/main.cpython-312.pyc b/vad/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3add7ab317e9e77cc1fc19a36c7c8c7454f77894 Binary files /dev/null and b/vad/__pycache__/main.cpython-312.pyc differ diff --git a/vad/audio_processor.py b/vad/audio_processor.py new file mode 100644 index 0000000000000000000000000000000000000000..65a8c55174d3ae50aacc8adb542a73d1ce416b6c --- /dev/null +++ b/vad/audio_processor.py @@ -0,0 +1,212 @@ +import numpy as np +import soundfile as sf +from typing import List, Tuple, Optional, Dict +import webrtcvad +from dataclasses import dataclass, asdict +from scipy import signal +import json +import os +from datetime import datetime + +@dataclass +class AudioSegment: + start_time: float # 开始时间(秒) + end_time: float # 结束时间(秒) + audio_data: np.ndarray # 音频数据 + is_speech: bool # 是否包含语音 + +class AudioProcessor: + def __init__(self, + sample_rate: int = 16000, + frame_duration_ms: int = 30, + vad_level: int = 1, # 降低VAD灵敏度 + min_silence_duration: float = 0.5, # 静音持续时间 + min_speech_duration: float = 1.0, # 增加最小语音持续时间,确保完整句子 + amplitude_threshold: float = 0.003): # 进一步降低振幅阈值 + """ + 初始化音频处理器 + + Args: + sample_rate: 采样率 + frame_duration_ms: VAD帧长度(毫秒) + vad_level: VAD灵敏度 (0-3) + min_silence_duration: 最小静音持续时间(秒) + min_speech_duration: 最小语音片段长度(秒) + amplitude_threshold: 振幅阈值 + """ + self.sample_rate = sample_rate + self.frame_duration_ms = frame_duration_ms + self.frame_size = int(sample_rate * frame_duration_ms / 1000) + self.vad = webrtcvad.Vad(vad_level) + self.min_silence_frames = int(min_silence_duration * 1000 / frame_duration_ms) + self.min_speech_frames = int(min_speech_duration * 1000 / frame_duration_ms) + self.amplitude_threshold = amplitude_threshold + + def _is_speech_frame(self, frame: np.ndarray) -> bool: + """ + 判断一帧是否包含语音 + """ + # 确保帧长度正确 + if len(frame) != self.frame_size: + return False + + # 将float32转换为int16,并确保值在范围内 + frame_int16 = np.clip(frame * 32768, -32768, 32767).astype(np.int16) + + # 使用振幅判断 + frame_amplitude = np.max(np.abs(frame)) + if frame_amplitude < self.amplitude_threshold: + return False + + # 使用VAD判断 + try: + return self.vad.is_speech(frame_int16.tobytes(), self.sample_rate) + except Exception as e: + print(f"VAD处理出错: {e}") + # 如果VAD失败,仅使用振幅判断 + return frame_amplitude >= self.amplitude_threshold * 2 + + def process_audio_file(self, audio_path: str) -> List[AudioSegment]: + """ + 处理音频文件,返回切割后的片段列表 + """ + # 读取音频文件 + print(f"正在读取音频文件: {audio_path}") + audio_data, sample_rate = sf.read(audio_path) + print(f"音频采样率: {sample_rate}Hz, 形状: {audio_data.shape}") + + if sample_rate != self.sample_rate: + print(f"正在重采样音频从 {sample_rate}Hz 到 {self.sample_rate}Hz") + # 使用scipy的resample函数进行重采样 + num_samples = int(len(audio_data) * self.sample_rate / sample_rate) + audio_data = signal.resample(audio_data, num_samples) + print(f"重采样后音频长度: {len(audio_data)} 采样点") + + if len(audio_data.shape) > 1: + print("检测到多声道音频,正在转换为单声道") + audio_data = audio_data.mean(axis=1) # 转换为单声道 + + # 初始化结果列表 + segments: List[AudioSegment] = [] + print(f"开始处理音频,总长度: {len(audio_data)} 采样点 ({len(audio_data)/self.sample_rate:.2f}秒)") + + # 当前处理的状态 + current_segment_start = 0 + silence_frame_count = 0 + is_in_speech = False + + # 按帧处理音频 + total_frames = len(audio_data) // self.frame_size + speech_frames = 0 + for i in range(0, len(audio_data), self.frame_size): + # 确保帧长度正确 + frame = audio_data[i:i + self.frame_size] + if len(frame) < self.frame_size: + # 对于最后一个不完整帧,补零处理 + frame = np.pad(frame, (0, self.frame_size - len(frame)), 'constant') + + is_speech = self._is_speech_frame(frame) + if is_speech: + speech_frames += 1 + + if is_speech and not is_in_speech: + # 开始新的语音段 + current_segment_start = i + is_in_speech = True + silence_frame_count = 0 + print(f"\n检测到语音开始,位置: {i/self.sample_rate:.2f}秒") + elif not is_speech and is_in_speech: + silence_frame_count += 1 + + # 如果静音持续足够长,结束当前语音段 + if silence_frame_count >= self.min_silence_frames: + segment_end = i - (silence_frame_count * self.frame_size) + duration_frames = (segment_end - current_segment_start) // self.frame_size + + # 只保存超过最小长度的片段 + if duration_frames >= self.min_speech_frames: + start_time = current_segment_start / self.sample_rate + end_time = segment_end / self.sample_rate + print(f"保存语音片段: {start_time:.2f}s -> {end_time:.2f}s (持续时间: {end_time-start_time:.2f}s)") + segments.append(AudioSegment( + start_time=start_time, + end_time=end_time, + audio_data=audio_data[current_segment_start:segment_end], + is_speech=True + )) + else: + print(f"丢弃过短的语音片段: {duration_frames * self.frame_duration_ms / 1000:.2f}s") + + is_in_speech = False + + # 处理最后一个语音段 + if is_in_speech: + segment_end = len(audio_data) + duration_frames = (segment_end - current_segment_start) // self.frame_size + if duration_frames >= self.min_speech_frames: + start_time = current_segment_start / self.sample_rate + end_time = segment_end / self.sample_rate + print(f"保存最后的语音片段: {start_time:.2f}s -> {end_time:.2f}s (持续时间: {end_time-start_time:.2f}s)") + segments.append(AudioSegment( + start_time=start_time, + end_time=end_time, + audio_data=audio_data[current_segment_start:segment_end], + is_speech=True + )) + else: + print(f"丢弃过短的最后语音片段: {duration_frames * self.frame_duration_ms / 1000:.2f}s") + + print(f"\n音频处理完成:") + print(f"总帧数: {total_frames}") + print(f"语音帧数: {speech_frames}") + print(f"检测到的语音片段数: {len(segments)}") + + # 保存中间结果到临时文件 + temp_dir = "../dataset/audio/temp" + os.makedirs(temp_dir, exist_ok=True) + + # 准备保存的数据 + temp_data = { + "audio_file": audio_path, + "timestamp": datetime.now().strftime("%Y%m%d_%H%M%S"), + "total_frames": total_frames, + "speech_frames": speech_frames, + "segments": [ + { + "start_time": seg.start_time, + "end_time": seg.end_time, + "duration": seg.end_time - seg.start_time, + "is_speech": seg.is_speech + } + for seg in segments + ] + } + + # 保存临时结果 + base_name = os.path.splitext(os.path.basename(audio_path))[0] + temp_path = os.path.join(temp_dir, f"{base_name}_segments_{temp_data['timestamp']}.json") + with open(temp_path, 'w', encoding='utf-8') as f: + json.dump(temp_data, f, ensure_ascii=False, indent=2) + print(f"\n临时结果已保存到: {temp_path}") + + return segments + + def save_segment(self, segment: AudioSegment, output_path: str): + """ + 保存音频片段到文件 + """ + sf.write(output_path, segment.audio_data, self.sample_rate) + +if __name__ == "__main__": + # 测试代码 + processor = AudioProcessor() + + # 示例:处理一个音频文件 + audio_path = "dataset/audio/test.wav" # 替换为实际的音频文件路径 + try: + segments = processor.process_audio_file(audio_path) + print(f"检测到 {len(segments)} 个语音片段:") + for i, segment in enumerate(segments): + print(f"片段 {i+1}: {segment.start_time:.2f}s -> {segment.end_time:.2f}s") + except Exception as e: + print(f"处理音频时出错: {e}") diff --git a/vad/audio_transcriber.py b/vad/audio_transcriber.py new file mode 100644 index 0000000000000000000000000000000000000000..40dc9864e9b2faa59ad232c77d999c2cba2245a9 --- /dev/null +++ b/vad/audio_transcriber.py @@ -0,0 +1,163 @@ +from faster_whisper import WhisperModel +from audio_processor import AudioSegment +import json +from typing import List, Dict, Optional +from dataclasses import dataclass +import os +from datetime import datetime + +@dataclass +class TranscriptionResult: + text: str + start_time: float + end_time: float + confidence: float + verified: bool = False + verified_text: Optional[str] = None + verification_notes: Optional[str] = None + +class AudioTranscriber: + def __init__(self, model: str = "small", device: str = "cuda", compute_type: str = "int8"): + """ + 初始化转录器 + + Args: + model_path: Whisper模型路径 + device: 使用的设备 ("cpu" 或 "cuda") + compute_type: 计算类型 + """ + print("📥 Loading Whisper model...") + self.model = WhisperModel(model, device=device, compute_type=compute_type) + print("📥 Loading Whisper model successfully!!") + + def transcribe_segment(self, segment: AudioSegment) -> List[TranscriptionResult]: + """ + 转录单个音频片段 + """ + print("Model transcribe...") + print(f"开始转录音频片段,长度: {len(segment.audio_data)} 采样点 ({len(segment.audio_data)/16000:.2f}秒)") + segments_generator, info = self.model.transcribe(segment.audio_data, + beam_size=3, + language="zh") + print(f"检测到语言: {info.language}, 语言概率: {info.language_probability:.2f}") + segments = list(segments_generator) + print(f"Model transcribe successfully! Segments count: {len(segments)}") + if len(segments) > 0: + print(segments[0]) + results = [] + for seg in segments: + # 调整时间戳以匹配原始音频中的位置 + absolute_start = segment.start_time + seg.start + absolute_end = segment.start_time + seg.end + + result = TranscriptionResult( + text=seg.text, + start_time=absolute_start, + end_time=absolute_end, + confidence=1.0 - seg.no_speech_prob + ) + results.append(result) + + return results + + def save_transcription(self, + results: List[TranscriptionResult], + audio_path: str, + output_dir: str = "../dataset/transcripts"): + """ + 保存转录结果到JSON文件 + """ + # 生成输出文件名 + base_name = os.path.splitext(os.path.basename(audio_path))[0] + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + output_path = os.path.join(output_dir, f"{base_name}_{timestamp}.json") + + # 准备保存的数据 + data = { + "audio_file": audio_path, + "timestamp": timestamp, + "segments": [ + { + "text": r.text, + "start_time": r.start_time, + "end_time": r.end_time, + "confidence": r.confidence, + "verified": r.verified, + "verified_text": r.verified_text, + "verification_notes": r.verification_notes + } + for r in results + ] + } + + # 保存到文件 + os.makedirs(output_dir, exist_ok=True) + with open(output_path, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=2) + + return output_path + + def verify_transcription(self, + result: TranscriptionResult, + verified_text: Optional[str] = None, + verification_notes: Optional[str] = None) -> TranscriptionResult: + """ + 人工验证转录结果 + """ + result.verified = True + if verified_text is not None: + result.verified_text = verified_text + if verification_notes is not None: + result.verification_notes = verification_notes + return result + + def load_transcription(self, json_path: str) -> List[TranscriptionResult]: + """ + 从JSON文件加载转录结果 + """ + with open(json_path, 'r', encoding='utf-8') as f: + data = json.load(f) + + results = [] + for seg in data["segments"]: + result = TranscriptionResult( + text=seg["text"], + start_time=seg["start_time"], + end_time=seg["end_time"], + confidence=seg["confidence"], + verified=seg["verified"], + verified_text=seg.get("verified_text"), + verification_notes=seg.get("verification_notes") + ) + results.append(result) + + return results + +if __name__ == "__main__": + # 测试代码 + from audio_processor import AudioProcessor + + # 初始化处理器和转录器 + processor = AudioProcessor() + transcriber = AudioTranscriber() + + # 示例:处理和转录音频文件 + audio_path = "../dataset/audio/test.wav" # 替换为实际的音频文件路径 + try: + # 1. 切割音频 + segments = processor.process_audio_file(audio_path) + print(f"检测到 {len(segments)} 个语音片段") + + # 2. 转录每个片段 + all_results = [] + for i, segment in enumerate(segments): + print(f"转录片段 {i+1}/{len(segments)}...") + results = transcriber.transcribe_segment(segment) + all_results.extend(results) + + # 3. 保存结果 + output_path = transcriber.save_transcription(all_results, audio_path) + print(f"✅ 转录结果已保存到: {output_path}") + + except Exception as e: + print(f"处理音频时出错: {e}") diff --git a/vad/dataset/audio/segments/test1_segment_1.wav b/vad/dataset/audio/segments/test1_segment_1.wav new file mode 100644 index 0000000000000000000000000000000000000000..87a9bf736fc4d64303b407881d474c84cdf00887 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_1.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:877aee33d778b34af2f0b819ac822d80316e97b73cb3823c1f436dbef8efcb0e +size 35564 diff --git a/vad/dataset/audio/segments/test1_segment_10.wav b/vad/dataset/audio/segments/test1_segment_10.wav new file mode 100644 index 0000000000000000000000000000000000000000..7c999215b7e04a4c2365b89f6f656bb908818a9e --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_10.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3135d983a5260d846e6cf165583efa3a0ef379bd86c885e678a63b41f66f548b +size 48044 diff --git a/vad/dataset/audio/segments/test1_segment_11.wav b/vad/dataset/audio/segments/test1_segment_11.wav new file mode 100644 index 0000000000000000000000000000000000000000..b5281f8ea095be0a93b026e14162821ef0e01ced --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_11.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9a966cbb2e82ebd278692adad509a18061306b73b715fc4a93468c27ed61627b +size 111404 diff --git a/vad/dataset/audio/segments/test1_segment_12.wav b/vad/dataset/audio/segments/test1_segment_12.wav new file mode 100644 index 0000000000000000000000000000000000000000..baac9e5f5b3ae957dc3d3e81d6880a47ce149c39 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_12.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52cfbcdc17cc5f190df467310f1a91c89e27f79662b2ce13f4ff5ec07015afec +size 71084 diff --git a/vad/dataset/audio/segments/test1_segment_13.wav b/vad/dataset/audio/segments/test1_segment_13.wav new file mode 100644 index 0000000000000000000000000000000000000000..37a1f3971d541c50f0d13d7c3be1f0566400ed52 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_13.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8eedb04a2d817c0875003a7594f8bac255a28898dfae56aa97bd3021870140b2 +size 86444 diff --git a/vad/dataset/audio/segments/test1_segment_14.wav b/vad/dataset/audio/segments/test1_segment_14.wav new file mode 100644 index 0000000000000000000000000000000000000000..2fabe7c092d49c272fc30b533daeeb2adeaab68c --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_14.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:078850683b71e5b04781884b44bce0edb74999459b68b6fd53175ecacbd4980e +size 34604 diff --git a/vad/dataset/audio/segments/test1_segment_15.wav b/vad/dataset/audio/segments/test1_segment_15.wav new file mode 100644 index 0000000000000000000000000000000000000000..82b6e1b7e83bb2fbe6b735706671ee9f9dc2dbb9 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_15.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9c467e2ec3bdec346774cde0480a78689c0f6f13fd093b32baaa00187c392fb +size 29804 diff --git a/vad/dataset/audio/segments/test1_segment_16.wav b/vad/dataset/audio/segments/test1_segment_16.wav new file mode 100644 index 0000000000000000000000000000000000000000..2406e3ad9d251f298c23eede92f8582538986f4c --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_16.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:59bc62b5c124c9cac5ef78c69caff4e5caf3d0333e496e382ee365142eafc354 +size 47084 diff --git a/vad/dataset/audio/segments/test1_segment_17.wav b/vad/dataset/audio/segments/test1_segment_17.wav new file mode 100644 index 0000000000000000000000000000000000000000..1283a01879c2ab4fbcae75b014de0f35de872a8d --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_17.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2dbcb3578c8537243143da7ac2c7531ea7b9fc750cb26e9809643289eeddce7b +size 107564 diff --git a/vad/dataset/audio/segments/test1_segment_18.wav b/vad/dataset/audio/segments/test1_segment_18.wav new file mode 100644 index 0000000000000000000000000000000000000000..1dc3945502977a114342f696d1d96eedcb2b0e51 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_18.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:538b2dda6990368d68234fded22b5ed3d67c56a620e79cba7ac545a102465160 +size 68204 diff --git a/vad/dataset/audio/segments/test1_segment_2.wav b/vad/dataset/audio/segments/test1_segment_2.wav new file mode 100644 index 0000000000000000000000000000000000000000..bb8d3bbd2db319a2326314270183c405a0d22471 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_2.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81375721eb3a532941083c9781f53f5e0f1ccbe1ef4108f98a019de400f5c564 +size 117164 diff --git a/vad/dataset/audio/segments/test1_segment_3.wav b/vad/dataset/audio/segments/test1_segment_3.wav new file mode 100644 index 0000000000000000000000000000000000000000..bc8bbae18a1d8822e20a76c75cc8cde0cb342910 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_3.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd6120ff04e7365640b9e3a1fb062bc1c31ce0dc54904bd27e25ac5a0b068cde +size 149804 diff --git a/vad/dataset/audio/segments/test1_segment_4.wav b/vad/dataset/audio/segments/test1_segment_4.wav new file mode 100644 index 0000000000000000000000000000000000000000..b422e33b1ab2ed38ad7c462cfe24e7dcf4d6e528 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_4.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99bc0d18ffd0d10742b8d6b5450e537eccd1497c2247e714fa8efe6beb602abd +size 41324 diff --git a/vad/dataset/audio/segments/test1_segment_5.wav b/vad/dataset/audio/segments/test1_segment_5.wav new file mode 100644 index 0000000000000000000000000000000000000000..9cf31cbbb4076dc8821e3936372a53bdc45635b0 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_5.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a9e2196db3537028898b87442f074523251b33219302e6eb8518fb33396c30bd +size 122924 diff --git a/vad/dataset/audio/segments/test1_segment_6.wav b/vad/dataset/audio/segments/test1_segment_6.wav new file mode 100644 index 0000000000000000000000000000000000000000..74c1e0ddfbc481384a1e5741850c6d558acd795d --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_6.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e929f7966a425a559b7442a2914cb99b0df74f1d02938264642dc71f160fc383 +size 113324 diff --git a/vad/dataset/audio/segments/test1_segment_7.wav b/vad/dataset/audio/segments/test1_segment_7.wav new file mode 100644 index 0000000000000000000000000000000000000000..0df5ddfe218e22475e6b70c1e3bcc3e9af0ae311 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_7.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65d800356647c415d80e59fac63db01df31ce51a497aacf43f98aa0e6ec468cb +size 77804 diff --git a/vad/dataset/audio/segments/test1_segment_8.wav b/vad/dataset/audio/segments/test1_segment_8.wav new file mode 100644 index 0000000000000000000000000000000000000000..74fe21cd6f3798de17e9715dc7140a95482df830 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_8.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1c574a7c20332f85c6260febf6eae232473a798404ca29f1b54ac39e5b2d35c +size 91244 diff --git a/vad/dataset/audio/segments/test1_segment_9.wav b/vad/dataset/audio/segments/test1_segment_9.wav new file mode 100644 index 0000000000000000000000000000000000000000..521bd1359e4012414ac91e9a4f047e3ccbbd61c3 --- /dev/null +++ b/vad/dataset/audio/segments/test1_segment_9.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f943b20eb3aafa0befb884f5d125e0596d3f419d8a3c5546ff3cf878603c36b8 +size 67244 diff --git a/vad/dataset/audio/temp/test1_segments_20250423_114118.json b/vad/dataset/audio/temp/test1_segments_20250423_114118.json new file mode 100644 index 0000000000000000000000000000000000000000..8570d5adcff2b2e47e7d1a0c79effa0f0859acce --- /dev/null +++ b/vad/dataset/audio/temp/test1_segments_20250423_114118.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_114118", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/vad/dataset/audio/temp/test1_segments_20250423_114230.json b/vad/dataset/audio/temp/test1_segments_20250423_114230.json new file mode 100644 index 0000000000000000000000000000000000000000..420f05b616516e4700fd4b69ee1ad7cfdb451d95 --- /dev/null +++ b/vad/dataset/audio/temp/test1_segments_20250423_114230.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_114230", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/vad/dataset/audio/temp/test1_segments_20250423_114252.json b/vad/dataset/audio/temp/test1_segments_20250423_114252.json new file mode 100644 index 0000000000000000000000000000000000000000..16d4bb55c36064d0d1834ac5744349e8f5391557 --- /dev/null +++ b/vad/dataset/audio/temp/test1_segments_20250423_114252.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_114252", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/vad/dataset/audio/temp/test1_segments_20250423_125721.json b/vad/dataset/audio/temp/test1_segments_20250423_125721.json new file mode 100644 index 0000000000000000000000000000000000000000..1882623ff7d95ad85c48d8b44de4ce6c4bdb138c --- /dev/null +++ b/vad/dataset/audio/temp/test1_segments_20250423_125721.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_125721", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/vad/dataset/audio/temp/test1_segments_20250423_130157.json b/vad/dataset/audio/temp/test1_segments_20250423_130157.json new file mode 100644 index 0000000000000000000000000000000000000000..ffecf97ad089ad4b556d0175047f8cc94dd90d35 --- /dev/null +++ b/vad/dataset/audio/temp/test1_segments_20250423_130157.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_130157", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/vad/dataset/audio/temp/test1_segments_20250423_130617.json b/vad/dataset/audio/temp/test1_segments_20250423_130617.json new file mode 100644 index 0000000000000000000000000000000000000000..999a4def60972b3c6a604ddd2b241f55b0e0c2c8 --- /dev/null +++ b/vad/dataset/audio/temp/test1_segments_20250423_130617.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_130617", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/vad/dataset/audio/temp/test1_segments_20250423_130734.json b/vad/dataset/audio/temp/test1_segments_20250423_130734.json new file mode 100644 index 0000000000000000000000000000000000000000..bbab86718b865a5ad3b2e8a625bd9a8046346006 --- /dev/null +++ b/vad/dataset/audio/temp/test1_segments_20250423_130734.json @@ -0,0 +1,80 @@ +{ + "audio_file": "../dataset/audio/test1.wav", + "timestamp": "20250423_130734", + "total_frames": 1821, + "speech_frames": 1167, + "segments": [ + { + "start_time": 4.56, + "end_time": 5.67, + "duration": 1.1100000000000003, + "is_speech": true + }, + { + "start_time": 8.4, + "end_time": 12.06, + "duration": 3.66, + "is_speech": true + }, + { + "start_time": 13.11, + "end_time": 17.79, + "duration": 4.68, + "is_speech": true + }, + { + "start_time": 19.77, + "end_time": 21.06, + "duration": 1.2899999999999991, + "is_speech": true + }, + { + "start_time": 21.63, + "end_time": 25.47, + "duration": 3.84, + "is_speech": true + }, + { + "start_time": 26.28, + "end_time": 29.82, + "duration": 3.539999999999999, + "is_speech": true + }, + { + "start_time": 30.42, + "end_time": 32.85, + "duration": 2.4299999999999997, + "is_speech": true + }, + { + "start_time": 33.54, + "end_time": 36.39, + "duration": 2.8500000000000014, + "is_speech": true + }, + { + "start_time": 37.8, + "end_time": 39.9, + "duration": 2.1000000000000014, + "is_speech": true + }, + { + "start_time": 40.86, + "end_time": 42.36, + "duration": 1.5, + "is_speech": true + }, + { + "start_time": 43.05, + "end_time": 46.53, + "duration": 3.480000000000004, + "is_speech": true + }, + { + "start_time": 47.49, + "end_time": 49.71, + "duration": 2.219999999999999, + "is_speech": true + } + ] +} \ No newline at end of file diff --git a/vad/dataset/transcripts/test1_segment_1_20250423_130738.json b/vad/dataset/transcripts/test1_segment_1_20250423_130738.json new file mode 100644 index 0000000000000000000000000000000000000000..b9e6bb501ba1271141f1ad7f912038d82ce5a592 --- /dev/null +++ b/vad/dataset/transcripts/test1_segment_1_20250423_130738.json @@ -0,0 +1,159 @@ +{ + "audio_file": "dataset/audio/segments\\test1_segment_1.wav", + "timestamp": "20250423_130738", + "segments": [ + { + "text": "音频数据处理", + "start_time": 0.0, + "end_time": 1.16, + "confidence": 0.906494140625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "所有音频或语言相关的任务都需要使用音频", + "start_time": 0.0, + "end_time": 3.72, + "confidence": 0.7564697265625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "在我们先入了解这些任务之前", + "start_time": 0.0, + "end_time": 1.6400000000000001, + "confidence": 0.939605712890625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "我们需要了解音频文件的实际内容", + "start_time": 1.6400000000000001, + "end_time": 4.0, + "confidence": 0.939605712890625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "以及如何", + "start_time": 4.0, + "end_time": 4.8, + "confidence": 0.939605712890625, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本台語言將為你介紹的", + "start_time": 0.0, + "end_time": 1.28, + "confidence": 0.907470703125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本单元将为你介绍于音频数据相关的基本概念", + "start_time": 0.0, + "end_time": 3.92, + "confidence": 0.66796875, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "包括剝形、採用、綠和平補土", + "start_time": 0.0, + "end_time": 2.0, + "confidence": 0.708251953125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "你會學習到如何使用音頻", + "start_time": 2.0, + "end_time": 3.6, + "confidence": 0.708251953125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "包括音频数位加载", + "start_time": 0.0, + "end_time": 1.4000000000000001, + "confidence": 0.86474609375, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "音频数据处理", + "start_time": 1.4000000000000001, + "end_time": 2.4, + "confidence": 0.86474609375, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "高效加载大规模音频数级的流适加载方", + "start_time": 0.0, + "end_time": 2.88, + "confidence": 0.956787109375, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "完成本單元的學期後", + "start_time": 0.0, + "end_time": 1.44, + "confidence": 0.9926719665527344, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "你會找", + "start_time": 1.44, + "end_time": 2.12, + "confidence": 0.9926719665527344, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "基础的音频相关数", + "start_time": 0.0, + "end_time": 1.6, + "confidence": 0.7969970703125, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "并且掌握针对不同应用的音频数据处理工具", + "start_time": 0.0, + "end_time": 3.52, + "confidence": 0.9851303100585938, + "verified": false, + "verified_text": null, + "verification_notes": null + }, + { + "text": "本单元的支持会成为后面章节的", + "start_time": 0.0, + "end_time": 2.0, + "confidence": 0.930908203125, + "verified": false, + "verified_text": null, + "verification_notes": null + } + ] +} \ No newline at end of file diff --git a/vad/main.py b/vad/main.py new file mode 100644 index 0000000000000000000000000000000000000000..64d593e9da7720cdc2cb8033bd176c78cf6d7a57 --- /dev/null +++ b/vad/main.py @@ -0,0 +1,130 @@ +import os +import argparse +from audio_processor import AudioProcessor, AudioSegment +from audio_transcriber import AudioTranscriber, TranscriptionResult +from typing import List, Tuple +import json +import soundfile as sf + +def process_audio(audio_path: str, output_dir: str = "dataset/audio/segments") -> Tuple[List[str], List[AudioSegment]]: + """ + 处理音频文件,返回切割后的音频片段路径列表和原始片段列表 + """ + processor = AudioProcessor() + segments = processor.process_audio_file(audio_path) + + # 创建输出目录 + os.makedirs(output_dir, exist_ok=True) + + # 保存切割后的音频片段 + segment_paths = [] + base_name = os.path.splitext(os.path.basename(audio_path))[0] + for i, segment in enumerate(segments): + segment_path = os.path.join(output_dir, f"{base_name}_segment_{i+1}.wav") + processor.save_segment(segment, segment_path) + segment_paths.append(segment_path) + + return segment_paths, segments + +def transcribe_segments(segment_paths: List[str], original_segments: List[AudioSegment]) -> str: + """ + 转录音频片段并保存结果 + """ + transcriber = AudioTranscriber() + all_results = [] + + for i, path in enumerate(segment_paths): + print(f"转录片段 {i+1}/{len(segment_paths)}: {path}") + + # 读取音频数据 + audio_data, _ = sf.read(path) + + # 使用原始片段的时间戳 + original_segment = original_segments[i] + + # 创建AudioSegment对象,保持原始时间戳 + segment = AudioSegment( + start_time=original_segment.start_time, + end_time=original_segment.end_time, + audio_data=audio_data, + is_speech=True + ) + + # 转录 + results = transcriber.transcribe_segment(segment) + all_results.extend(results) + + # 保存转录结果 + output_path = transcriber.save_transcription(all_results, segment_paths[0]) + return output_path + +def verify_transcription(json_path: str): + """ + 交互式验证转录结果 + """ + transcriber = AudioTranscriber() + results = transcriber.load_transcription(json_path) + + print("\n=== 转录结果验证 ===") + print(f"加载转录文件: {json_path}") + print(f"共有 {len(results)} 个片段需要验证") + + for i, result in enumerate(results): + if result.verified: + continue + + print(f"\n片段 {i+1}/{len(results)}") + print(f"时间: {result.start_time:.2f}s -> {result.end_time:.2f}s") + print(f"转录文本: {result.text}") + print(f"置信度: {result.confidence:.2f}") + + while True: + choice = input("\n选项:\n1. 确认正确\n2. 修改文本\n3. 添加注释\n4. 跳过\n请选择 (1-4): ") + + if choice == "1": + transcriber.verify_transcription(result) + break + elif choice == "2": + new_text = input("请输入正确的文本: ") + transcriber.verify_transcription(result, verified_text=new_text) + break + elif choice == "3": + notes = input("请输入注释: ") + transcriber.verify_transcription(result, verification_notes=notes) + break + elif choice == "4": + break + + # 保存验证后的结果 + transcriber.save_transcription(results, json_path) + print("\n✅ 验证结果已保存") + +def main(): + parser = argparse.ArgumentParser(description="音频处理和转录工具") + parser.add_argument("action", choices=["process", "verify"], help="执行的操作: process(处理音频) 或 verify(验证转录)") + parser.add_argument("input_path", help="输入文件路径 (音频文件或JSON文件)") + + args = parser.parse_args() + + try: + if args.action == "process": + print(f"处理音频文件: {args.input_path}") + # 1. 切割音频 + segment_paths, original_segments = process_audio(args.input_path) + print(f"✅ 音频切割完成,共 {len(segment_paths)} 个片段") + if len(segment_paths) == 0: + print("❌ 未找到有效的音频片段,无法继续处理") + return + + # 2. 转录音频 + json_path = transcribe_segments(segment_paths, original_segments) + print(f"✅ 转录完成,结果保存在: {json_path}") + + elif args.action == "verify": + verify_transcription(args.input_path) + + except Exception as e: + print(f"错误: {e}") + +if __name__ == "__main__": + main()