Polyphase resampling (no aliasing); n_perm switch for tests
Browse files
app.py
CHANGED
|
@@ -33,16 +33,20 @@ SR = 16000
|
|
| 33 |
|
| 34 |
|
| 35 |
def _to16k(audio):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
sr, x = audio
|
| 37 |
x = np.asarray(x)
|
| 38 |
if x.dtype.kind == "i":
|
| 39 |
-
x = x.astype(np.float32) / np.iinfo(x.dtype).max
|
| 40 |
x = x.astype(np.float32)
|
| 41 |
if x.ndim == 2:
|
| 42 |
x = x.mean(axis=1)
|
| 43 |
if sr != SR:
|
| 44 |
-
|
| 45 |
-
x =
|
| 46 |
return x[: SR * 20] # at most 20 s
|
| 47 |
|
| 48 |
|
|
@@ -71,20 +75,20 @@ def parse_table(text, lang):
|
|
| 71 |
|
| 72 |
|
| 73 |
@spaces.GPU(duration=20, size=GPU_SIZE)
|
| 74 |
-
def _run(x, qs):
|
| 75 |
t = time.perf_counter()
|
| 76 |
-
res = DECIDER.decide(x, qs) if MOCK else DECIDER.decide(x, qs, n_perm=
|
| 77 |
return res, (time.perf_counter() - t) * 1000
|
| 78 |
|
| 79 |
|
| 80 |
-
def decide(audio, lang, text):
|
| 81 |
if audio is None:
|
| 82 |
raise gr.Error("Record or upload a clip first (or pick an example).")
|
| 83 |
x = _to16k(audio)
|
| 84 |
if len(x) < SR * 0.2:
|
| 85 |
raise gr.Error("The clip is too short.")
|
| 86 |
qs = parse_table(text, lang)
|
| 87 |
-
res, ms = _run(x, qs)
|
| 88 |
rows = []
|
| 89 |
for q in qs:
|
| 90 |
r = res[q.id]
|
|
@@ -135,6 +139,7 @@ with gr.Blocks(title="DuplexJev — speech to decisions", theme=gr.themes.Soft(p
|
|
| 135 |
with gr.Accordion("Questions (editable) / 判断题(可编辑)", open=False):
|
| 136 |
table = gr.Textbox(value=table_text("en"), lines=11, show_label=False)
|
| 137 |
btn = gr.Button("Decide ⚡", variant="primary")
|
|
|
|
| 138 |
gr.Examples(EXAMPLES, inputs=[audio, lang], label="Examples (synthetic or public-licence clips)",
|
| 139 |
example_labels=["EN · angry barge-in", "EN · stops mid-request", "EN · “mm-hmm” backchannel", "laughter", "中文 · 等一下我想想", "中文 · 后排闲聊(不是对助手说)", "中文 · 开心道谢", "中文 · 导航请求"])
|
| 140 |
with gr.Column(scale=6):
|
|
@@ -143,7 +148,7 @@ with gr.Blocks(title="DuplexJev — speech to decisions", theme=gr.themes.Soft(p
|
|
| 143 |
interactive=False, max_height=1000, column_widths=["18%", "34%", "13%", "35%"])
|
| 144 |
gr.Markdown(FOOT)
|
| 145 |
lang.change(set_lang, lang, table)
|
| 146 |
-
btn.click(decide, [audio, lang, table], [head, out], api_name="decide")
|
| 147 |
|
| 148 |
if __name__ == "__main__":
|
| 149 |
demo.queue(max_size=40).launch()
|
|
|
|
| 33 |
|
| 34 |
|
| 35 |
def _to16k(audio):
|
| 36 |
+
"""Gradio gives (sr, int16 array); resample with a polyphase filter (plain interpolation aliases and makes
|
| 37 |
+
speech sound harsher, which skews emotion and speaking-style answers)."""
|
| 38 |
+
from math import gcd
|
| 39 |
+
from scipy.signal import resample_poly
|
| 40 |
sr, x = audio
|
| 41 |
x = np.asarray(x)
|
| 42 |
if x.dtype.kind == "i":
|
| 43 |
+
x = x.astype(np.float32) / float(np.iinfo(x.dtype).max + 1)
|
| 44 |
x = x.astype(np.float32)
|
| 45 |
if x.ndim == 2:
|
| 46 |
x = x.mean(axis=1)
|
| 47 |
if sr != SR:
|
| 48 |
+
g = gcd(int(sr), SR)
|
| 49 |
+
x = resample_poly(x, SR // g, int(sr) // g).astype(np.float32)
|
| 50 |
return x[: SR * 20] # at most 20 s
|
| 51 |
|
| 52 |
|
|
|
|
| 75 |
|
| 76 |
|
| 77 |
@spaces.GPU(duration=20, size=GPU_SIZE)
|
| 78 |
+
def _run(x, qs, n_perm):
|
| 79 |
t = time.perf_counter()
|
| 80 |
+
res = DECIDER.decide(x, qs) if MOCK else DECIDER.decide(x, qs, n_perm=n_perm)
|
| 81 |
return res, (time.perf_counter() - t) * 1000
|
| 82 |
|
| 83 |
|
| 84 |
+
def decide(audio, lang, text, n_perm=None):
|
| 85 |
if audio is None:
|
| 86 |
raise gr.Error("Record or upload a clip first (or pick an example).")
|
| 87 |
x = _to16k(audio)
|
| 88 |
if len(x) < SR * 0.2:
|
| 89 |
raise gr.Error("The clip is too short.")
|
| 90 |
qs = parse_table(text, lang)
|
| 91 |
+
res, ms = _run(x, qs, int(n_perm or N_PERM))
|
| 92 |
rows = []
|
| 93 |
for q in qs:
|
| 94 |
r = res[q.id]
|
|
|
|
| 139 |
with gr.Accordion("Questions (editable) / 判断题(可编辑)", open=False):
|
| 140 |
table = gr.Textbox(value=table_text("en"), lines=11, show_label=False)
|
| 141 |
btn = gr.Button("Decide ⚡", variant="primary")
|
| 142 |
+
nperm = gr.Number(value=N_PERM, visible=False)
|
| 143 |
gr.Examples(EXAMPLES, inputs=[audio, lang], label="Examples (synthetic or public-licence clips)",
|
| 144 |
example_labels=["EN · angry barge-in", "EN · stops mid-request", "EN · “mm-hmm” backchannel", "laughter", "中文 · 等一下我想想", "中文 · 后排闲聊(不是对助手说)", "中文 · 开心道谢", "中文 · 导航请求"])
|
| 145 |
with gr.Column(scale=6):
|
|
|
|
| 148 |
interactive=False, max_height=1000, column_widths=["18%", "34%", "13%", "35%"])
|
| 149 |
gr.Markdown(FOOT)
|
| 150 |
lang.change(set_lang, lang, table)
|
| 151 |
+
btn.click(decide, [audio, lang, table, nperm], [head, out], api_name="decide")
|
| 152 |
|
| 153 |
if __name__ == "__main__":
|
| 154 |
demo.queue(max_size=40).launch()
|