mirror of
https://github.com/gradio-app/gradio.git
synced 2025-04-06 12:30:29 +08:00
Merge pull request #800 from gradio-app/streaming_audio
Streaming audio
This commit is contained in:
commit
9afdf09075
2
demo/streaming_stt/.gitignore
vendored
Normal file
2
demo/streaming_stt/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.pbmm
|
||||
*.scorer
|
1
demo/streaming_stt/requirements.txt
Normal file
1
demo/streaming_stt/requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
deepspeech==0.8.2
|
43
demo/streaming_stt/run.py
Normal file
43
demo/streaming_stt/run.py
Normal file
@ -0,0 +1,43 @@
|
||||
from deepspeech import Model
|
||||
import gradio as gr
|
||||
import scipy.io.wavfile
|
||||
import numpy as np
|
||||
|
||||
model_file_path = "deepspeech-0.8.2-models.pbmm"
|
||||
lm_file_path = "deepspeech-0.8.2-models.scorer"
|
||||
beam_width = 100
|
||||
lm_alpha = 0.93
|
||||
lm_beta = 1.18
|
||||
|
||||
model = Model(model_file_path)
|
||||
model.enableExternalScorer(lm_file_path)
|
||||
model.setScorerAlphaBeta(lm_alpha, lm_beta)
|
||||
model.setBeamWidth(beam_width)
|
||||
|
||||
|
||||
def reformat_freq(sr, y):
|
||||
if sr not in (
|
||||
48000,
|
||||
16000,
|
||||
): # Deepspeech only supports 16k, (we convert 48k -> 16k)
|
||||
raise ValueError("Unsupported rate", sr)
|
||||
if sr == 48000:
|
||||
y = (
|
||||
((y / max(np.max(y), 1)) * 32767)
|
||||
.reshape((-1, 3))
|
||||
.mean(axis=1)
|
||||
.astype("int16")
|
||||
)
|
||||
sr = 16000
|
||||
return sr, y
|
||||
|
||||
|
||||
def transcribe(speech, stream):
|
||||
_, y = reformat_freq(*speech)
|
||||
if stream is None:
|
||||
stream = model.createStream()
|
||||
stream.feedAudioContent(y)
|
||||
text = stream.intermediateDecode()
|
||||
return text, stream
|
||||
|
||||
gr.Interface(transcribe, ["microphone", "state"], ["text", "state"], live=True).launch()
|
3
demo/streaming_stt/setup.sh
Normal file
3
demo/streaming_stt/setup.sh
Normal file
@ -0,0 +1,3 @@
|
||||
wget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.pbmm
|
||||
wget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer
|
||||
apt install libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 ffmpeg
|
1
demo/streaming_wav2vec/requirements.txt
Normal file
1
demo/streaming_wav2vec/requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
deepspeech==0.8.2
|
43
demo/streaming_wav2vec/run.py
Normal file
43
demo/streaming_wav2vec/run.py
Normal file
@ -0,0 +1,43 @@
|
||||
from deepspeech import Model
|
||||
import gradio as gr
|
||||
import scipy.io.wavfile
|
||||
import numpy as np
|
||||
|
||||
model_file_path = "deepspeech-0.8.2-models.pbmm"
|
||||
lm_file_path = "deepspeech-0.8.2-models.scorer"
|
||||
beam_width = 100
|
||||
lm_alpha = 0.93
|
||||
lm_beta = 1.18
|
||||
|
||||
model = Model(model_file_path)
|
||||
model.enableExternalScorer(lm_file_path)
|
||||
model.setScorerAlphaBeta(lm_alpha, lm_beta)
|
||||
model.setBeamWidth(beam_width)
|
||||
|
||||
|
||||
def reformat_freq(sr, y):
|
||||
if sr not in (
|
||||
48000,
|
||||
16000,
|
||||
): # Deepspeech only supports 16k, (we convert 48k -> 16k)
|
||||
raise ValueError("Unsupported rate", sr)
|
||||
if sr == 48000:
|
||||
y = (
|
||||
((y / max(np.max(y), 1)) * 32767)
|
||||
.reshape((-1, 3))
|
||||
.mean(axis=1)
|
||||
.astype("int16")
|
||||
)
|
||||
sr = 16000
|
||||
return sr, y
|
||||
|
||||
|
||||
def transcribe(speech, stream):
|
||||
_, y = reformat_freq(*speech)
|
||||
if stream is None:
|
||||
stream = model.createStream()
|
||||
stream.feedAudioContent(y)
|
||||
text = stream.intermediateDecode()
|
||||
return text, stream
|
||||
|
||||
gr.Interface(transcribe, ["microphone", "state"], ["text", "state"], live=True).launch()
|
@ -72,6 +72,7 @@ class PredictBody(BaseModel):
|
||||
data: List[Any]
|
||||
state: Optional[Any]
|
||||
fn_index: Optional[int]
|
||||
cleared: Optional[bool]
|
||||
|
||||
|
||||
class FlagData(BaseModel):
|
||||
@ -257,10 +258,13 @@ def api_docs(request: Request):
|
||||
async def predict(body: PredictBody, username: str = Depends(get_current_user)):
|
||||
if app.launchable.stateful:
|
||||
session_hash = body.session_hash
|
||||
state = app.state_holder.get(
|
||||
(session_hash, "state"), app.launchable.state_default
|
||||
)
|
||||
body.state = state
|
||||
if body.cleared:
|
||||
body.state = None
|
||||
else:
|
||||
state = app.state_holder.get(
|
||||
(session_hash, "state"), app.launchable.state_default
|
||||
)
|
||||
body.state = state
|
||||
try:
|
||||
output = await run_in_threadpool(app.launchable.process_api, body, username)
|
||||
if app.launchable.stateful:
|
||||
|
215
ui/package-lock.json
generated
215
ui/package-lock.json
generated
@ -13,9 +13,54 @@
|
||||
"prettier-plugin-svelte": "^2.6.0",
|
||||
"svelte": "^3.46.3",
|
||||
"svelte-check": "^2.4.1",
|
||||
"svelte-i18n": "^3.3.13",
|
||||
"vitest": "^0.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/ecma402-abstract": {
|
||||
"version": "1.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.3.tgz",
|
||||
"integrity": "sha512-kP/Buv5vVFMAYLHNvvUzr0lwRTU0u2WTy44Tqwku1X3C3lJ5dKqDCYVqA8wL+Y19Bq+MwHgxqd5FZJRCIsLRyQ==",
|
||||
"dependencies": {
|
||||
"@formatjs/intl-localematcher": "0.2.24",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/fast-memoize": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz",
|
||||
"integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/icu-messageformat-parser": {
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.0.18.tgz",
|
||||
"integrity": "sha512-vquIzsAJJmZ5jWVH8dEgUKcbG4yu3KqtyPet+q35SW5reLOvblkfeCXTRW2TpIwNXzdVqsJBwjbTiRiSU9JxwQ==",
|
||||
"dependencies": {
|
||||
"@formatjs/ecma402-abstract": "1.11.3",
|
||||
"@formatjs/icu-skeleton-parser": "1.3.5",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/icu-skeleton-parser": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.5.tgz",
|
||||
"integrity": "sha512-Nhyo2/6kG7ZfgeEfo02sxviOuBcvtzH6SYUharj3DLCDJH3A/4OxkKcmx/2PWGX4bc6iSieh+FA94CsKDxnZBQ==",
|
||||
"dependencies": {
|
||||
"@formatjs/ecma402-abstract": "1.11.3",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/intl-localematcher": {
|
||||
"version": "0.2.24",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.24.tgz",
|
||||
"integrity": "sha512-K/HRGo6EMnCbhpth/y3u4rW4aXkmQNqRe1L2G+Y5jNr3v0gYhvaucV8WixNju/INAMbPBlbsRBRo/nfjnoOnxQ==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@ -215,6 +260,14 @@
|
||||
"node": ">=0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/deepmerge": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
|
||||
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-indent": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
|
||||
@ -546,6 +599,11 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.2.11",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
|
||||
@ -641,6 +699,16 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/globalyzer": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
|
||||
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="
|
||||
},
|
||||
"node_modules/globrex": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
|
||||
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.9",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
|
||||
@ -686,6 +754,17 @@
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/intl-messageformat": {
|
||||
"version": "9.11.4",
|
||||
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.11.4.tgz",
|
||||
"integrity": "sha512-77TSkNubIy/hsapz6LQpyR6OADcxhWdhSaboPb5flMaALCVkPvAIxr48AlPqaMl4r1anNcvR9rpLWVdwUY1IKg==",
|
||||
"dependencies": {
|
||||
"@formatjs/ecma402-abstract": "1.11.3",
|
||||
"@formatjs/fast-memoize": "1.2.1",
|
||||
"@formatjs/icu-messageformat-parser": "2.0.18",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
@ -1156,6 +1235,27 @@
|
||||
"svelte": "^3.24.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-i18n": {
|
||||
"version": "3.3.13",
|
||||
"resolved": "https://registry.npmjs.org/svelte-i18n/-/svelte-i18n-3.3.13.tgz",
|
||||
"integrity": "sha512-RQM+ys4+Y9ztH//tX22H1UL2cniLNmIR+N4xmYygV6QpQ6EyQvloZiENRew8XrVzfvJ8HaE8NU6/yurLkl7z3g==",
|
||||
"dependencies": {
|
||||
"deepmerge": "^4.2.2",
|
||||
"estree-walker": "^2.0.1",
|
||||
"intl-messageformat": "^9.3.15",
|
||||
"sade": "^1.7.4",
|
||||
"tiny-glob": "^0.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"svelte-i18n": "dist/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 11.15.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.25.1"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-preprocess": {
|
||||
"version": "4.10.3",
|
||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.3.tgz",
|
||||
@ -1221,6 +1321,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-glob": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
|
||||
"dependencies": {
|
||||
"globalyzer": "0.1.0",
|
||||
"globrex": "^0.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/tinypool": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.1.2.tgz",
|
||||
@ -1248,6 +1357,11 @@
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"node_modules/type-detect": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||
@ -1354,6 +1468,50 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@formatjs/ecma402-abstract": {
|
||||
"version": "1.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.3.tgz",
|
||||
"integrity": "sha512-kP/Buv5vVFMAYLHNvvUzr0lwRTU0u2WTy44Tqwku1X3C3lJ5dKqDCYVqA8wL+Y19Bq+MwHgxqd5FZJRCIsLRyQ==",
|
||||
"requires": {
|
||||
"@formatjs/intl-localematcher": "0.2.24",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"@formatjs/fast-memoize": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz",
|
||||
"integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==",
|
||||
"requires": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"@formatjs/icu-messageformat-parser": {
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.0.18.tgz",
|
||||
"integrity": "sha512-vquIzsAJJmZ5jWVH8dEgUKcbG4yu3KqtyPet+q35SW5reLOvblkfeCXTRW2TpIwNXzdVqsJBwjbTiRiSU9JxwQ==",
|
||||
"requires": {
|
||||
"@formatjs/ecma402-abstract": "1.11.3",
|
||||
"@formatjs/icu-skeleton-parser": "1.3.5",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"@formatjs/icu-skeleton-parser": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.5.tgz",
|
||||
"integrity": "sha512-Nhyo2/6kG7ZfgeEfo02sxviOuBcvtzH6SYUharj3DLCDJH3A/4OxkKcmx/2PWGX4bc6iSieh+FA94CsKDxnZBQ==",
|
||||
"requires": {
|
||||
"@formatjs/ecma402-abstract": "1.11.3",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-localematcher": {
|
||||
"version": "0.2.24",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.24.tgz",
|
||||
"integrity": "sha512-K/HRGo6EMnCbhpth/y3u4rW4aXkmQNqRe1L2G+Y5jNr3v0gYhvaucV8WixNju/INAMbPBlbsRBRo/nfjnoOnxQ==",
|
||||
"requires": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@ -1506,6 +1664,11 @@
|
||||
"type-detect": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"deepmerge": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
|
||||
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
|
||||
},
|
||||
"detect-indent": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
|
||||
@ -1656,6 +1819,11 @@
|
||||
"integrity": "sha512-8Sbo0zpzgwWrwjQYLmHF78f7E2xg5Ve63bjB2ng3V2aManilnnTGaliq2snYg+NOX60+hEvJHRdVnuIAHW0lVw==",
|
||||
"optional": true
|
||||
},
|
||||
"estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "3.2.11",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
|
||||
@ -1726,6 +1894,16 @@
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"globalyzer": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
|
||||
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="
|
||||
},
|
||||
"globrex": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
|
||||
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.9",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
|
||||
@ -1762,6 +1940,17 @@
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"intl-messageformat": {
|
||||
"version": "9.11.4",
|
||||
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.11.4.tgz",
|
||||
"integrity": "sha512-77TSkNubIy/hsapz6LQpyR6OADcxhWdhSaboPb5flMaALCVkPvAIxr48AlPqaMl4r1anNcvR9rpLWVdwUY1IKg==",
|
||||
"requires": {
|
||||
"@formatjs/ecma402-abstract": "1.11.3",
|
||||
"@formatjs/fast-memoize": "1.2.1",
|
||||
"@formatjs/icu-messageformat-parser": "2.0.18",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
@ -2070,6 +2259,18 @@
|
||||
"typescript": "*"
|
||||
}
|
||||
},
|
||||
"svelte-i18n": {
|
||||
"version": "3.3.13",
|
||||
"resolved": "https://registry.npmjs.org/svelte-i18n/-/svelte-i18n-3.3.13.tgz",
|
||||
"integrity": "sha512-RQM+ys4+Y9ztH//tX22H1UL2cniLNmIR+N4xmYygV6QpQ6EyQvloZiENRew8XrVzfvJ8HaE8NU6/yurLkl7z3g==",
|
||||
"requires": {
|
||||
"deepmerge": "^4.2.2",
|
||||
"estree-walker": "^2.0.1",
|
||||
"intl-messageformat": "^9.3.15",
|
||||
"sade": "^1.7.4",
|
||||
"tiny-glob": "^0.2.6"
|
||||
}
|
||||
},
|
||||
"svelte-preprocess": {
|
||||
"version": "4.10.3",
|
||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.3.tgz",
|
||||
@ -2083,6 +2284,15 @@
|
||||
"strip-indent": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"tiny-glob": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
|
||||
"requires": {
|
||||
"globalyzer": "0.1.0",
|
||||
"globrex": "^0.1.2"
|
||||
}
|
||||
},
|
||||
"tinypool": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.1.2.tgz",
|
||||
@ -2101,6 +2311,11 @@
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"type-detect": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||
|
@ -36,6 +36,7 @@
|
||||
let queue_index: number | null = null;
|
||||
let initial_queue_index: number | null = null;
|
||||
let just_flagged: boolean = false;
|
||||
let cleared_since_last_submit = false;
|
||||
|
||||
const default_inputs: Array<unknown> = input_components.map((component) =>
|
||||
"default" in component ? component.default : null
|
||||
@ -52,12 +53,12 @@
|
||||
let expected_duration: number | null = null;
|
||||
let example_id: number | null = null;
|
||||
|
||||
const setValues = (index: number, value: unknown) => {
|
||||
const setValues = async (index: number, value: unknown) => {
|
||||
example_id = null;
|
||||
has_changed = true;
|
||||
input_values[index] = value;
|
||||
if (live && state !== "PENDING") {
|
||||
submit();
|
||||
await submit();
|
||||
}
|
||||
};
|
||||
|
||||
@ -90,7 +91,7 @@
|
||||
clearInterval(timer);
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
const submit = async () => {
|
||||
if (state === "PENDING") {
|
||||
return;
|
||||
}
|
||||
@ -108,64 +109,67 @@
|
||||
has_changed = false;
|
||||
let submission_count_at_click = submission_count;
|
||||
startTimer();
|
||||
fn(
|
||||
"predict",
|
||||
{ data: input_values, example_id: example_id },
|
||||
queue,
|
||||
queueCallback
|
||||
)
|
||||
.then((output) => {
|
||||
if (
|
||||
state !== "PENDING" ||
|
||||
submission_count_at_click !== submission_count
|
||||
) {
|
||||
return;
|
||||
}
|
||||
stopTimer();
|
||||
output_values = output["data"];
|
||||
for (let [i, value] of output_values.entries()) {
|
||||
if (output_components[i].name === "state") {
|
||||
for (let [j, input_component] of input_components.entries()) {
|
||||
if (input_component.name === "state") {
|
||||
input_values[j] = value;
|
||||
}
|
||||
}
|
||||
let output: any;
|
||||
try {
|
||||
output = await fn(
|
||||
"predict",
|
||||
{
|
||||
data: input_values,
|
||||
cleared: cleared_since_last_submit,
|
||||
example_id: example_id
|
||||
},
|
||||
queue,
|
||||
queueCallback
|
||||
);
|
||||
} catch (e) {
|
||||
if (
|
||||
state !== "PENDING" ||
|
||||
submission_count_at_click !== submission_count
|
||||
) {
|
||||
return;
|
||||
}
|
||||
stopTimer();
|
||||
console.error(e);
|
||||
state = "ERROR";
|
||||
output_values = deepCopy(default_outputs);
|
||||
}
|
||||
if (state !== "PENDING" || submission_count_at_click !== submission_count) {
|
||||
return;
|
||||
}
|
||||
stopTimer();
|
||||
output_values = output["data"];
|
||||
cleared_since_last_submit = false;
|
||||
for (let [i, value] of output_values.entries()) {
|
||||
if (output_components[i].name === "state") {
|
||||
for (let [j, input_component] of input_components.entries()) {
|
||||
if (input_component.name === "state") {
|
||||
input_values[j] = value;
|
||||
}
|
||||
}
|
||||
if ("durations" in output) {
|
||||
last_duration = output["durations"][0];
|
||||
}
|
||||
if ("avg_durations" in output) {
|
||||
avg_duration = output["avg_durations"][0];
|
||||
if (queue && initial_queue_index) {
|
||||
expected_duration = avg_duration * (initial_queue_index + 1);
|
||||
} else {
|
||||
expected_duration = avg_duration;
|
||||
}
|
||||
}
|
||||
state = "COMPLETE";
|
||||
if (live && has_changed) {
|
||||
submit();
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
if (
|
||||
state !== "PENDING" ||
|
||||
submission_count_at_click !== submission_count
|
||||
) {
|
||||
return;
|
||||
}
|
||||
stopTimer();
|
||||
console.error(e);
|
||||
state = "ERROR";
|
||||
output_values = deepCopy(default_outputs);
|
||||
});
|
||||
}
|
||||
}
|
||||
if ("durations" in output) {
|
||||
last_duration = output["durations"][0];
|
||||
}
|
||||
if ("avg_durations" in output) {
|
||||
avg_duration = output["avg_durations"][0];
|
||||
if (queue && initial_queue_index) {
|
||||
expected_duration = avg_duration * (initial_queue_index + 1);
|
||||
} else {
|
||||
expected_duration = avg_duration;
|
||||
}
|
||||
}
|
||||
state = "COMPLETE";
|
||||
if (live && has_changed) {
|
||||
await submit();
|
||||
}
|
||||
};
|
||||
const clear = () => {
|
||||
input_values = deepCopy(default_inputs);
|
||||
output_values = deepCopy(default_outputs);
|
||||
interpret_mode = false;
|
||||
state = "START";
|
||||
cleared_since_last_submit = true;
|
||||
stopTimer();
|
||||
};
|
||||
const flag = (flag_option: string | null) => {
|
||||
@ -231,6 +235,7 @@
|
||||
{...input_component}
|
||||
{theme}
|
||||
{static_src}
|
||||
{live}
|
||||
value={input_values[i]}
|
||||
interpretation={interpret_mode
|
||||
? interpretation_values[i]
|
||||
@ -248,19 +253,21 @@
|
||||
>
|
||||
{$_("interface.clear")}
|
||||
</button>
|
||||
<button
|
||||
class="panel-button submit bg-gray-50 dark:bg-gray-700 flex-1 p-3 rounded transition font-semibold focus:outline-none"
|
||||
on:click={submit}
|
||||
>
|
||||
{$_("interface.submit")}
|
||||
</button>
|
||||
{#if !live}
|
||||
<button
|
||||
class="panel-button submit bg-gray-50 dark:bg-gray-700 flex-1 p-3 rounded transition font-semibold focus:outline-none"
|
||||
on:click={submit}
|
||||
>
|
||||
{$_("interface.submit")}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel flex-1">
|
||||
<div
|
||||
class="component-set p-2 rounded flex flex-col flex-1 gap-2 relative"
|
||||
style="min-height: 36px"
|
||||
class:opacity-50={state === "PENDING"}
|
||||
class:opacity-50={state === "PENDING" && !live}
|
||||
>
|
||||
{#if state !== "START"}
|
||||
<div class="state absolute right-2 flex items-center gap-0.5 text-xs">
|
||||
|
@ -9,6 +9,7 @@
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
export let value: null | Value;
|
||||
export let live: boolean;
|
||||
export let setValue: (val: typeof value) => typeof value;
|
||||
export let theme: string;
|
||||
export let name: string;
|
||||
@ -20,37 +21,54 @@
|
||||
let recorder: MediaRecorder;
|
||||
let mode = "";
|
||||
let audio_chunks: Array<Blob> = [];
|
||||
let chunks_at_submit: number = 0;
|
||||
let audio_blob;
|
||||
let player;
|
||||
let inited = false;
|
||||
let crop_values = [0, 100];
|
||||
let submitting_data = false;
|
||||
let record_interval;
|
||||
|
||||
function blob_to_data_url(blob: Blob): Promise<string> {
|
||||
return new Promise((fulfill, reject) => {
|
||||
let reader = new FileReader();
|
||||
reader.onerror = reject;
|
||||
reader.onload = (e) => fulfill(reader.result as string);
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
async function generate_data(): Promise<{
|
||||
data: string;
|
||||
name: string;
|
||||
is_example: boolean;
|
||||
}> {
|
||||
function blob_to_data_url(blob: Blob): Promise<string> {
|
||||
return new Promise((fulfill, reject) => {
|
||||
let reader = new FileReader();
|
||||
reader.onerror = reject;
|
||||
reader.onload = (e) => fulfill(reader.result as string);
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
audio_blob = new Blob(audio_chunks, { type: "audio/wav" });
|
||||
return {
|
||||
data: await blob_to_data_url(audio_blob),
|
||||
name,
|
||||
is_example
|
||||
};
|
||||
}
|
||||
|
||||
async function prepare_audio() {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
recorder = new MediaRecorder(stream);
|
||||
|
||||
recorder.addEventListener("dataavailable", (event) => {
|
||||
recorder.addEventListener("dataavailable", async (event) => {
|
||||
audio_chunks.push(event.data);
|
||||
if (live && !submitting_data) {
|
||||
submitting_data = true;
|
||||
chunks_at_submit = audio_chunks.length;
|
||||
await setValue(await generate_data());
|
||||
submitting_data = false;
|
||||
audio_chunks = audio_chunks.slice(chunks_at_submit);
|
||||
}
|
||||
});
|
||||
|
||||
recorder.addEventListener("stop", async () => {
|
||||
recording = false;
|
||||
audio_blob = new Blob(audio_chunks, { type: "audio/wav" });
|
||||
|
||||
setValue({
|
||||
data: await blob_to_data_url(audio_blob),
|
||||
name,
|
||||
is_example
|
||||
});
|
||||
if (!live) {
|
||||
setValue(await generate_data());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -61,6 +79,12 @@
|
||||
if (!inited) await prepare_audio();
|
||||
|
||||
recorder.start();
|
||||
if (live) {
|
||||
record_interval = setInterval(() => {
|
||||
recorder.stop();
|
||||
recorder.start();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
@ -70,7 +94,11 @@
|
||||
});
|
||||
|
||||
const stop = () => {
|
||||
recording = false;
|
||||
recorder.stop();
|
||||
if (live) {
|
||||
clearInterval(record_interval);
|
||||
}
|
||||
};
|
||||
|
||||
function clear() {
|
||||
@ -117,7 +145,7 @@
|
||||
</script>
|
||||
|
||||
<div class="input-audio">
|
||||
{#if value === null}
|
||||
{#if value === null || (source === "microphone" && live)}
|
||||
{#if source === "microphone"}
|
||||
{#if recording}
|
||||
<button
|
||||
|
Loading…
x
Reference in New Issue
Block a user