neverlib 0.1.8__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- neverlib/utils/audio_split.py +266 -0
- neverlib/utils/message.py +75 -6
- neverlib/utils/utils.py +224 -108
- neverlib/vad/utils.py +7 -9
- {neverlib-0.1.8.dist-info → neverlib-0.2.0.dist-info}/METADATA +3 -2
- {neverlib-0.1.8.dist-info → neverlib-0.2.0.dist-info}/RECORD +9 -8
- {neverlib-0.1.8.dist-info → neverlib-0.2.0.dist-info}/WHEEL +1 -1
- {neverlib-0.1.8.dist-info → neverlib-0.2.0.dist-info/licenses}/LICENSE +0 -0
- {neverlib-0.1.8.dist-info → neverlib-0.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Author: 凌逆战 | Never
|
|
3
|
+
Date: 2025-04-10 18:07:03
|
|
4
|
+
Description: 音频切割
|
|
5
|
+
'''
|
|
6
|
+
import os
|
|
7
|
+
import random
|
|
8
|
+
import subprocess
|
|
9
|
+
from tqdm import tqdm
|
|
10
|
+
import soundfile as sf
|
|
11
|
+
import numpy as np
|
|
12
|
+
from utils import get_path_list
|
|
13
|
+
from pydub import AudioSegment
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def audio_split_ffmpeg(source_path, target_path, sr, channel_num, duration, endwith="*.pcm"):
|
|
17
|
+
""" 切割音频切不准,会留点尾巴0.016s
|
|
18
|
+
使用ffmpeg分割音频, 分割为短音频(单位:秒), 似乎无法非常准确的分割到指定长度
|
|
19
|
+
:param source_path: 源音频路径
|
|
20
|
+
:param target_path: 目标音频路径
|
|
21
|
+
:param sr: 源音频采样率
|
|
22
|
+
:param channel_num: 源音频声道数
|
|
23
|
+
:param duration: 分割为时长(短音频)(单位:秒)
|
|
24
|
+
:param endwith: 音频格式(支持pcm和wav)
|
|
25
|
+
"""
|
|
26
|
+
wav_path_list = get_path_list(source_path, end=endwith)
|
|
27
|
+
print("待分割的音频数: ", len(wav_path_list))
|
|
28
|
+
for wav_path in wav_path_list:
|
|
29
|
+
wav_folder = wav_path[:-4].replace(source_path, target_path)
|
|
30
|
+
os.makedirs(wav_folder, exist_ok=True)
|
|
31
|
+
|
|
32
|
+
if endwith == "*.pcm":
|
|
33
|
+
# 将pcm文件切割成30s的语音, 有括号会报错
|
|
34
|
+
# ffmpeg -f s16le -ar 16000 -ac 6 -i ./NO.1_A3035_2.pcm -f segment -segment_time 30 -c copy NO.1_A3035_2/%03d.wav
|
|
35
|
+
command = ["ffmpeg", "-f", "s16le", "-ar", f"{sr}", "-ac", str(channel_num),
|
|
36
|
+
"-i", wav_path, "-f", "segment", "-segment_time",
|
|
37
|
+
f"{duration}", "-c", "copy", f"{wav_folder}/%03d.wav"]
|
|
38
|
+
subprocess.run(command, check=True)
|
|
39
|
+
elif endwith == "*.wav":
|
|
40
|
+
# ffmpeg -i ./NO.1_A3035_2.wav -f segment -segment_time 30 -c copy NO.1_A3035_2/%03d.wav
|
|
41
|
+
command = ["ffmpeg", "-i", wav_path, "-f", "segment", "-segment_time",
|
|
42
|
+
f"{duration}", "-c", "copy", f"{wav_folder}/%03d.wav"]
|
|
43
|
+
subprocess.run(command, check=True)
|
|
44
|
+
else:
|
|
45
|
+
assert False, "不支持的音频格式"
|
|
46
|
+
print("分割完毕: done!")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def audio_split_sox(source_path, target_path, duration, endwith="*.wav"):
|
|
50
|
+
"""
|
|
51
|
+
使用sox分割音频, 分割为短音频(单位:秒), 可以非常准确的分割到指定长度
|
|
52
|
+
:param source_path: 源音频路径
|
|
53
|
+
:param target_path: 目标音频路径
|
|
54
|
+
:param duration: 分割为时长(短音频)(单位:秒)
|
|
55
|
+
:param endwith: 音频格式(只支持wav)
|
|
56
|
+
"""
|
|
57
|
+
wav_path_list = get_path_list(source_path, end=endwith)
|
|
58
|
+
|
|
59
|
+
for wav_path in wav_path_list:
|
|
60
|
+
wav_folder = wav_path[:-4].replace(source_path, target_path)
|
|
61
|
+
os.makedirs(wav_folder, exist_ok=True)
|
|
62
|
+
|
|
63
|
+
output_pattern = f"{wav_folder}/%.wav"
|
|
64
|
+
|
|
65
|
+
if endwith == "*.wav":
|
|
66
|
+
# 对 WAV 文件直接进行分割
|
|
67
|
+
os.system(f"sox {wav_path} {output_pattern} trim 0 {str(duration)} : newfile : restart")
|
|
68
|
+
else:
|
|
69
|
+
assert False, "不支持的音频格式"
|
|
70
|
+
|
|
71
|
+
print("分割完毕: done!")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def audio_split_np(source_path, target_path, sr, channel_num, duration, endwith="*.pcm"):
|
|
75
|
+
"""
|
|
76
|
+
使用numpy读取pcm文件并切割保存为wav文件, 保持通道数一致, 保存不足30秒的最后一段音频
|
|
77
|
+
:param source_path: 源音频路径
|
|
78
|
+
:param target_path: 目标音频路径
|
|
79
|
+
:param sr: 采样率
|
|
80
|
+
:param channel_num: 声道数
|
|
81
|
+
:param duration: 分割的时长 (秒)
|
|
82
|
+
:param endwith: 音频格式 (支持 pcm)
|
|
83
|
+
"""
|
|
84
|
+
wav_path_list = get_path_list(source_path, end=endwith) # 获取音频文件列表
|
|
85
|
+
print("待分割的音频数: ", len(wav_path_list))
|
|
86
|
+
|
|
87
|
+
segment_length_samples = duration * sr # 每个切片音频的采样点数
|
|
88
|
+
|
|
89
|
+
for wav_path in wav_path_list:
|
|
90
|
+
print("正在分割: ", wav_path)
|
|
91
|
+
wav_folder = wav_path[:-4].replace(source_path, target_path)
|
|
92
|
+
os.makedirs(wav_folder, exist_ok=True)
|
|
93
|
+
|
|
94
|
+
# 注意读取时使用正确的dtype(例如int16表示16位PCM)
|
|
95
|
+
pcm_data = np.fromfile(wav_path, dtype=np.int16)
|
|
96
|
+
pcm_data = pcm_data.reshape(-1, channel_num)
|
|
97
|
+
|
|
98
|
+
# 计算分割的数量
|
|
99
|
+
num_segments = len(pcm_data) // segment_length_samples
|
|
100
|
+
|
|
101
|
+
# 切割并保存每段音频
|
|
102
|
+
for i in tqdm(range(num_segments)):
|
|
103
|
+
start_idx = i * segment_length_samples
|
|
104
|
+
end_idx = (i + 1) * segment_length_samples
|
|
105
|
+
segment = pcm_data[start_idx:end_idx]
|
|
106
|
+
segment_filename = os.path.join(wav_folder, f"{i + 1:03d}.wav") # 保存为wav文件
|
|
107
|
+
sf.write(segment_filename, segment, sr, subtype='PCM_16')
|
|
108
|
+
|
|
109
|
+
# 如果剩余部分少于30秒, 保存最后一段不足30秒的音频
|
|
110
|
+
remaining_samples = len(pcm_data) % segment_length_samples
|
|
111
|
+
if remaining_samples > 0:
|
|
112
|
+
segment = pcm_data[-remaining_samples:]
|
|
113
|
+
# 保存剩余部分
|
|
114
|
+
remaining_filename = os.path.join(wav_folder, f"{num_segments + 1:03d}.wav")
|
|
115
|
+
sf.write(remaining_filename, segment, sr, subtype='PCM_16')
|
|
116
|
+
|
|
117
|
+
print("分割完毕: done!")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def audio_split_pydub(source_path, target_path, sr, channel_num, duration, endwith="*.pcm", sample_width=2):
|
|
121
|
+
"""
|
|
122
|
+
使用pydub分割音频, 进行精确的分割
|
|
123
|
+
:param source_path: 源音频路径
|
|
124
|
+
:param target_path: 目标音频路径
|
|
125
|
+
:param sr: 源音频采样率
|
|
126
|
+
:param channel_num: 源音频声道数
|
|
127
|
+
:param duration: 分割为时长(短音频)(单位:秒), 必须是1s的整数倍
|
|
128
|
+
:param endwith: 音频格式(支持pcm和wav)
|
|
129
|
+
:param sample_width: 音频的样本宽度(字节数), 默认为2, 表示16位音频
|
|
130
|
+
"""
|
|
131
|
+
assert duration % 1 == 0, "duration必须是1s的整数倍"
|
|
132
|
+
wav_path_list = get_path_list(source_path, end=endwith) # 获取音频文件列表
|
|
133
|
+
print("待分割的音频数: ", len(wav_path_list))
|
|
134
|
+
|
|
135
|
+
for wav_path in wav_path_list:
|
|
136
|
+
print("正在分割: ", wav_path)
|
|
137
|
+
wav_folder = wav_path[:-4].replace(source_path, target_path) # 设置目标文件夹
|
|
138
|
+
os.makedirs(wav_folder, exist_ok=True)
|
|
139
|
+
|
|
140
|
+
# 使用pydub加载音频
|
|
141
|
+
if endwith == "*.pcm":
|
|
142
|
+
# 读取pcm文件, 指定采样率、声道数和样本宽度
|
|
143
|
+
audio = AudioSegment.from_file(wav_path, format="raw", channels=channel_num, frame_rate=sr, sample_width=sample_width)
|
|
144
|
+
elif endwith == "*.wav":
|
|
145
|
+
# 读取wav文件
|
|
146
|
+
audio = AudioSegment.from_wav(wav_path)
|
|
147
|
+
else:
|
|
148
|
+
assert False, "不支持的音频格式"
|
|
149
|
+
|
|
150
|
+
# 计算每段的时长(以毫秒为单位)
|
|
151
|
+
segment_length = duration * 1000 # 转换为毫秒
|
|
152
|
+
|
|
153
|
+
# 切割音频并保存为多个文件
|
|
154
|
+
segment_number = 1
|
|
155
|
+
for i in tqdm(range(0, len(audio), segment_length)):
|
|
156
|
+
segment = audio[i:i + segment_length]
|
|
157
|
+
segment_filename = os.path.join(wav_folder, f"{segment_number:03d}.wav")
|
|
158
|
+
segment.export(segment_filename, format="wav")
|
|
159
|
+
segment_number += 1
|
|
160
|
+
|
|
161
|
+
print("分割完毕: done!")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def audio_split_random(source_dir, target_dir, min_duration=3, max_duration=10, sr=16000):
|
|
165
|
+
"""
|
|
166
|
+
将音频切割成 3 到 10 秒的多个片段并保存。
|
|
167
|
+
参数:
|
|
168
|
+
- input_audio_path: 输入音频文件路径
|
|
169
|
+
- output_dir: 输出音频文件夹路径
|
|
170
|
+
- min_duration: 最短切割片段长度 (秒), 默认3秒
|
|
171
|
+
- max_duration: 最长切割片段长度 (秒), 默认10秒
|
|
172
|
+
- sample_rate: 采样率, 默认16000
|
|
173
|
+
"""
|
|
174
|
+
wav_path_list = get_path_list(source_dir, "*.wav")
|
|
175
|
+
for wav_path in wav_path_list:
|
|
176
|
+
output_dir = wav_path[:-4].replace(source_dir, target_dir)
|
|
177
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
178
|
+
|
|
179
|
+
wav, wav_sr = sf.read(wav_path, always_2d=True)
|
|
180
|
+
assert wav_sr == sr, f"音频采样率不匹配: {wav_sr} != {sr}"
|
|
181
|
+
count = 0
|
|
182
|
+
while len(wav) > min_duration * sr:
|
|
183
|
+
segment_len = random.randint(min_duration * sr, max_duration * sr)
|
|
184
|
+
segment = wav[0: segment_len]
|
|
185
|
+
wav = wav[segment_len:]
|
|
186
|
+
count += 1
|
|
187
|
+
sf.write(os.path.join(output_dir, f"{count}.wav"), segment, sr)
|
|
188
|
+
sf.write(os.path.join(output_dir, f"{count + 1}.wav"), wav, sr)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def audio_split_VADfunasr(source_dir, target_dir, sr=16000):
|
|
192
|
+
"""
|
|
193
|
+
使用funasr的vad模型将音频中的语音分割成短句
|
|
194
|
+
"""
|
|
195
|
+
from filter import HPFilter
|
|
196
|
+
from audio_aug import volume_norm
|
|
197
|
+
from funasr import AutoModel
|
|
198
|
+
model = AutoModel(model="fsmn-vad", model_revision="v2.0.4")
|
|
199
|
+
|
|
200
|
+
wav_path_list = get_path_list(source_dir, "*.wav")
|
|
201
|
+
for wav_path in wav_path_list:
|
|
202
|
+
wav_folder = wav_path[:-4].replace(source_dir, target_dir)
|
|
203
|
+
os.makedirs(wav_folder, exist_ok=True)
|
|
204
|
+
|
|
205
|
+
wav_orig, wav_sr = sf.read(wav_path, always_2d=True)
|
|
206
|
+
assert wav_sr == sr, f"音频采样率为{wav_sr}, 期望为{sr}"
|
|
207
|
+
|
|
208
|
+
wav = HPFilter(wav_orig[:, 0], sr=sr, order=6, cutoff=100)
|
|
209
|
+
wav = volume_norm(wav)
|
|
210
|
+
|
|
211
|
+
res_list = model.generate(input=wav)
|
|
212
|
+
|
|
213
|
+
for res in res_list:
|
|
214
|
+
for i, value_item in enumerate(res["value"]):
|
|
215
|
+
start, end = value_item
|
|
216
|
+
start, end = int(start * wav_sr / 1000), int(end * wav_sr / 1000)
|
|
217
|
+
|
|
218
|
+
# short_wav = wav_orig[start - int(0.5 * sr):end + int(0.5 * sr)]
|
|
219
|
+
# duration = (end - start) / sr
|
|
220
|
+
# assert len(short_wav) > sr * 3, f"{end/sr:.2f}-{start/sr:.2f}={duration:.2f}"
|
|
221
|
+
sf.write(os.path.join(wav_folder, f"{i}.wav"), wav_orig[start:end], sr)
|
|
222
|
+
# break
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def audio_split_VADsilero(source_dir, target_dir, sr, threshold=0.4,
|
|
226
|
+
min_speech_duration_ms=400, min_silence_duration_ms=400,
|
|
227
|
+
window_size_samples=512, speech_pad_ms=500):
|
|
228
|
+
"""
|
|
229
|
+
使用silero的vad模型将音频中的语音分割成短句
|
|
230
|
+
source_dir: 音频文件目录
|
|
231
|
+
target_dir: 分割后的音频文件目录
|
|
232
|
+
sr: 音频采样率
|
|
233
|
+
threshold: 阈值
|
|
234
|
+
min_speech_duration_ms: 语音块的最小持续时间 ms
|
|
235
|
+
min_silence_duration_ms: 语音块之间的最小静音时间 ms
|
|
236
|
+
window_size_samples: 512\1024\1536
|
|
237
|
+
"""
|
|
238
|
+
import torch
|
|
239
|
+
from filter import HPFilter
|
|
240
|
+
from audio_aug import volume_norm
|
|
241
|
+
model, utils = torch.hub.load(repo_or_dir='snakers4/silero-vad', model='silero_vad', force_reload=False, onnx=True)
|
|
242
|
+
(get_speech_timestamps, save_audio, read_audio, VADIterator, collect_chunks) = utils
|
|
243
|
+
|
|
244
|
+
wav_path_list = get_path_list(source_dir, "*.wav")
|
|
245
|
+
for wav_path in wav_path_list:
|
|
246
|
+
wav_folder = wav_path[:-4].replace(source_dir, target_dir)
|
|
247
|
+
os.makedirs(wav_folder, exist_ok=True)
|
|
248
|
+
|
|
249
|
+
wav_orig, wav_sr = sf.read(wav_path, always_2d=True)
|
|
250
|
+
assert wav_sr == sr, f"音频采样率为{wav_sr}, 期望为{sr}"
|
|
251
|
+
|
|
252
|
+
wav = HPFilter(wav_orig[:, 0], sr=sr, order=6, cutoff=100)
|
|
253
|
+
wav = volume_norm(wav)
|
|
254
|
+
|
|
255
|
+
speech_timestamps = get_speech_timestamps(wav, model,
|
|
256
|
+
sampling_rate=sr,
|
|
257
|
+
threshold=threshold,
|
|
258
|
+
min_speech_duration_ms=min_speech_duration_ms, # 语音块的最小持续时间 ms
|
|
259
|
+
min_silence_duration_ms=min_silence_duration_ms, # 语音块之间的最小静音时间 ms
|
|
260
|
+
window_size_samples=window_size_samples, # 512\1024\1536
|
|
261
|
+
speech_pad_ms=speech_pad_ms, # 最后的语音块由两侧的speech_pad_ms填充
|
|
262
|
+
)
|
|
263
|
+
for i, timestamp in enumerate(speech_timestamps):
|
|
264
|
+
wav_vad = wav_orig[timestamp["start"]:timestamp["end"]]
|
|
265
|
+
|
|
266
|
+
sf.write(os.path.join(wav_folder, f"{i}.wav"), wav_vad, sr)
|
neverlib/utils/message.py
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Author: 凌逆战 | Never
|
|
3
|
+
Date: 2025-02-13 20:06:07
|
|
4
|
+
Description: 请填写文件描述
|
|
5
|
+
'''
|
|
1
6
|
# -*- coding:utf-8 -*-
|
|
2
7
|
# Author:凌逆战 | Never
|
|
3
8
|
# Date: 2024/2/1
|
|
4
9
|
"""
|
|
5
10
|
通过邮件发送通知
|
|
6
11
|
"""
|
|
12
|
+
import os
|
|
7
13
|
import smtplib
|
|
8
14
|
from email.header import Header
|
|
9
15
|
from email.mime.text import MIMEText
|
|
16
|
+
from email.mime.image import MIMEImage
|
|
10
17
|
from email.utils import formataddr
|
|
11
|
-
|
|
18
|
+
from email.mime.multipart import MIMEMultipart
|
|
12
19
|
|
|
13
|
-
np.set_printoptions(precision=1) # 设置numpy的打印精度
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
def send_QQEmail(title, content, from_email, from_password, to_email):
|
|
21
|
+
def send_QQEmail(title, content, from_name, from_email, from_password, to_email):
|
|
17
22
|
"""
|
|
18
23
|
Args:
|
|
19
24
|
title: 邮件标题
|
|
@@ -28,8 +33,8 @@ def send_QQEmail(title, content, from_email, from_password, to_email):
|
|
|
28
33
|
# 设置邮件正文
|
|
29
34
|
message = MIMEText(content, "plain", "utf-8")
|
|
30
35
|
message["Subject"] = Header(title, charset="utf-8")
|
|
31
|
-
message["From"] = formataddr((
|
|
32
|
-
message["From"] = Header(from_email)
|
|
36
|
+
message["From"] = formataddr((from_name, from_email))
|
|
37
|
+
# message["From"] = Header(from_email)
|
|
33
38
|
message["To"] = Header(to_email)
|
|
34
39
|
|
|
35
40
|
try:
|
|
@@ -44,6 +49,70 @@ def send_QQEmail(title, content, from_email, from_password, to_email):
|
|
|
44
49
|
print(f"邮件发送失败:{e}")
|
|
45
50
|
|
|
46
51
|
|
|
52
|
+
def send_QQEmail_with_images(title, content, from_name, from_email, from_password, to_email, image_paths):
|
|
53
|
+
"""
|
|
54
|
+
发送包含多张PNG图片附件的QQ邮件
|
|
55
|
+
:param title: 邮件标题
|
|
56
|
+
:param content: 邮件正文内容(支持HTML格式)
|
|
57
|
+
:param from_email: 发件人邮箱
|
|
58
|
+
:param from_password: 发件人邮箱SMTP授权码
|
|
59
|
+
:param to_email: 收件人邮箱
|
|
60
|
+
:param image_paths: 图片文件路径列表,应为PNG格式
|
|
61
|
+
"""
|
|
62
|
+
# 设置邮箱的域名
|
|
63
|
+
HOST = "smtp.qq.com"
|
|
64
|
+
# 创建一个MIMEMultipart对象来包含邮件的各个部分
|
|
65
|
+
message = MIMEMultipart()
|
|
66
|
+
message["Subject"] = Header(title, charset="utf-8")
|
|
67
|
+
message["From"] = formataddr((from_name, from_email))
|
|
68
|
+
message["To"] = Header(to_email)
|
|
69
|
+
|
|
70
|
+
# 准备HTML内容
|
|
71
|
+
html_content = content + "<br>"
|
|
72
|
+
|
|
73
|
+
# 循环处理每张图片
|
|
74
|
+
for index, image_path in enumerate(image_paths):
|
|
75
|
+
try:
|
|
76
|
+
# 生成图片的Content-ID
|
|
77
|
+
image_id = f'image{index + 1}'
|
|
78
|
+
cid = f"<{image_id}>"
|
|
79
|
+
|
|
80
|
+
# 在HTML内容中添加图片引用
|
|
81
|
+
html_content += f'<br><img src="cid:{image_id}" style="max-width:100%; max-height:100%;"><br>'
|
|
82
|
+
|
|
83
|
+
# 打开图片文件并将其添加到邮件中
|
|
84
|
+
with open(image_path, 'rb') as img_file:
|
|
85
|
+
img_data = img_file.read()
|
|
86
|
+
|
|
87
|
+
# 使用 MIMEImage 添加图片
|
|
88
|
+
image_part = MIMEImage(img_data)
|
|
89
|
+
|
|
90
|
+
# 设置Content-ID,以便在正文中引用图片
|
|
91
|
+
image_part.add_header('Content-ID', cid)
|
|
92
|
+
|
|
93
|
+
# 设置为 inline 显示,避免附件处理
|
|
94
|
+
image_part.add_header('Content-Disposition', 'inline', filename=os.path.basename(image_path))
|
|
95
|
+
|
|
96
|
+
# 添加图片到邮件
|
|
97
|
+
message.attach(image_part)
|
|
98
|
+
except Exception as e:
|
|
99
|
+
print(f"添加图片 {image_path} 失败: {e}")
|
|
100
|
+
|
|
101
|
+
# 添加邮件正文
|
|
102
|
+
text_part = MIMEText(html_content, "html", "utf-8")
|
|
103
|
+
message.attach(text_part)
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
# 使用SSL连接
|
|
107
|
+
server = smtplib.SMTP_SSL(HOST)
|
|
108
|
+
server.connect(HOST, 465)
|
|
109
|
+
server.login(from_email, from_password) # 登录邮箱
|
|
110
|
+
server.sendmail(from_email, to_email, message.as_string()) # 发送邮件
|
|
111
|
+
server.quit() # 关闭SMTP服务器
|
|
112
|
+
print("邮件发送成功")
|
|
113
|
+
except Exception as e:
|
|
114
|
+
print(f"邮件发送失败:{e}")
|
|
115
|
+
|
|
47
116
|
|
|
48
117
|
if __name__ == "__main__":
|
|
49
118
|
send_QQEmail("实验跑完", "实验跑完了,快去看看吧!",
|
neverlib/utils/utils.py
CHANGED
|
@@ -8,11 +8,10 @@ import os
|
|
|
8
8
|
import random
|
|
9
9
|
import shutil
|
|
10
10
|
import fnmatch
|
|
11
|
-
import subprocess
|
|
12
11
|
from tqdm import tqdm
|
|
13
|
-
import multiprocessing
|
|
14
12
|
from datetime import datetime
|
|
15
|
-
|
|
13
|
+
import soundfile as sf
|
|
14
|
+
import numpy as np
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
def get_path_list(source_path, end="*.wav", shuffle=False):
|
|
@@ -47,111 +46,6 @@ def rename_files_and_folders(directory, replace='_-', replacement='_'):
|
|
|
47
46
|
print(f'Renamed folder: {old_path} -> {new_path}')
|
|
48
47
|
|
|
49
48
|
|
|
50
|
-
def audio_split_ffmpeg(source_path, target_path, sr, channel_num, duration, endwith="*.pcm"):
|
|
51
|
-
"""
|
|
52
|
-
使用ffmpeg分割音频, 分割为短音频(单位:秒), 似乎无法非常准确的分割到指定长度
|
|
53
|
-
:param source_path: 源音频路径
|
|
54
|
-
:param target_path: 目标音频路径
|
|
55
|
-
:param sr: 源音频采样率
|
|
56
|
-
:param channel_num: 源音频声道数
|
|
57
|
-
:param duration: 分割为时长(短音频)(单位:秒)
|
|
58
|
-
:param endwith: 音频格式(支持pcm和wav)
|
|
59
|
-
"""
|
|
60
|
-
wav_path_list = get_path_list(source_path, end=endwith)
|
|
61
|
-
print("待分割的音频数: ", len(wav_path_list))
|
|
62
|
-
for wav_path in wav_path_list:
|
|
63
|
-
wav_folder = wav_path[:-4].replace(source_path, target_path)
|
|
64
|
-
if not os.path.exists(wav_folder):
|
|
65
|
-
os.makedirs(wav_folder)
|
|
66
|
-
|
|
67
|
-
if endwith == "*.pcm":
|
|
68
|
-
# 将pcm文件切割成30s的语音, 有括号会报错
|
|
69
|
-
# ffmpeg -f s16le -ar 16000 -ac 6 -i ./NO.1_A3035_2.pcm -f segment -segment_time 30 -c copy NO.1_A3035_2/%03d.wav
|
|
70
|
-
command = ["ffmpeg", "-f", "s16le", "-ar", f"{sr}", "-ac", str(channel_num),
|
|
71
|
-
"-i", wav_path, "-f", "segment", "-segment_time",
|
|
72
|
-
f"{duration}", "-c", "copy", f"{wav_folder}/%03d.wav"]
|
|
73
|
-
subprocess.run(command, check=True)
|
|
74
|
-
elif endwith == "*.wav":
|
|
75
|
-
# ffmpeg -i ./NO.1_A3035_2.wav -f segment -segment_time 30 -c copy NO.1_A3035_2/%03d.wav
|
|
76
|
-
command = ["ffmpeg", "-i", wav_path, "-f", "segment", "-segment_time",
|
|
77
|
-
f"{duration}", "-c", "copy", f"{wav_folder}/%03d.wav"]
|
|
78
|
-
subprocess.run(command, check=True)
|
|
79
|
-
else:
|
|
80
|
-
assert False, "不支持的音频格式"
|
|
81
|
-
print("分割完毕: done!")
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def audio_split_sox(source_path, target_path, duration, endwith="*.wav"):
|
|
85
|
-
"""
|
|
86
|
-
使用sox分割音频, 分割为短音频(单位:秒), 可以非常准确的分割到指定长度
|
|
87
|
-
:param source_path: 源音频路径
|
|
88
|
-
:param target_path: 目标音频路径
|
|
89
|
-
:param duration: 分割为时长(短音频)(单位:秒)
|
|
90
|
-
:param endwith: 音频格式(只支持wav)
|
|
91
|
-
"""
|
|
92
|
-
wav_path_list = get_path_list(source_path, end=endwith)
|
|
93
|
-
|
|
94
|
-
for wav_path in wav_path_list:
|
|
95
|
-
wav_folder = wav_path[:-4].replace(source_path, target_path)
|
|
96
|
-
if not os.path.exists(wav_folder):
|
|
97
|
-
os.makedirs(wav_folder)
|
|
98
|
-
|
|
99
|
-
output_pattern = f"{wav_folder}/%.wav"
|
|
100
|
-
|
|
101
|
-
if endwith == "*.wav":
|
|
102
|
-
# 对 WAV 文件直接进行分割
|
|
103
|
-
os.system(f"sox {wav_path} {output_pattern} trim 0 {str(duration)} : newfile : restart")
|
|
104
|
-
else:
|
|
105
|
-
assert False, "不支持的音频格式"
|
|
106
|
-
|
|
107
|
-
print("分割完毕: done!")
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def audio_split_worker(wav_path, target_path, sr, channel_num, duration, endwith="*.pcm"):
|
|
111
|
-
wav_name = os.path.basename(wav_path)[:-4]
|
|
112
|
-
wav_folder = os.path.join(target_path, wav_name)
|
|
113
|
-
if not os.path.exists(wav_folder):
|
|
114
|
-
os.makedirs(wav_folder)
|
|
115
|
-
|
|
116
|
-
if endwith == "*.pcm":
|
|
117
|
-
# 将pcm文件切割成30s的语音, 有括号会报错
|
|
118
|
-
# os.system(r"ffmpeg -f s16le -ar {} -ac {} -i {} -f segment -segment_time {} -c copy {}/%03d.wav".format(
|
|
119
|
-
# sr, channel_num, wav_path, duration, wav_folder))
|
|
120
|
-
command = ["ffmpeg", "-f", "s16le", "-ar", f"{sr}", "-ac", str(channel_num),
|
|
121
|
-
"-i", wav_path, "-f", "segment", "-segment_time",
|
|
122
|
-
f"{duration}", "-c", "copy", f"{wav_folder}/%03d.wav"]
|
|
123
|
-
subprocess.run(command, check=True)
|
|
124
|
-
# 调用库
|
|
125
|
-
# input_audio = ffmpeg.input(wav_path, format='s16le', ar=16000, ac=5)
|
|
126
|
-
# output_audio = ffmpeg.output(input_audio, f='segment', segment_time=30, c='copy', path=f'{wav_folder}/%03d.wav')
|
|
127
|
-
# ffmpeg.run(output_audio)
|
|
128
|
-
elif endwith == "*.wav":
|
|
129
|
-
# ffmpeg -i ./NO.1_A3035_2.wav -f segment -segment_time 30 -c copy NO.1_A3035_2/%03d.wav
|
|
130
|
-
command = ["ffmpeg", "-i", wav_path, "-f", "segment", "-segment_time",
|
|
131
|
-
f"{duration}", "-c", "copy", f"{wav_folder}/%03d.wav"]
|
|
132
|
-
subprocess.run(command, check=True)
|
|
133
|
-
else:
|
|
134
|
-
assert False, "不支持的音频格式"
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def audio_split_multiprocessing(source_path, target_path, sr, channel_num, duration, endwith="*.pcm"):
|
|
138
|
-
wav_path_list = get_path_list(source_path, end=endwith)
|
|
139
|
-
print("待分割的音频数: ", len(wav_path_list))
|
|
140
|
-
|
|
141
|
-
# 创建进程池
|
|
142
|
-
pool = multiprocessing.Pool(processes=5)
|
|
143
|
-
|
|
144
|
-
# 使用进程池处理音频文件分割任务
|
|
145
|
-
for wav_path in wav_path_list:
|
|
146
|
-
pool.apply_async(audio_split_worker, args=(wav_path, target_path, sr, channel_num, duration, endwith))
|
|
147
|
-
|
|
148
|
-
# 关闭进程池,等待所有进程完成
|
|
149
|
-
pool.close()
|
|
150
|
-
pool.join()
|
|
151
|
-
|
|
152
|
-
print("分割完毕: done!")
|
|
153
|
-
|
|
154
|
-
|
|
155
49
|
def get_file_time(file_path):
|
|
156
50
|
# 获取最后修改时间
|
|
157
51
|
mod_time = os.path.getmtime(file_path)
|
|
@@ -192,3 +86,225 @@ def TrainValSplit(dataset_dir, train_dir, val_dir, percentage=0.9):
|
|
|
192
86
|
shutil.copy(val_wavpath, target_path)
|
|
193
87
|
|
|
194
88
|
print("Done!")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def TrainValTestSplit(dataset_dir, train_dir, val_dir, test_dir, percentage=[0.8, 0.1, 0.1]):
|
|
92
|
+
""" 分割数据集为训练集、验证集和测试集
|
|
93
|
+
:param dataset_dir: 源数据集地址
|
|
94
|
+
:param train_dir: 训练集地址
|
|
95
|
+
:param val_dir: 验证集地址
|
|
96
|
+
:param test_dir: 测试集地址
|
|
97
|
+
:param percentage: 分割百分比
|
|
98
|
+
"""
|
|
99
|
+
assert sum(percentage) == 1.0, "百分比总和必须等于1.0"
|
|
100
|
+
|
|
101
|
+
wav_path_list = sorted(get_path_list(dataset_dir, end="*.wav"))
|
|
102
|
+
random.seed(10086)
|
|
103
|
+
random.shuffle(wav_path_list) # 打乱列表的顺序
|
|
104
|
+
total_wav_num = len(wav_path_list)
|
|
105
|
+
|
|
106
|
+
# 计算训练集、验证集和测试集的分割点
|
|
107
|
+
train_split_idx = int(total_wav_num * percentage[0])
|
|
108
|
+
val_split_idx = train_split_idx + int(total_wav_num * percentage[1])
|
|
109
|
+
|
|
110
|
+
train_path_list = wav_path_list[:train_split_idx]
|
|
111
|
+
val_path_list = wav_path_list[train_split_idx:val_split_idx]
|
|
112
|
+
test_path_list = wav_path_list[val_split_idx:]
|
|
113
|
+
|
|
114
|
+
for train_wavpath in tqdm(train_path_list, desc="复制训练集音频"):
|
|
115
|
+
target_path = train_wavpath.replace(dataset_dir, train_dir)
|
|
116
|
+
if not os.path.exists(os.path.split(target_path)[0]):
|
|
117
|
+
os.makedirs(os.path.split(target_path)[0])
|
|
118
|
+
shutil.copy(train_wavpath, target_path)
|
|
119
|
+
|
|
120
|
+
for val_wavpath in tqdm(val_path_list, desc="复制验证集音频"):
|
|
121
|
+
target_path = val_wavpath.replace(dataset_dir, val_dir)
|
|
122
|
+
if not os.path.exists(os.path.split(target_path)[0]):
|
|
123
|
+
os.makedirs(os.path.split(target_path)[0])
|
|
124
|
+
shutil.copy(val_wavpath, target_path)
|
|
125
|
+
|
|
126
|
+
for test_wavpath in tqdm(test_path_list, desc="复制测试集音频"):
|
|
127
|
+
target_path = test_wavpath.replace(dataset_dir, test_dir)
|
|
128
|
+
if not os.path.exists(os.path.split(target_path)[0]):
|
|
129
|
+
os.makedirs(os.path.split(target_path)[0])
|
|
130
|
+
shutil.copy(test_wavpath, target_path)
|
|
131
|
+
|
|
132
|
+
print(f"完成! 训练集: {len(train_path_list)}个文件, 验证集: {len(val_path_list)}个文件, 测试集: {len(test_path_list)}个文件")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def get_leaf_folders(directory):
|
|
136
|
+
# 获取最底层的文件夹路径
|
|
137
|
+
leaf_folders = []
|
|
138
|
+
for root, dirs, _ in os.walk(directory):
|
|
139
|
+
if not dirs: # 如果当前文件夹没有子文件夹
|
|
140
|
+
leaf_folders.append(root)
|
|
141
|
+
return leaf_folders
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def DatasetSubfloderSplit(source_dir, split_dirs, percentage=None):
|
|
145
|
+
"""
|
|
146
|
+
将一个数据集按照子文件夹数量分割成train/val/test数据集
|
|
147
|
+
Args:
|
|
148
|
+
source_dir (str): 源数据集目录
|
|
149
|
+
split_dirs (list): 目标目录列表,如 [train_dir, val_dir] 或 [train_dir, val_dir, test_dir]
|
|
150
|
+
percentage (list, optional): 分割比例,如 [0.9, 0.1] 或 [0.8, 0.1, 0.1]。默认为 None,此时:
|
|
151
|
+
- 如果是两路分割,默认为 [0.9, 0.1]
|
|
152
|
+
- 如果是三路分割,默认为 [0.8, 0.1, 0.1]
|
|
153
|
+
Example:
|
|
154
|
+
# 两路分割示例
|
|
155
|
+
DatasetSplit(
|
|
156
|
+
source_dir=source_dataset_path,
|
|
157
|
+
split_dirs=[target_train_path, target_val_path],
|
|
158
|
+
percentage=[0.9, 0.1]
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# 三路分割示例
|
|
162
|
+
DatasetSplit(
|
|
163
|
+
source_dir=source_dataset_path,
|
|
164
|
+
split_dirs=[target_train_path, target_val_path, target_test_path],
|
|
165
|
+
percentage=[0.8, 0.1, 0.1]
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# 使用默认比例的两路分割
|
|
169
|
+
DatasetSplit(
|
|
170
|
+
source_dir=source_dataset_path,
|
|
171
|
+
split_dirs=[target_train_path, target_val_path]
|
|
172
|
+
)
|
|
173
|
+
"""
|
|
174
|
+
if percentage is None:
|
|
175
|
+
percentage = [0.9, 0.1] if len(split_dirs) == 2 else [0.8, 0.1, 0.1]
|
|
176
|
+
|
|
177
|
+
# 验证输入参数
|
|
178
|
+
if len(split_dirs) not in [2, 3]:
|
|
179
|
+
raise ValueError("只支持2路或3路分割(训练集/验证集 或 训练集/验证集/测试集)")
|
|
180
|
+
if len(percentage) != len(split_dirs):
|
|
181
|
+
raise ValueError("分割比例数量必须与目标目录数量相同")
|
|
182
|
+
if sum(percentage) != 1.0:
|
|
183
|
+
raise ValueError("分割比例之和必须等于1.0")
|
|
184
|
+
|
|
185
|
+
# 获取并打乱文件夹列表
|
|
186
|
+
leaf_folder_list = sorted(get_leaf_folders(source_dir))
|
|
187
|
+
random.seed(10086)
|
|
188
|
+
random.shuffle(leaf_folder_list)
|
|
189
|
+
total_folder_num = len(leaf_folder_list)
|
|
190
|
+
|
|
191
|
+
# 计算分割点
|
|
192
|
+
split_indices = []
|
|
193
|
+
acc_percentage = 0
|
|
194
|
+
for p in percentage[:-1]: # 最后一个比例不需要计算
|
|
195
|
+
acc_percentage += p
|
|
196
|
+
split_indices.append(int(total_folder_num * acc_percentage))
|
|
197
|
+
|
|
198
|
+
# 分割文件夹列表
|
|
199
|
+
split_folder_lists = []
|
|
200
|
+
start_idx = 0
|
|
201
|
+
for end_idx in split_indices:
|
|
202
|
+
split_folder_lists.append(leaf_folder_list[start_idx:end_idx])
|
|
203
|
+
start_idx = end_idx
|
|
204
|
+
split_folder_lists.append(leaf_folder_list[start_idx:]) # 添加最后一部分
|
|
205
|
+
|
|
206
|
+
# 复制文件夹
|
|
207
|
+
split_names = ['train', 'val', 'test']
|
|
208
|
+
for folders, target_dir, split_name in zip(split_folder_lists, split_dirs, split_names[:len(split_dirs)]):
|
|
209
|
+
for folder in tqdm(folders, desc=f"Copying {split_name} folders"):
|
|
210
|
+
target_folder = folder.replace(source_dir, target_dir)
|
|
211
|
+
os.makedirs(os.path.dirname(target_folder), exist_ok=True)
|
|
212
|
+
shutil.copytree(folder, target_folder)
|
|
213
|
+
|
|
214
|
+
# 打印统计信息
|
|
215
|
+
print(f"Total folders: {total_folder_num}")
|
|
216
|
+
for folders, split_name in zip(split_folder_lists, split_names[:len(split_dirs)]):
|
|
217
|
+
print(f"{split_name.capitalize()} folders: {len(folders)}")
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def pcm2wav(pcm_path, wav_path, sr=16000, channels=1, subtype='PCM_16'):
|
|
221
|
+
"""
|
|
222
|
+
将pcm文件转换为wav文件
|
|
223
|
+
:param pcm_path: pcm文件路径
|
|
224
|
+
:param wav_path: wav文件路径
|
|
225
|
+
:param sr: 采样率
|
|
226
|
+
:param channels: 声道数
|
|
227
|
+
:param subtype: 子类型
|
|
228
|
+
"""
|
|
229
|
+
pcm_data = np.fromfile(pcm_path, dtype=np.int16)
|
|
230
|
+
pcm_data = pcm_data.reshape(-1, channels) # 支持多通道
|
|
231
|
+
sf.write(wav_path, pcm_data, sr, subtype=subtype)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def wav2pcm(wav_path, pcm_path):
|
|
235
|
+
"""
|
|
236
|
+
将wav文件转换为pcm文件
|
|
237
|
+
:param wav_path: wav文件路径
|
|
238
|
+
:param pcm_path: pcm文件路径
|
|
239
|
+
"""
|
|
240
|
+
data, _ = sf.read(wav_path, dtype='int16')
|
|
241
|
+
data.tofile(pcm_path)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def save_weight_histogram(model, save_dir, mode=["params", "buffers"], ignore_name=["scale", "bias"], bins=100):
|
|
245
|
+
"""
|
|
246
|
+
保存模型权重分布直方图
|
|
247
|
+
Args:
|
|
248
|
+
model: PyTorch模型
|
|
249
|
+
save_dir: 保存路径
|
|
250
|
+
mode: 保存模式,可选值为["params", "buffers"]
|
|
251
|
+
bins: 直方图bin数量
|
|
252
|
+
"""
|
|
253
|
+
import matplotlib.pyplot as plt
|
|
254
|
+
# 如果路径存在,则删除
|
|
255
|
+
if os.path.exists(save_dir):
|
|
256
|
+
shutil.rmtree(save_dir)
|
|
257
|
+
|
|
258
|
+
if "params" in mode:
|
|
259
|
+
os.makedirs(os.path.join(save_dir, "param"), exist_ok=True)
|
|
260
|
+
for name, param in model.named_parameters():
|
|
261
|
+
if any(ignore in name for ignore in ignore_name):
|
|
262
|
+
continue
|
|
263
|
+
param = param.cpu().data.flatten().numpy()
|
|
264
|
+
param_min = param.min()
|
|
265
|
+
param_max = param.max()
|
|
266
|
+
param_mean = param.mean()
|
|
267
|
+
param_std = param.std()
|
|
268
|
+
|
|
269
|
+
# 保存模型参数到地址
|
|
270
|
+
# 绘制直方图
|
|
271
|
+
plt.title(name)
|
|
272
|
+
plt.xlabel("value")
|
|
273
|
+
plt.ylabel("count")
|
|
274
|
+
plt.grid(alpha=0.5)
|
|
275
|
+
# 在右上角添加统计信息
|
|
276
|
+
plt.text(1, 1, f"max: {param_max:.2f}\n \
|
|
277
|
+
min: {param_min:.2f}\n \
|
|
278
|
+
mean: {param_mean:.2f}\n \
|
|
279
|
+
std: {param_std:.2f}",
|
|
280
|
+
ha='right', va='top', transform=plt.gca().transAxes)
|
|
281
|
+
plt.hist(param, bins=bins)
|
|
282
|
+
plt.savefig(os.path.join(save_dir, "param", f"{name}.png"))
|
|
283
|
+
plt.close()
|
|
284
|
+
if "buffers" in mode:
|
|
285
|
+
os.makedirs(os.path.join(save_dir, "buffer"), exist_ok=True)
|
|
286
|
+
for name, buffer in model.named_buffers():
|
|
287
|
+
if "running_mean" not in name and "running_var" not in name:
|
|
288
|
+
continue
|
|
289
|
+
buffer = buffer.cpu().data.flatten().numpy()
|
|
290
|
+
|
|
291
|
+
# 计算统计数据
|
|
292
|
+
buffer_min = buffer.min()
|
|
293
|
+
buffer_max = buffer.max()
|
|
294
|
+
buffer_mean = buffer.mean()
|
|
295
|
+
buffer_std = buffer.std()
|
|
296
|
+
|
|
297
|
+
# 绘制直方图
|
|
298
|
+
plt.title(name)
|
|
299
|
+
plt.xlabel("value")
|
|
300
|
+
plt.ylabel("count")
|
|
301
|
+
plt.grid(alpha=0.5)
|
|
302
|
+
# 在右上角添加统计信息
|
|
303
|
+
plt.text(1, 1, f"max: {buffer_max:.2f}\n \
|
|
304
|
+
min: {buffer_min:.2f}\n \
|
|
305
|
+
mean: {buffer_mean:.2f}\n \
|
|
306
|
+
std: {buffer_std:.2f}",
|
|
307
|
+
ha='right', va='top', transform=plt.gca().transAxes)
|
|
308
|
+
plt.hist(buffer, bins=bins)
|
|
309
|
+
plt.savefig(os.path.join(save_dir, "buffer", f"{name}.png"))
|
|
310
|
+
plt.close()
|
neverlib/vad/utils.py
CHANGED
|
@@ -7,20 +7,18 @@
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def
|
|
10
|
+
def from_vadArray_to_vadEndpoint(vad_array):
|
|
11
11
|
# 计算活动段的起始点和结束点
|
|
12
12
|
# vad_array = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1])
|
|
13
13
|
# 返回 [(2320, 8079), (8400, 8719), (8880, 10959), (11600, 25039), (25840, 27439), (29040, 29359), (29520, 31759), (32240, 32399)]
|
|
14
|
-
starts = np.where((vad_array[:-1] == 0) & (vad_array[1:] == 1))[0] + 1
|
|
15
|
-
ends = np.where((vad_array[:-1] == 1) & (vad_array[1:] == 0))[0]
|
|
14
|
+
starts = np.where((vad_array[:-1] == 0) & (vad_array[1:] == 1))[0] + 1 # +1是因为提前了一个点
|
|
15
|
+
ends = np.where((vad_array[:-1] == 1) & (vad_array[1:] == 0))[0] + 1 # + 1是因为不取最后一个点
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
if vad_array[-1] == 1: ends = np.append(ends, len(vad_array)
|
|
19
|
-
#
|
|
17
|
+
# 如果最后一个点还是1,则需要手动添加结束点
|
|
18
|
+
if vad_array[-1] == 1: ends = np.append(ends, len(vad_array))
|
|
19
|
+
# 如果第一个点就是1, 则需要手动添加起始点
|
|
20
20
|
if vad_array[0] == 1: starts = np.insert(starts, 0, 0)
|
|
21
|
-
|
|
22
|
-
# 处理可能存在的错位情况
|
|
23
|
-
if len(starts) > len(ends): starts = starts[:-1]
|
|
21
|
+
assert len(starts) == len(ends), "starts and ends must have the same length"
|
|
24
22
|
|
|
25
23
|
Timestamps = [{"start": int(start), "end": int(end)} for start, end in zip(starts, ends)]
|
|
26
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: neverlib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A successful sign for python setup
|
|
5
5
|
Author-email: "Never.Ling" <1786088386@qq.com>
|
|
6
6
|
License: MIT
|
|
@@ -41,6 +41,7 @@ Requires-Dist: funasr; extra == "all"
|
|
|
41
41
|
Requires-Dist: openai-whisper; extra == "all"
|
|
42
42
|
Requires-Dist: transformers; extra == "all"
|
|
43
43
|
Requires-Dist: GPUtil; extra == "all"
|
|
44
|
+
Dynamic: license-file
|
|
44
45
|
|
|
45
46
|
# NeverLib
|
|
46
47
|
|
|
@@ -14,9 +14,10 @@ neverlib/filter/common.py,sha256=9MGVpnW2D6wYxO0-5Kru4SwmB7CriPZqf5FacTt6b7Y,103
|
|
|
14
14
|
neverlib/tests/__init__.py,sha256=PITL4btOVji1rexFP35A20v2gcLqc6vmGWiF-_5ywnI,27
|
|
15
15
|
neverlib/tests/test_preprocess.py,sha256=GHj2PvlG8chJlV-zpRfy8IYlTXzGkn5heO9ipy6Xe20,1003
|
|
16
16
|
neverlib/utils/__init__.py,sha256=kUUhBstCxeXNg3WMmHyrNcx6aDNhUs_LucyygnOF4Ro,137
|
|
17
|
+
neverlib/utils/audio_split.py,sha256=pRh2DqOg8Rg4o6QBv_xuQKWlZ4WI-RDqtCoP_-YTE6o,12014
|
|
17
18
|
neverlib/utils/checkGPU.py,sha256=Wye2UovtVK6Fk8W4wZ3dqaYrdZc30WyW5iGa-6Ouxf0,4075
|
|
18
|
-
neverlib/utils/message.py,sha256=
|
|
19
|
-
neverlib/utils/utils.py,sha256=
|
|
19
|
+
neverlib/utils/message.py,sha256=xeBwvHXJ0GTJ-4Mt0KrrfJNk3JY22_fxYwV7TTuLjWk,4235
|
|
20
|
+
neverlib/utils/utils.py,sha256=A3zqRVIoZeskuDMI_Dnx7g46yyN8ZT1k1g0x0prK_6A,12336
|
|
20
21
|
neverlib/utils/waveform_analyzer.py,sha256=H4lgcms2Obkeg8uxazLvA7GPwa5dsMaIaP_GXF6fi5w,1264
|
|
21
22
|
neverlib/vad/PreProcess.py,sha256=KlJ3LlJjv4dgVMqpC49BbKLoaueRvCC6OGnUkR9fdAs,2078
|
|
22
23
|
neverlib/vad/README.md,sha256=179PS6jXe9FfzNmg1yhTshIPqLsczWRP8FoSd5dGLBY,1502
|
|
@@ -30,10 +31,10 @@ neverlib/vad/VAD_whisper.py,sha256=Hmk6l8quenr4cnnWre_3DNGJE9XHhwzUFpM-q27ZSCI,1
|
|
|
30
31
|
neverlib/vad/__init__.py,sha256=RePuPF-0sCRxxQk4l74A66CnA8fE7jRxWRhC0uiEzX4,557
|
|
31
32
|
neverlib/vad/class_get_speech.py,sha256=yIfGqvtsLCkDsOwS8HOGf9jZnt7WN5yMt_vgTAGrpnA,2078
|
|
32
33
|
neverlib/vad/class_vad.py,sha256=u5szyOHjDrLt3-OA4TKlGZu8R8nQ6t1znatNlYhPwsI,5216
|
|
33
|
-
neverlib/vad/utils.py,sha256=
|
|
34
|
+
neverlib/vad/utils.py,sha256=oHYIDnG_rCEJWbgvCBDQ2QQtuaKOPCcaF4AdwOZJkqI,1151
|
|
34
35
|
neverlib/wav_data/000_short.wav,sha256=3pVeI6yGfjiD2q1_A9F_mIEYQnUhp9AMjy-gR4TAqK8,210430
|
|
35
|
-
neverlib-0.
|
|
36
|
-
neverlib-0.
|
|
37
|
-
neverlib-0.
|
|
38
|
-
neverlib-0.
|
|
39
|
-
neverlib-0.
|
|
36
|
+
neverlib-0.2.0.dist-info/licenses/LICENSE,sha256=h-U7vhFdQhieyaNCiA_utrRNMk1rjfrBAUJVodgkfsw,1096
|
|
37
|
+
neverlib-0.2.0.dist-info/METADATA,sha256=tismKBKfAteFiKX8IzZLuTROG3plY0EXBCc9NhRZTQ8,2624
|
|
38
|
+
neverlib-0.2.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
|
39
|
+
neverlib-0.2.0.dist-info/top_level.txt,sha256=QqwYFuDiY_iFTz0Kx8av6zKCP_s4M5NiMTNsIXOy8Po,9
|
|
40
|
+
neverlib-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|