Choultion-Rudas commited on
Commit
cd66ae0
·
verified ·
1 Parent(s): 55e806a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -151
app.py CHANGED
@@ -2,82 +2,22 @@ import gradio as gr
2
  import numpy as np
3
  import torch
4
  import torchaudio
 
5
  from funasr import AutoModel
6
 
7
- print("正在加载SenseVoice-Small模型,请稍候...")
8
  model = AutoModel(
9
  model="iic/SenseVoiceSmall",
10
  vad_model="iic/speech_fsmn_vad_zh-cn-16k-common-pytorch",
11
  vad_kwargs={"max_single_segment_time": 30000},
12
  trust_remote_code=True,
13
  )
14
- print("模型加载成功!")
15
-
16
- emo_dict = {
17
- "<|HAPPY|>": "😊",
18
- "<|SAD|>": "😔",
19
- "<|ANGRY|>": "😡",
20
- "<|NEUTRAL|>": "",
21
- "<|FEARFUL|>": "😰",
22
- "<|DISGUSTED|>": "🤢",
23
- "<|SURPRISED|>": "😮",
24
- }
25
-
26
- event_dict = {
27
- "<|BGM|>": "🎼",
28
- "<|Speech|>": "",
29
- "<|Applause|>": "👏",
30
- "<|Laughter|>": "😀",
31
- "<|Cry|>": "😭",
32
- "<|Sneeze|>": "🤧",
33
- "<|Breath|>": "",
34
- "<|Cough|>": "🤧",
35
- }
36
-
37
- emoji_dict = {
38
- "<|nospeech|><|Event_UNK|>": "❓",
39
- "<|zh|>": "",
40
- "<|en|>": "",
41
- "<|yue|>": "",
42
- "<|ja|>": "",
43
- "<|ko|>": "",
44
- "<|nospeech|>": "",
45
- "<|HAPPY|>": "😊",
46
- "<|SAD|>": "😔",
47
- "<|ANGRY|>": "😡",
48
- "<|NEUTRAL|>": "",
49
- "<|BGM|>": "🎼",
50
- "<|Speech|>": "",
51
- "<|Applause|>": "👏",
52
- "<|Laughter|>": "😀",
53
- "<|FEARFUL|>": "😰",
54
- "<|DISGUSTED|>": "🤢",
55
- "<|SURPRISED|>": "😮",
56
- "<|Cry|>": "😭",
57
- "<|EMO_UNKNOWN|>": "",
58
- "<|Sneeze|>": "🤧",
59
- "<|Breath|>": "",
60
- "<|Cough|>": "😷",
61
- "<|Sing|>": "",
62
- "<|Speech_Noise|>": "",
63
- "<|withitn|>": "",
64
- "<|woitn|>": "",
65
- "<|GBG|>": "",
66
- "<|Event_UNK|>": "",
67
- }
68
-
69
- lang_dict = {
70
- "<|zh|>": "<|lang|>",
71
- "<|en|>": "<|lang|>",
72
- "<|yue|>": "<|lang|>",
73
- "<|ja|>": "<|lang|>",
74
- "<|ko|>": "<|lang|>",
75
- "<|nospeech|>": "<|lang|>",
76
- }
77
 
 
 
 
 
78
  emo_set = {"😊", "😔", "😡", "😰", "🤢", "😮"}
79
- event_set = {"🎼", "👏", "😀", "😭", "🤧", "😷"}
80
-
81
 
82
  def format_str_v2(s):
83
  sptk_dict = {}
@@ -86,115 +26,79 @@ def format_str_v2(s):
86
  s = s.replace(sptk, "")
87
  emo = "<|NEUTRAL|>"
88
  for e in emo_dict:
89
- if sptk_dict.get(e, 0) > sptk_dict.get(emo, 0):
90
- emo = e
91
  for e in event_dict:
92
- if sptk_dict.get(e, 0) > 0:
93
- s = event_dict[e] + s
94
  s = s + emo_dict.get(emo, "")
95
-
96
  for emoji in emo_set.union(event_set):
97
- s = s.replace(" " + emoji, emoji)
98
- s = s.replace(emoji + " ", emoji)
99
  return s.strip()
100
 
101
-
102
  def format_str_v3(s):
103
- def get_emo(s):
104
- return s[-1] if s and s[-1] in emo_set else None
105
-
106
- def get_event(s):
107
- return s[0] if s and s[0] in event_set else None
108
-
109
  s = s.replace("<|nospeech|><|Event_UNK|>", "❓")
110
- for lang in lang_dict:
111
- s = s.replace(lang, "<|lang|>")
112
  s_list = [format_str_v2(s_i).strip(" ") for s_i in s.split("<|lang|>")]
113
  new_s = " " + (s_list[0] if s_list else "")
114
  cur_ent_event = get_event(new_s)
115
  for i in range(1, len(s_list)):
116
- if not s_list[i]:
117
- continue
118
- if get_event(s_list[i]) == cur_ent_event and cur_ent_event is not None:
119
- s_list[i] = s_list[i][1:]
120
  cur_ent_event = get_event(s_list[i])
121
- if get_emo(s_list[i]) is not None and get_emo(s_list[i]) == get_emo(new_s):
122
- new_s = new_s[:-1]
123
  new_s += s_list[i].strip().lstrip()
124
- new_s = new_s.replace("The.", " ")
125
  return new_s.strip()
126
 
127
-
128
- def model_inference(audio_input, language):
129
- if audio_input is None:
130
- return "错误:请先上传或录制音频。"
131
-
132
  fs, input_wav = audio_input
133
- input_wav = input_wav.astype(np.float32) / 32768.0
134
-
135
- if len(input_wav.shape) > 1:
136
- input_wav = input_wav.mean(-1)
137
-
138
  if fs != 16000:
139
- print(f"音频采样率不是16k,正在重采样: {fs}")
140
  resampler = torchaudio.transforms.Resample(orig_freq=fs, new_freq=16000)
141
  input_wav = resampler(torch.from_numpy(input_wav)).numpy()
142
-
143
- print(f"开始识别... 语言: {language}")
144
-
145
- res = model.generate(
146
- input=input_wav,
147
- cache={},
148
- language=language,
149
- use_itn=True,
150
- batch_size_s=60,
151
- merge_vad=True,
152
- )
153
-
154
  raw_text = res[0].get("text", "未能识别出文本。")
155
- print(f"原始输出: {raw_text}")
156
-
157
- # 使用格式化函数处理文本
158
- formatted_text = format_str_v3(raw_text)
159
- print(f"格式化输出: {formatted_text}")
160
-
161
- return formatted_text
162
-
163
-
164
- html_content = """
165
- <div style="text-align: center;">
166
- <h2 style="font-size: 22px;">语音理解模型: SenseVoice-Small</h2>
167
- <p style="font-size: 16px;">
168
- 这是一个部署在Hugging Face上的SenseVoice-Small语音识别模型。<br>
169
- 它支持中、英、粤、日、韩等多语言识别,并能识别情感和声音事件。
170
- </p>
171
- <p style="font-size: 16px;">
172
- <b>用法:</b> 上传音频或使用麦克风录音,在下方“配置”中选择识别语言,然后点击“开始”。
173
- </p>
174
  </div>
175
  """
176
 
177
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
178
- gr.HTML(html_content)
179
 
 
 
180
  with gr.Row():
181
- with gr.Column():
182
- audio_inputs = gr.Audio(label="上传音频或使用麦克风录音")
183
-
184
- with gr.Accordion("配置", open=True):
185
- language_inputs = gr.Dropdown(
186
- choices=["auto", "zh", "en", "yue", "ja", "ko", "nospeech"],
187
- value="auto",
188
- label="选择语言 (Select Language)",
189
- )
190
-
191
  fn_button = gr.Button("开始识别", variant="primary")
 
 
 
 
192
 
193
- with gr.Row():
194
- text_outputs = gr.Textbox(label="识别结果", lines=20)
195
-
196
- fn_button.click(
197
- fn=model_inference, inputs=[audio_inputs, language_inputs], outputs=text_outputs
198
- )
199
-
200
- demo.launch()
 
2
  import numpy as np
3
  import torch
4
  import torchaudio
5
+ import re
6
  from funasr import AutoModel
7
 
 
8
  model = AutoModel(
9
  model="iic/SenseVoiceSmall",
10
  vad_model="iic/speech_fsmn_vad_zh-cn-16k-common-pytorch",
11
  vad_kwargs={"max_single_segment_time": 30000},
12
  trust_remote_code=True,
13
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ emo_dict = {"<|HAPPY|>":"😊", "<|SAD|>":"😔", "<|ANGRY|>":"😡", "<|NEUTRAL|>":"", "<|FEARFUL|>":"😰", "<|DISGUSTED|>":"🤢", "<|SURPRISED|>":"😮"}
16
+ event_dict = {"<|BGM|>":"🎼", "<|Speech|>":"", "<|Applause|>":"👏", "<|Laughter|>":"😀", "<|Cry|>":"😭", "<|Sneeze|>":"🤧", "<|Breath|>":"", "<|Cough|>":"🤧"}
17
+ emoji_dict = {"<|nospeech|><|Event_UNK|>":"❓", "<|zh|>":"", "<|en|>":"", "<|yue|>":"", "<|ja|>":"", "<|ko|>":"", "<|nospeech|>":"", "<|HAPPY|>":"😊", "<|SAD|>":"😔", "<|ANGRY|>":"😡", "<|NEUTRAL|>":"", "<|BGM|>":"🎼", "<|Speech|>":"", "<|Applause|>":"👏", "<|Laughter|>":"😀", "<|FEARFUL|>":"😰", "<|DISGUSTED|>":"🤢", "<|SURPRISED|>":"😮", "<|Cry|>":"😭", "<|EMO_UNKNOWN|>":"", "<|Sneeze|>":"🤧", "<|Breath|>":"", "<|Cough|>":"😷", "<|Sing|>":"", "<|Speech_Noise|>":"", "<|withitn|>":"", "<|woitn|>":"", "<|GBG|>":"", "<|Event_UNK|>":""}
18
+ lang_dict = {"<|zh|>":"<|lang|>", "<|en|>":"<|lang|>", "<|yue|>":"<|lang|>", "<|ja|>":"<|lang|>", "<|ko|>":"<|lang|>", "<|nospeech|>":"<|lang|>"}
19
  emo_set = {"😊", "😔", "😡", "😰", "🤢", "😮"}
20
+ event_set = = {"🎼", "👏", "😀", "😭", "🤧", "😷"}
 
21
 
22
  def format_str_v2(s):
23
  sptk_dict = {}
 
26
  s = s.replace(sptk, "")
27
  emo = "<|NEUTRAL|>"
28
  for e in emo_dict:
29
+ if sptk_dict.get(e, 0) > sptk_dict.get(emo, 0): emo = e
 
30
  for e in event_dict:
31
+ if sptk_dict.get(e, 0) > 0: s = event_dict[e] + s
 
32
  s = s + emo_dict.get(emo, "")
 
33
  for emoji in emo_set.union(event_set):
34
+ s = s.replace(" " + emoji, emoji).replace(emoji + " ", emoji)
 
35
  return s.strip()
36
 
 
37
  def format_str_v3(s):
38
+ def get_emo(s): return s[-1] if s and s[-1] in emo_set else None
39
+ def get_event(s): return s[0] if s and s[0] in event_set else None
 
 
 
 
40
  s = s.replace("<|nospeech|><|Event_UNK|>", "❓")
41
+ for lang in lang_dict: s = s.replace(lang, "<|lang|>")
 
42
  s_list = [format_str_v2(s_i).strip(" ") for s_i in s.split("<|lang|>")]
43
  new_s = " " + (s_list[0] if s_list else "")
44
  cur_ent_event = get_event(new_s)
45
  for i in range(1, len(s_list)):
46
+ if not s_list[i]: continue
47
+ if get_event(s_list[i]) == cur_ent_event and cur_ent_event is not None: s_list[i] = s_list[i][1:]
 
 
48
  cur_ent_event = get_event(s_list[i])
49
+ if get_emo(s_list[i]) is not None and get_emo(s_list[i]) == get_emo(new_s): new_s = new_s[:-1]
 
50
  new_s += s_list[i].strip().lstrip()
 
51
  return new_s.strip()
52
 
53
+ def model_inference(audio_input, language, output_format, use_itn, merge_vad, merge_length, ban_emo_unk):
54
+ if audio_input is None: return "错误:请上传或录制音频。"
 
 
 
55
  fs, input_wav = audio_input
56
+ input_wav = input_wav.astype(np.float32) / np.iinfo(np.int16).max
57
+ if len(input_wav.shape) > 1: input_wav = input_wav.mean(-1)
 
 
 
58
  if fs != 16000:
 
59
  resampler = torchaudio.transforms.Resample(orig_freq=fs, new_freq=16000)
60
  input_wav = resampler(torch.from_numpy(input_wav)).numpy()
61
+ res = model.generate(input=input_wav, cache={}, language=language, use_itn=use_itn, batch_size_s=60, merge_vad=merge_vad, merge_length_s=merge_length, ban_emo_unk=ban_emo_unk)
 
 
 
 
 
 
 
 
 
 
 
62
  raw_text = res[0].get("text", "未能识别出文本。")
63
+ if output_format == "原始富文本": return raw_text
64
+ elif output_format == "纯净文本": return ' '.join(re.sub(r'<\|[^>]*>', '', raw_text).split())
65
+ else: return format_str_v3(raw_text)
66
+
67
+ html_intro = """
68
+ <div>
69
+ <h2 style="font-size: 22px;margin-left: 0px;">语音理解模型: SenseVoice-Small</h2>
70
+ <p style="font-size: 18px;margin-left: 20px;">
71
+ SenseVoice-Small 是一种仅包含编码器的语音基础模型,专为快速语音理解而设计。它包含多种功能,包括自动语音识别 (ASR)、口语识别 (LID)、语音情感识别 (SER) 和声学事件检测 (AED)。 SenseVoice-Small支持中文、英语、粤语、日语、韩语等多语言识别。此外,它还提供极低的推理延迟,执行速度比 Whisper-small 快 7 倍,比 Whisper-large 快 17 倍。</p>
72
+ <h2 style="font-size: 22px;margin-left: 0px;">用法</h2> <p style="font-size: 18px;margin-left: 20px;">上传音频文件或通过麦克风输入,然后选择任务和语言。音频被转录成相应的文本以及相关的情绪(😊快乐,😡愤怒/兴奋,😔悲伤)和声音事件类型(😀笑声,🎼音乐,👏掌声,🤧咳嗽和打喷嚏,😔哭泣)。事件标签放在文本的前面,情感放在文本的后面。</p>
73
+ <h2 style="font-size: 22px;margin-left: 0px;">目录</h2>
74
+ <p style="font-size: 18px;margin-left: 20px;"><a href="https://github.com/FunAudioLLM/SenseVoice" target="_blank">SenseVoice</a>:多语言语音理解模型</p>
75
+ <p style="font-size: 18px;margin-left: 20px;"><a href="https://github.com/modelscope/FunASR" target="_blank">FunASR</a>:基本语音识别工具包</p>
76
+ <p style="font-size: 18px;margin-left: 20px;"><a href="https://github.com/FunAudioLLM/CosyVoice" target="_blank">CosyVoice</a>:高质量多语言TTS模型</p>
77
+ </div>
78
+ <div style="text-align: center; font-size: 15px; font-weight: bold; color: red; margin-bottom: 20px;">
79
+ ⚠️ 该演示仅供学术研究和体验使用。
 
 
80
  </div>
81
  """
82
 
83
+ lang_options = [("自动检测", "auto"), ("中文", "zh"), ("English", "en"), ("粤语", "yue"), ("日本語", "ja"), ("한국어", "ko"), ("无语音", "nospeech")]
84
+ example_list = [[f"{model.model_path}/example/zh.mp3", "auto"], [f"{model.model_path}/example/en.mp3", "auto"], [f"{model.model_path}/example/yue.mp3", "auto"], [f"{model.model_path}/example/ja.mp3", "auto"], [f"{model.model_path}/example/ko.mp3", "auto"], [f"{model.model_path}/example/rich_1.wav", "auto"], [f"{model.model_path}/example/rich_2.wav", "auto"], [f"{model.model_path}/example/longwav_1.wav", "auto"]]
85
 
86
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
87
+ gr.HTML(html_intro)
88
  with gr.Row():
89
+ with gr.Column(scale=2):
90
+ audio_inputs = gr.Audio(label="上传音频或使用麦克风")
91
+ with gr.Accordion("高级设置", open=False):
92
+ output_format_dropdown = gr.Dropdown(choices=["Emoji格式化", "纯净文本", "原始富文本"], value="Emoji格式化", label="选择输出格式")
93
+ language_inputs = gr.Dropdown(choices=lang_options, value="auto", label="识别语言")
94
+ use_itn_checkbox = gr.Checkbox(value=True, label="启用标点和逆文本正规化")
95
+ merge_vad_checkbox = gr.Checkbox(value=True, label="合并VAD切分的音频片段")
96
+ merge_length_slider = gr.Slider(minimum=5, maximum=30, value=15, step=1, label="合并后片段最大长度(秒)")
97
+ ban_emo_unk_checkbox = gr.Checkbox(value=False, label="禁用未知情感标签")
 
98
  fn_button = gr.Button("开始识别", variant="primary")
99
+ with gr.Column(scale=3):
100
+ text_outputs = gr.Textbox(label="识别结果", lines=20)
101
+ gr.Examples(examples=example_list, inputs=[audio_inputs, language_inputs], label="示例音频 (点击即可试用)")
102
+ fn_button.click(fn=model_inference, inputs=[audio_inputs, language_inputs, output_format_dropdown, use_itn_checkbox, merge_vad_checkbox, merge_length_slider, ban_emo_unk_checkbox], outputs=text_outputs)
103
 
104
+ demo.launch()