HoneyTian commited on
Commit
ae4888e
·
1 Parent(s): e83359a
.gitignore CHANGED
@@ -1,4 +1,5 @@
1
 
 
2
  .git/
3
  .idea/
4
 
 
1
 
2
+ .gradio/
3
  .git/
4
  .idea/
5
 
examples/jky_gender/step_1.py DELETED
@@ -1,53 +0,0 @@
1
- #!/usr/bin/python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- https://arxiv.org/abs/2306.16962
5
-
6
- https://huggingface.co/audeering/wav2vec2-large-robust-24-ft-age-gender
7
- """
8
- import argparse
9
-
10
- import pandas as pd
11
- import torch
12
- import torch.nn as nn
13
- import librosa
14
- from transformers import Wav2Vec2Processor
15
- from transformers.models.wav2vec2.modeling_wav2vec2 import Wav2Vec2Model, Wav2Vec2PreTrainedModel
16
-
17
- from project_settings import project_path
18
-
19
-
20
- def get_args():
21
- parser = argparse.ArgumentParser()
22
- parser.add_argument(
23
- "--model_path",
24
- # default=(project_path / "pretrained_models/wav2vec2-large-robust-6-ft-age-gender").as_posix(),
25
- default=(project_path / "pretrained_models/wav2vec2-large-robust-6-ft-age-gender").as_posix(),
26
- type=str,
27
- )
28
- parser.add_argument(
29
- "--task_file",
30
- default=(project_path / "examples/jky_gender/task_8.27开始+日本GMP营销永久任务.xlsx").as_posix(),
31
- type=str,
32
- )
33
- args = parser.parse_args()
34
- return args
35
-
36
-
37
- def main():
38
- args = get_args()
39
-
40
- df = pd.read_excel(args.task_file)
41
- for i, row in df.iterrows():
42
- task_name = row["任务名称"]
43
- bot_name = row["话术模版名称"]
44
- call_id = row["通话ID"]
45
- duration = row["通话时长"]
46
- intent_desc = row["意向标签"]
47
- record_url = row["录音地址"]
48
-
49
- return
50
-
51
-
52
- if __name__ == "__main__":
53
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
examples/jky_gender/step_1_predict_by_task.py ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ https://arxiv.org/abs/2306.16962
5
+
6
+ https://huggingface.co/audeering/wav2vec2-large-robust-24-ft-age-gender
7
+
8
+ 查看GPU
9
+ nvidia-smi
10
+ watch -n 1 -d nvidia-smi
11
+ """
12
+ import argparse
13
+ import json
14
+ import logging
15
+ import shutil
16
+ from pathlib import Path
17
+ from urllib.parse import urlparse
18
+
19
+ import numpy as np
20
+ from gradio_client import Client, handle_file
21
+ import pandas as pd
22
+ import requests
23
+ from tenacity import before_sleep_log, retry, retry_if_exception_type, stop_after_attempt, wait_fixed
24
+
25
+ import log
26
+ from project_settings import project_path, temp_directory, time_zone_info
27
+
28
+ log.setup_stream(tz_info=time_zone_info)
29
+
30
+ logger = logging.getLogger("main")
31
+
32
+
33
+ def get_args():
34
+ parser = argparse.ArgumentParser()
35
+ parser.add_argument(
36
+ "--task_file",
37
+ default=(project_path / "examples/jky_gender/task_8.27开始+日本GMP营销永久任务.xlsx").as_posix(),
38
+ type=str,
39
+ )
40
+ parser.add_argument(
41
+ "--raw_audio_dir",
42
+ default=(temp_directory / "raw_audio").as_posix(),
43
+ type=str,
44
+ )
45
+ parser.add_argument(
46
+ "--sub_audio_dir",
47
+ default=(temp_directory / "sub_audio").as_posix(),
48
+ type=str,
49
+ )
50
+ parser.add_argument(
51
+ "--concat_audio_dir",
52
+ default=(temp_directory / "concat_audio").as_posix(),
53
+ type=str,
54
+ )
55
+ parser.add_argument(
56
+ "--output_file",
57
+ default=(temp_directory / "age_and_gender/predict.jsonl").as_posix(),
58
+ type=str,
59
+ )
60
+ args = parser.parse_args()
61
+ return args
62
+
63
+
64
+ def get_audio_by_url(url: str, audio_dir: str) -> str:
65
+ audio_dir = Path(audio_dir)
66
+ audio_dir.mkdir(parents=True, exist_ok=True)
67
+
68
+ p = urlparse(url)
69
+ name = Path(p.path).name
70
+
71
+ filename = audio_dir / name
72
+ if not filename.exists():
73
+ response = requests.get(url)
74
+ with open(filename, "wb") as f:
75
+ f.write(response.content)
76
+
77
+ return filename.as_posix()
78
+
79
+
80
+ def retry_call(fn, *args, **kwargs):
81
+ @retry(
82
+ wait=wait_fixed(10),
83
+ stop=stop_after_attempt(3),
84
+ before_sleep=before_sleep_log(logger, logging.ERROR),
85
+ )
86
+ def wrapped():
87
+ return fn(*args, **kwargs)
88
+ return wrapped()
89
+
90
+
91
+ def main():
92
+ args = get_args()
93
+
94
+ raw_audio_dir = Path(args.raw_audio_dir)
95
+ raw_audio_dir.mkdir(parents=True, exist_ok=True)
96
+ sub_audio_dir = Path(args.sub_audio_dir)
97
+ sub_audio_dir.mkdir(parents=True, exist_ok=True)
98
+ concat_audio_dir = Path(args.concat_audio_dir)
99
+ concat_audio_dir.mkdir(parents=True, exist_ok=True)
100
+ output_file = Path(args.output_file)
101
+ output_file.parent.mkdir(parents=True, exist_ok=True)
102
+
103
+ # audio edit
104
+ client1 = Client("http://10.75.27.247:7861/")
105
+
106
+ # cc_audio_8
107
+ client2 = Client("http://10.75.27.247:7864/")
108
+
109
+ # age and gender
110
+ client3 = Client("http://10.75.27.247:7863/")
111
+
112
+ # finished
113
+ finished = set()
114
+ if output_file.exists():
115
+ with open(output_file.as_posix(), "r", encoding="utf-8") as f:
116
+ for row in f:
117
+ row = json.loads(row)
118
+ call_id = row["call_id"]
119
+ finished.add(call_id)
120
+ logger.info(f"finished count: {len(finished)}")
121
+
122
+ df = pd.read_excel(args.task_file)
123
+ with open(output_file.as_posix(), "a+", encoding="utf-8") as f:
124
+ for i, row in df.iterrows():
125
+ task_name = row["任务名称"]
126
+ bot_name = row["话术模版名称"]
127
+ call_id = row["通话ID"]
128
+ duration = row["通话时长(秒)"]
129
+ intent_desc = row["意向标签"]
130
+ record_url = row["录音地址"]
131
+ if pd.isna(record_url):
132
+ continue
133
+ if intent_desc in ["语音信箱"]:
134
+ continue
135
+
136
+ # download url
137
+ filename: str = retry_call(get_audio_by_url, record_url, audio_dir=raw_audio_dir.as_posix())
138
+ logger.info(f"finish download: {filename}")
139
+
140
+ filename, _, _, _ = retry_call(
141
+ client1.predict,
142
+ audio_t=handle_file(filename),
143
+ to_sample_rate=8000,
144
+ sample_width=2,
145
+ channels="0",
146
+ engine="librosa",
147
+ api_name="/when_click_audio_convert"
148
+ )
149
+ logger.info(f"finish convert: {filename}")
150
+
151
+ sub_audio_dataset = retry_call(
152
+ client2.predict,
153
+ audio_t=handle_file(filename),
154
+ model_name="sound-8-ch32",
155
+ label="voice",
156
+ win_size=2,
157
+ win_step=0.25,
158
+ n_erode=2,
159
+ n_dilate=2,
160
+ api_name="/when_click_split_button"
161
+ )
162
+ sub_audio_dataset = sub_audio_dataset["samples"]
163
+ logger.info(f"finish sub_audio_dataset, count: {len(sub_audio_dataset)}")
164
+ if len(sub_audio_dataset) == 0:
165
+ row = {
166
+ "task_name": task_name,
167
+ "bot_name": bot_name,
168
+ "call_id": call_id,
169
+ "duration": duration,
170
+ "intent_desc": intent_desc,
171
+ "record_url": record_url,
172
+ "label": "silence",
173
+ "prob": 1,
174
+ }
175
+ row = json.dumps(row, ensure_ascii=False)
176
+ f.write(f"{row}\n")
177
+ f.flush()
178
+ continue
179
+
180
+ sub_audio_dir_ = sub_audio_dir / call_id
181
+ sub_audio_dir_.mkdir(parents=True, exist_ok=True)
182
+ sub_filename_list = list()
183
+ for idx in range(len(sub_audio_dataset)):
184
+ sub_audio, _ = retry_call(
185
+ client2.predict,
186
+ x=idx,
187
+ api_name="/lambda"
188
+ )
189
+ sub_filename = (sub_audio_dir_ / f"{call_id}_{idx}.wav").as_posix()
190
+ shutil.move(sub_audio, sub_filename)
191
+ sub_filename_list.append(sub_filename)
192
+ logger.info(f"finish sub_filename_list: {sub_filename_list}")
193
+
194
+ concat_audio, _ = retry_call(
195
+ client1.predict,
196
+ files=[handle_file(item) for item in sub_filename_list],
197
+ api_name="/when_click_concat_audio"
198
+ )
199
+ concat_filename = (concat_audio_dir / f"{call_id}.wav").as_posix()
200
+ shutil.move(concat_audio, concat_filename)
201
+ logger.info(f"finish concat_filename: {concat_filename}")
202
+
203
+ logger.info(f"start get_age_and_gender: {concat_filename}")
204
+ js = retry_call(
205
+ client3.predict,
206
+ audio_t=handle_file(concat_filename),
207
+ engine="audeering-6-ft",
208
+ api_name="/when_click_get_age_and_gender_button"
209
+ )
210
+ js = json.loads(js)
211
+ logger.info(f"finish get_age_and_gender")
212
+
213
+ labels = ["female", "male", "child"]
214
+ probs = list()
215
+ for label in labels:
216
+ prob = js[label]
217
+ probs.append(prob)
218
+
219
+ index = np.argmax(probs)
220
+ label = labels[index]
221
+ prob = probs[index]
222
+ logger.info(f"finally predict label: {label}, prob: {prob}")
223
+
224
+ row = {
225
+ "task_name": task_name,
226
+ "bot_name": bot_name,
227
+ "call_id": call_id,
228
+ "duration": duration,
229
+ "intent_desc": intent_desc,
230
+ "record_url": record_url,
231
+ "label": label,
232
+ "prob": prob,
233
+ }
234
+ row = json.dumps(row, ensure_ascii=False)
235
+ f.write(f"{row}\n")
236
+ f.flush()
237
+
238
+ return
239
+
240
+
241
+ if __name__ == "__main__":
242
+ main()
examples/jky_gender/step_2_predict_by_concat_audio.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ https://arxiv.org/abs/2306.16962
5
+
6
+ https://huggingface.co/audeering/wav2vec2-large-robust-24-ft-age-gender
7
+
8
+ 查看GPU
9
+ nvidia-smi
10
+ watch -n 1 -d nvidia-smi
11
+ """
12
+ import argparse
13
+ import json
14
+ import logging
15
+ import shutil
16
+ from pathlib import Path
17
+ from urllib.parse import urlparse
18
+
19
+ import numpy as np
20
+ from gradio_client import Client, handle_file
21
+ import pandas as pd
22
+ import requests
23
+ from tenacity import before_sleep_log, retry, retry_if_exception_type, stop_after_attempt, wait_fixed
24
+
25
+ import log
26
+ from project_settings import project_path, temp_directory, time_zone_info
27
+
28
+ log.setup_stream(tz_info=time_zone_info)
29
+
30
+ logger = logging.getLogger("main")
31
+
32
+
33
+ def get_args():
34
+ parser = argparse.ArgumentParser()
35
+ parser.add_argument(
36
+ "--concat_audio_dir",
37
+ default=(temp_directory / "concat_audio").as_posix(),
38
+ type=str,
39
+ )
40
+ parser.add_argument(
41
+ "--output_file",
42
+ default=(temp_directory / "age_and_gender/predict-audeering-24-ft.jsonl").as_posix(),
43
+ type=str,
44
+ )
45
+ args = parser.parse_args()
46
+ return args
47
+
48
+
49
+ def get_audio_by_url(url: str, audio_dir: str) -> str:
50
+ audio_dir = Path(audio_dir)
51
+ audio_dir.mkdir(parents=True, exist_ok=True)
52
+
53
+ p = urlparse(url)
54
+ name = Path(p.path).name
55
+
56
+ filename = audio_dir / name
57
+ if not filename.exists():
58
+ response = requests.get(url)
59
+ with open(filename, "wb") as f:
60
+ f.write(response.content)
61
+
62
+ return filename.as_posix()
63
+
64
+
65
+ def retry_call(fn, *args, **kwargs):
66
+ @retry(
67
+ wait=wait_fixed(10),
68
+ stop=stop_after_attempt(3),
69
+ before_sleep=before_sleep_log(logger, logging.ERROR),
70
+ )
71
+ def wrapped():
72
+ return fn(*args, **kwargs)
73
+ return wrapped()
74
+
75
+
76
+ def main():
77
+ args = get_args()
78
+
79
+ concat_audio_dir = Path(args.concat_audio_dir)
80
+ output_file = Path(args.output_file)
81
+ output_file.parent.mkdir(parents=True, exist_ok=True)
82
+
83
+ # age and gender
84
+ client3 = Client("http://10.75.27.247:7863/")
85
+
86
+ # finished
87
+ finished = set()
88
+ if output_file.exists():
89
+ with open(output_file.as_posix(), "r", encoding="utf-8") as f:
90
+ for row in f:
91
+ row = json.loads(row)
92
+ call_id = row["call_id"]
93
+ finished.add(call_id)
94
+ logger.info(f"finished count: {len(finished)}")
95
+
96
+ with open(output_file.as_posix(), "a+", encoding="utf-8") as f:
97
+ for filename in concat_audio_dir.glob("*.wav"):
98
+ call_id = filename.stem
99
+
100
+ logger.info(f"start get_age_and_gender: {filename.as_posix()}")
101
+ js = retry_call(
102
+ client3.predict,
103
+ audio_t=handle_file(filename.as_posix()),
104
+ engine="audeering-24-ft",
105
+ api_name="/when_click_get_age_and_gender_button"
106
+ )
107
+ js = json.loads(js)
108
+ logger.info(f"finish get_age_and_gender")
109
+
110
+ labels = ["female", "male", "child"]
111
+ probs = list()
112
+ for label in labels:
113
+ prob = js[label]
114
+ probs.append(prob)
115
+
116
+ index = np.argmax(probs)
117
+ label = labels[index]
118
+ prob = probs[index]
119
+ logger.info(f"finally predict label: {label}, prob: {prob}")
120
+
121
+ row = {
122
+ "call_id": call_id,
123
+ "label": label,
124
+ "prob": prob,
125
+ }
126
+ row = json.dumps(row, ensure_ascii=False)
127
+ f.write(f"{row}\n")
128
+ f.flush()
129
+
130
+ return
131
+
132
+
133
+ if __name__ == "__main__":
134
+ main()
examples/jky_gender/step_3_make_excel.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ https://arxiv.org/abs/2306.16962
5
+
6
+ https://huggingface.co/audeering/wav2vec2-large-robust-24-ft-age-gender
7
+
8
+ 查看GPU
9
+ nvidia-smi
10
+ watch -n 1 -d nvidia-smi
11
+ """
12
+ import argparse
13
+ import json
14
+ import logging
15
+ import shutil
16
+ from pathlib import Path
17
+ from urllib.parse import urlparse
18
+
19
+ import numpy as np
20
+ from gradio_client import Client, handle_file
21
+ import pandas as pd
22
+ import requests
23
+ from tenacity import before_sleep_log, retry, retry_if_exception_type, stop_after_attempt, wait_fixed
24
+
25
+ import log
26
+ from project_settings import project_path, temp_directory, time_zone_info
27
+
28
+ log.setup_stream(tz_info=time_zone_info)
29
+
30
+ logger = logging.getLogger("main")
31
+
32
+
33
+ def get_args():
34
+ parser = argparse.ArgumentParser()
35
+ parser.add_argument(
36
+ "--jsonl_file",
37
+ default=(temp_directory / "age_and_gender/predict-audeering-24-ft.jsonl").as_posix(),
38
+ type=str,
39
+ )
40
+ parser.add_argument(
41
+ "--output_file",
42
+ default=(temp_directory / "age_and_gender/predict-audeering-24-ft.xlsx").as_posix(),
43
+ type=str,
44
+ )
45
+ args = parser.parse_args()
46
+ return args
47
+
48
+
49
+ def main():
50
+ args = get_args()
51
+
52
+ jsonl_file = Path(args.jsonl_file)
53
+ output_file = Path(args.output_file)
54
+ output_file.parent.mkdir(parents=True, exist_ok=True)
55
+
56
+ result = list()
57
+ with open(jsonl_file.as_posix(), "r", encoding="utf-8") as fin:
58
+ for row in fin:
59
+ row = json.loads(row)
60
+ result.append(row)
61
+
62
+ result = pd.DataFrame(result)
63
+ result.to_excel(output_file.as_posix(), index=False)
64
+ return
65
+
66
+
67
+ if __name__ == "__main__":
68
+ main()
log.py CHANGED
@@ -1,16 +1,67 @@
1
  #!/usr/bin/python3
2
  # -*- coding: utf-8 -*-
 
3
  import logging
4
  from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
5
  import os
 
6
 
7
 
8
- def setup_size_rotating(log_directory: str):
9
- fmt = "%(asctime)s - %(name)s - %(levelname)s %(filename)s:%(lineno)d > %(message)s"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  stream_handler = logging.StreamHandler()
12
  stream_handler.setLevel(logging.INFO)
13
- stream_handler.setFormatter(logging.Formatter(fmt))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  # main
16
  main_logger = logging.getLogger("main")
@@ -22,11 +73,12 @@ def setup_size_rotating(log_directory: str):
22
  backupCount=2,
23
  )
24
  main_info_file_handler.setLevel(logging.INFO)
25
- main_info_file_handler.setFormatter(logging.Formatter(fmt))
26
  main_logger.addHandler(main_info_file_handler)
27
 
28
  # http
29
  http_logger = logging.getLogger("http")
 
30
  http_file_handler = RotatingFileHandler(
31
  filename=os.path.join(log_directory, "http.log"),
32
  maxBytes=100*1024*1024, # 100MB
@@ -34,11 +86,12 @@ def setup_size_rotating(log_directory: str):
34
  backupCount=2,
35
  )
36
  http_file_handler.setLevel(logging.DEBUG)
37
- http_file_handler.setFormatter(logging.Formatter(fmt))
38
  http_logger.addHandler(http_file_handler)
39
 
40
  # api
41
  api_logger = logging.getLogger("api")
 
42
  api_file_handler = RotatingFileHandler(
43
  filename=os.path.join(log_directory, "api.log"),
44
  maxBytes=10*1024*1024, # 10MB
@@ -46,22 +99,9 @@ def setup_size_rotating(log_directory: str):
46
  backupCount=2,
47
  )
48
  api_file_handler.setLevel(logging.DEBUG)
49
- api_file_handler.setFormatter(logging.Formatter(fmt))
50
  api_logger.addHandler(api_file_handler)
51
 
52
- # toolbox
53
- toolbox_logger = logging.getLogger("toolbox")
54
- toolbox_logger.addHandler(stream_handler)
55
- toolbox_file_handler = RotatingFileHandler(
56
- filename=os.path.join(log_directory, "toolbox.log"),
57
- maxBytes=10*1024*1024, # 10MB
58
- encoding="utf-8",
59
- backupCount=2,
60
- )
61
- toolbox_file_handler.setLevel(logging.DEBUG)
62
- toolbox_file_handler.setFormatter(logging.Formatter(fmt))
63
- toolbox_logger.addHandler(toolbox_file_handler)
64
-
65
  # alarm
66
  alarm_logger = logging.getLogger("alarm")
67
  alarm_file_handler = RotatingFileHandler(
@@ -71,7 +111,7 @@ def setup_size_rotating(log_directory: str):
71
  backupCount=2,
72
  )
73
  alarm_file_handler.setLevel(logging.DEBUG)
74
- alarm_file_handler.setFormatter(logging.Formatter(fmt))
75
  alarm_logger.addHandler(alarm_file_handler)
76
 
77
  debug_file_handler = RotatingFileHandler(
@@ -81,7 +121,7 @@ def setup_size_rotating(log_directory: str):
81
  backupCount=2,
82
  )
83
  debug_file_handler.setLevel(logging.DEBUG)
84
- debug_file_handler.setFormatter(logging.Formatter(fmt))
85
 
86
  info_file_handler = RotatingFileHandler(
87
  filename=os.path.join(log_directory, "info.log"),
@@ -90,7 +130,7 @@ def setup_size_rotating(log_directory: str):
90
  backupCount=2,
91
  )
92
  info_file_handler.setLevel(logging.INFO)
93
- info_file_handler.setFormatter(logging.Formatter(fmt))
94
 
95
  error_file_handler = RotatingFileHandler(
96
  filename=os.path.join(log_directory, "error.log"),
@@ -99,7 +139,7 @@ def setup_size_rotating(log_directory: str):
99
  backupCount=2,
100
  )
101
  error_file_handler.setLevel(logging.ERROR)
102
- error_file_handler.setFormatter(logging.Formatter(fmt))
103
 
104
  logging.basicConfig(
105
  level=logging.DEBUG,
@@ -159,18 +199,6 @@ def setup_time_rotating(log_directory: str):
159
  api_file_handler.setFormatter(logging.Formatter(fmt))
160
  api_logger.addHandler(api_file_handler)
161
 
162
- # toolbox
163
- toolbox_logger = logging.getLogger("toolbox")
164
- toolbox_file_handler = RotatingFileHandler(
165
- filename=os.path.join(log_directory, "toolbox.log"),
166
- maxBytes=10*1024*1024, # 10MB
167
- encoding="utf-8",
168
- backupCount=2,
169
- )
170
- toolbox_file_handler.setLevel(logging.DEBUG)
171
- toolbox_file_handler.setFormatter(logging.Formatter(fmt))
172
- toolbox_logger.addHandler(toolbox_file_handler)
173
-
174
  # alarm
175
  alarm_logger = logging.getLogger("alarm")
176
  alarm_file_handler = TimedRotatingFileHandler(
 
1
  #!/usr/bin/python3
2
  # -*- coding: utf-8 -*-
3
+ from datetime import datetime
4
  import logging
5
  from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
6
  import os
7
+ from zoneinfo import ZoneInfo # Python 3.9+ 自带,无需安装
8
 
9
 
10
+ def get_converter(tz_info: str = "Asia/Shanghai"):
11
+ def converter(timestamp):
12
+ dt = datetime.fromtimestamp(timestamp, ZoneInfo(tz_info))
13
+ result = dt.timetuple()
14
+ return result
15
+ return converter
16
+
17
+
18
+ def setup_stream(tz_info: str = "Asia/Shanghai"):
19
+ fmt = "%(asctime)s|%(name)s|%(levelname)s|%(filename)s|%(lineno)d|%(message)s"
20
+
21
+ formatter = logging.Formatter(
22
+ fmt=fmt,
23
+ datefmt="%Y-%m-%d %H:%M:%S %z"
24
+ )
25
+ formatter.converter = get_converter(tz_info)
26
 
27
  stream_handler = logging.StreamHandler()
28
  stream_handler.setLevel(logging.INFO)
29
+ stream_handler.setFormatter(formatter)
30
+
31
+ # main
32
+ main_logger = logging.getLogger("main")
33
+ main_logger.addHandler(stream_handler)
34
+
35
+ # http
36
+ http_logger = logging.getLogger("http")
37
+ http_logger.addHandler(stream_handler)
38
+
39
+ # api
40
+ api_logger = logging.getLogger("api")
41
+ api_logger.addHandler(stream_handler)
42
+
43
+ logging.basicConfig(
44
+ level=logging.DEBUG,
45
+ datefmt="%a, %d %b %Y %H:%M:%S",
46
+ handlers=[
47
+
48
+ ]
49
+ )
50
+ return
51
+
52
+
53
+ def setup_size_rotating(log_directory: str, tz_info: str = "Asia/Shanghai"):
54
+ fmt = "%(asctime)s|%(name)s|%(levelname)s|%(filename)s|%(lineno)d|%(message)s"
55
+
56
+ formatter = logging.Formatter(
57
+ fmt=fmt,
58
+ datefmt="%Y-%m-%d %H:%M:%S %z"
59
+ )
60
+ formatter.converter = get_converter(tz_info)
61
+
62
+ stream_handler = logging.StreamHandler()
63
+ stream_handler.setLevel(logging.INFO)
64
+ stream_handler.setFormatter(formatter)
65
 
66
  # main
67
  main_logger = logging.getLogger("main")
 
73
  backupCount=2,
74
  )
75
  main_info_file_handler.setLevel(logging.INFO)
76
+ main_info_file_handler.setFormatter(formatter)
77
  main_logger.addHandler(main_info_file_handler)
78
 
79
  # http
80
  http_logger = logging.getLogger("http")
81
+ http_logger.addHandler(stream_handler)
82
  http_file_handler = RotatingFileHandler(
83
  filename=os.path.join(log_directory, "http.log"),
84
  maxBytes=100*1024*1024, # 100MB
 
86
  backupCount=2,
87
  )
88
  http_file_handler.setLevel(logging.DEBUG)
89
+ http_file_handler.setFormatter(formatter)
90
  http_logger.addHandler(http_file_handler)
91
 
92
  # api
93
  api_logger = logging.getLogger("api")
94
+ api_logger.addHandler(stream_handler)
95
  api_file_handler = RotatingFileHandler(
96
  filename=os.path.join(log_directory, "api.log"),
97
  maxBytes=10*1024*1024, # 10MB
 
99
  backupCount=2,
100
  )
101
  api_file_handler.setLevel(logging.DEBUG)
102
+ api_file_handler.setFormatter(formatter)
103
  api_logger.addHandler(api_file_handler)
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  # alarm
106
  alarm_logger = logging.getLogger("alarm")
107
  alarm_file_handler = RotatingFileHandler(
 
111
  backupCount=2,
112
  )
113
  alarm_file_handler.setLevel(logging.DEBUG)
114
+ alarm_file_handler.setFormatter(formatter)
115
  alarm_logger.addHandler(alarm_file_handler)
116
 
117
  debug_file_handler = RotatingFileHandler(
 
121
  backupCount=2,
122
  )
123
  debug_file_handler.setLevel(logging.DEBUG)
124
+ debug_file_handler.setFormatter(formatter)
125
 
126
  info_file_handler = RotatingFileHandler(
127
  filename=os.path.join(log_directory, "info.log"),
 
130
  backupCount=2,
131
  )
132
  info_file_handler.setLevel(logging.INFO)
133
+ info_file_handler.setFormatter(formatter)
134
 
135
  error_file_handler = RotatingFileHandler(
136
  filename=os.path.join(log_directory, "error.log"),
 
139
  backupCount=2,
140
  )
141
  error_file_handler.setLevel(logging.ERROR)
142
+ error_file_handler.setFormatter(formatter)
143
 
144
  logging.basicConfig(
145
  level=logging.DEBUG,
 
199
  api_file_handler.setFormatter(logging.Formatter(fmt))
200
  api_logger.addHandler(api_file_handler)
201
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  # alarm
203
  alarm_logger = logging.getLogger("alarm")
204
  alarm_file_handler = TimedRotatingFileHandler(
main.py CHANGED
@@ -8,8 +8,7 @@ docker run -itd \
8
  --restart=always \
9
  --network host \
10
  -e server_port=7865 \
11
- denoise:v20250828_1030 /bin/bash
12
-
13
 
14
  docker run -itd \
15
  --name speech_age_and_gender_7863 \
@@ -17,20 +16,9 @@ docker run -itd \
17
  --gpus all \
18
  --privileged \
19
  --ipc=host \
20
- -v /data/tianxing/HuggingDatasets/nx_noise/data:/data/tianxing/HuggingDatasets/nx_noise/data \
21
- -v /data/tianxing/PycharmProjects/cc_vad:/data/tianxing/PycharmProjects/cc_vad \
22
  python:3.12 /bin/bash
23
 
24
-
25
- docker run -itd \
26
- --name speech_age_and_gender_7863 \
27
- --network host \
28
- --gpus all \
29
- --privileged \
30
- --ipc=host \
31
- python:3.12 /bin/bash
32
-
33
-
34
  """
35
  import argparse
36
  from functools import lru_cache
@@ -51,6 +39,7 @@ import log
51
  from project_settings import environment, project_path, log_directory
52
  from toolbox.os.command import Command
53
  from toolbox.age_and_gender.models.audeering import AudeeringModel
 
54
 
55
  log.setup_size_rotating(log_directory=log_directory)
56
 
@@ -109,6 +98,15 @@ age_and_gender_model_map = {
109
  },
110
  "sample_rate": 16000,
111
  },
 
 
 
 
 
 
 
 
 
112
  }
113
 
114
 
@@ -139,7 +137,6 @@ def when_click_get_age_and_gender_button(audio_t, engine: str):
139
 
140
  infer_engine = load_get_age_and_gender_model(infer_cls=infer_cls, **kwargs)
141
 
142
-
143
  time_begin = time.time()
144
  age_and_gender = infer_engine.__call__(signal, sample_rate)
145
  time_cost = time.time() - time_begin
 
8
  --restart=always \
9
  --network host \
10
  -e server_port=7865 \
11
+ speech_age_and_gender:v20250828_1030 /bin/bash
 
12
 
13
  docker run -itd \
14
  --name speech_age_and_gender_7863 \
 
16
  --gpus all \
17
  --privileged \
18
  --ipc=host \
 
 
19
  python:3.12 /bin/bash
20
 
21
+ nohup python3 main.py --server_port 7863 &
 
 
 
 
 
 
 
 
 
22
  """
23
  import argparse
24
  from functools import lru_cache
 
39
  from project_settings import environment, project_path, log_directory
40
  from toolbox.os.command import Command
41
  from toolbox.age_and_gender.models.audeering import AudeeringModel
42
+ from toolbox.age_and_gender.models.common_voice import CommonVoiceGenderModel
43
 
44
  log.setup_size_rotating(log_directory=log_directory)
45
 
 
98
  },
99
  "sample_rate": 16000,
100
  },
101
+ "common_voice_gender_detection": {
102
+ "infer_cls": CommonVoiceGenderModel,
103
+ "kwargs": {
104
+ "model_path":
105
+ (project_path / "pretrained_models/Common-Voice-Gender-Detection").as_posix()
106
+ if platform.system() == "Windows" else "prithivMLmods/Common-Voice-Gender-Detection",
107
+ },
108
+ "sample_rate": 16000,
109
+ },
110
  }
111
 
112
 
 
137
 
138
  infer_engine = load_get_age_and_gender_model(infer_cls=infer_cls, **kwargs)
139
 
 
140
  time_begin = time.time()
141
  age_and_gender = infer_engine.__call__(signal, sample_rate)
142
  time_cost = time.time() - time_begin
project_settings.py CHANGED
@@ -9,9 +9,14 @@ from toolbox.os.environment import EnvironmentManager
9
  project_path = os.path.abspath(os.path.dirname(__file__))
10
  project_path = Path(project_path)
11
 
 
 
12
  log_directory = project_path / "logs"
13
  log_directory.mkdir(parents=True, exist_ok=True)
14
 
 
 
 
15
  environment = EnvironmentManager(
16
  path=os.path.join(project_path, "dotenv"),
17
  env=os.environ.get("environment", "dev"),
 
9
  project_path = os.path.abspath(os.path.dirname(__file__))
10
  project_path = Path(project_path)
11
 
12
+ time_zone_info = "Asia/Shanghai"
13
+
14
  log_directory = project_path / "logs"
15
  log_directory.mkdir(parents=True, exist_ok=True)
16
 
17
+ temp_directory = project_path / "temp"
18
+ temp_directory.mkdir(parents=True, exist_ok=True)
19
+
20
  environment = EnvironmentManager(
21
  path=os.path.join(project_path, "dotenv"),
22
  env=os.environ.get("environment", "dev"),
requirements.txt CHANGED
@@ -7,3 +7,4 @@ librosa
7
  python-dotenv
8
  pandas
9
  openpyxl
 
 
7
  python-dotenv
8
  pandas
9
  openpyxl
10
+ tenacity
toolbox/age_and_gender/models/common_voice.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python3
2
+ # -*- coding: utf-8 -*-
3
+ import argparse
4
+
5
+ import numpy as np
6
+ import torch
7
+ import torch.nn as nn
8
+ import librosa
9
+ from transformers import Wav2Vec2Processor
10
+ from transformers.models.wav2vec2.modeling_wav2vec2 import Wav2Vec2Model, Wav2Vec2PreTrainedModel
11
+ from transformers import Wav2Vec2ForSequenceClassification, Wav2Vec2FeatureExtractor
12
+
13
+ from project_settings import project_path
14
+
15
+
16
+ class CommonVoiceGenderModel(object):
17
+ def __init__(self, model_path: str):
18
+ self.model_path = model_path
19
+
20
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
21
+
22
+ processor = Wav2Vec2FeatureExtractor.from_pretrained(self.model_path)
23
+ model = Wav2Vec2ForSequenceClassification.from_pretrained(self.model_path).to(device)
24
+ model.eval()
25
+
26
+ self.device = device
27
+ self.processor = processor
28
+ self.model = model
29
+
30
+ def predict(self, signal: np.ndarray, sample_rate: int) -> dict:
31
+ y = self.processor.__call__(signal, sampling_rate=sample_rate)
32
+ print(f"y: {y}")
33
+ y = y["input_values"][0]
34
+ y = y.reshape(1, -1)
35
+ y = torch.from_numpy(y).to(self.device)
36
+
37
+ _, age, gender = self.model.forward(y)
38
+
39
+ gender = gender.detach().cpu().numpy().tolist()
40
+ gender = gender[0]
41
+
42
+ result = {
43
+ "age": round(age, 4),
44
+ "female": round(gender[0], 4),
45
+ "male": round(gender[1], 4),
46
+ "child": round(gender[2], 4),
47
+ }
48
+ return result
49
+
50
+ def __call__(self, *args, **kwargs):
51
+ return self.predict(*args, **kwargs)
52
+
53
+
54
+ if __name__ == "__main__":
55
+ pass