Deploy checked Hendrix D26 browser demo
Browse files- .gitattributes +2 -0
- README.md +8 -5
- assets/local-DNpA26UR.js +0 -0
- deployment.json +26 -20
- diagnostic.wav +0 -0
- index.html +1 -1
- local.html +1 -1
- source/demo/web/src/local.tsx +1 -1
- source/deploy/huggingface/README.md +8 -5
- source/docs/assets/slakh_test_Track01876.wav +3 -0
- source/scripts/check_huggingface_space.mjs +2 -2
- source/scripts/deploy_huggingface_space.py +7 -4
.gitattributes
CHANGED
|
@@ -34,3 +34,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
source/docs/assets/choir_bwv407.wav filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
source/docs/assets/choir_bwv407.wav filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
diagnostic.wav filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
source/docs/assets/slakh_test_Track01876.wav filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -21,8 +21,8 @@ custom_headers:
|
|
| 21 |
|
| 22 |
# Hendrix
|
| 23 |
|
| 24 |
-
Choose an audio file, record with your microphone, or try the short
|
| 25 |
-
|
| 26 |
plays the result, and lets you download a MIDI file.
|
| 27 |
|
| 28 |
Audio decoding and model inference run on your device. The app does not upload
|
|
@@ -36,9 +36,12 @@ depends on browser permissions. Predictions are a research result and may
|
|
| 36 |
miss notes, assign the wrong instrument, or give poor note endings. MIDI
|
| 37 |
playback uses a simple browser synth.
|
| 38 |
|
| 39 |
-
The example is a two-second excerpt
|
| 40 |
-
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
Model: 46.5M-parameter D26, derived from YPTF-MoE+Multi. `models/fp32/manifest.json`
|
| 44 |
records the source checkpoint and graph hashes. `deployment.json` records the
|
|
|
|
| 21 |
|
| 22 |
# Hendrix
|
| 23 |
|
| 24 |
+
Choose an audio file, record with your microphone, or try the short demo
|
| 25 |
+
clip. Hendrix predicts notes and instrument families, draws a piano roll,
|
| 26 |
plays the result, and lets you download a MIDI file.
|
| 27 |
|
| 28 |
Audio decoding and model inference run on your device. The app does not upload
|
|
|
|
| 36 |
miss notes, assign the wrong instrument, or give poor note endings. MIDI
|
| 37 |
playback uses a simple browser synth.
|
| 38 |
|
| 39 |
+
The example is a two-second excerpt (6–8 seconds of the repo's preview) from
|
| 40 |
+
Slakh2100 test Track01876, cropped from the existing project demo. Slakh2100
|
| 41 |
+
is by Ethan Manilow, Gordon Wichern, Prem Seetharaman, and Jonathan Le Roux,
|
| 42 |
+
available on [Zenodo](https://zenodo.org/records/4599666) under
|
| 43 |
+
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). We do not
|
| 44 |
+
redistribute the local YouTube diagnostic audio.
|
| 45 |
|
| 46 |
Model: 46.5M-parameter D26, derived from YPTF-MoE+Multi. `models/fp32/manifest.json`
|
| 47 |
records the source checkpoint and graph hashes. `deployment.json` records the
|
assets/local-DNpA26UR.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
deployment.json
CHANGED
|
@@ -5,10 +5,16 @@
|
|
| 5 |
"source_dirty": true,
|
| 6 |
"build_command": "VITE_HENDRIX_SPACE=1 npx --yes pnpm@10.20.0 --dir demo/web build --manifest",
|
| 7 |
"checkpoint_sha256": "3df08bb38dce7ae30be23090524b63755c565d1a3242860aef6c9401fc125bbe",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
"files": {
|
| 9 |
"README.md": {
|
| 10 |
-
"bytes":
|
| 11 |
-
"sha256": "
|
| 12 |
},
|
| 13 |
"assets/PianoRollCanvas-xSq9nagc.js": {
|
| 14 |
"bytes": 3055,
|
|
@@ -18,9 +24,9 @@
|
|
| 18 |
"bytes": 4149,
|
| 19 |
"sha256": "dfab143da9fda372f21e3513d3882baffdc7c40f4df51ad86f7ad3c01b34ef3d"
|
| 20 |
},
|
| 21 |
-
"assets/local-
|
| 22 |
-
"bytes":
|
| 23 |
-
"sha256": "
|
| 24 |
},
|
| 25 |
"assets/ort-wasm-simd-threaded.asyncify-CvvOzbbq.wasm": {
|
| 26 |
"bytes": 24254953,
|
|
@@ -39,8 +45,8 @@
|
|
| 39 |
"sha256": "1be18fcb99a202c31bfe5ab4154afda3aaeb95af45706ae534653910c0b914dc"
|
| 40 |
},
|
| 41 |
"diagnostic.wav": {
|
| 42 |
-
"bytes":
|
| 43 |
-
"sha256": "
|
| 44 |
},
|
| 45 |
"favicon.png": {
|
| 46 |
"bytes": 4671,
|
|
@@ -48,11 +54,11 @@
|
|
| 48 |
},
|
| 49 |
"index.html": {
|
| 50 |
"bytes": 770,
|
| 51 |
-
"sha256": "
|
| 52 |
},
|
| 53 |
"local.html": {
|
| 54 |
"bytes": 770,
|
| 55 |
-
"sha256": "
|
| 56 |
},
|
| 57 |
"models/fp32/cross_cache.onnx": {
|
| 58 |
"bytes": 12648891,
|
|
@@ -195,8 +201,8 @@
|
|
| 195 |
"sha256": "461a7c37240940c440694d7a65cc18c47090b8429bbeb1daa5a6175440c75c99"
|
| 196 |
},
|
| 197 |
"source/demo/web/src/local.tsx": {
|
| 198 |
-
"bytes":
|
| 199 |
-
"sha256": "
|
| 200 |
},
|
| 201 |
"source/demo/web/src/main.tsx": {
|
| 202 |
"bytes": 381,
|
|
@@ -231,20 +237,20 @@
|
|
| 231 |
"sha256": "2e3e6765cca9de53a0f23e42a52f4f152b9789b36e630345c9e2e6fb3f1b8475"
|
| 232 |
},
|
| 233 |
"source/deploy/huggingface/README.md": {
|
| 234 |
-
"bytes":
|
| 235 |
-
"sha256": "
|
| 236 |
},
|
| 237 |
-
"source/docs/assets/
|
| 238 |
-
"bytes":
|
| 239 |
-
"sha256": "
|
| 240 |
},
|
| 241 |
"source/scripts/check_huggingface_space.mjs": {
|
| 242 |
-
"bytes":
|
| 243 |
-
"sha256": "
|
| 244 |
},
|
| 245 |
"source/scripts/deploy_huggingface_space.py": {
|
| 246 |
-
"bytes":
|
| 247 |
-
"sha256": "
|
| 248 |
}
|
| 249 |
}
|
| 250 |
}
|
|
|
|
| 5 |
"source_dirty": true,
|
| 6 |
"build_command": "VITE_HENDRIX_SPACE=1 npx --yes pnpm@10.20.0 --dir demo/web build --manifest",
|
| 7 |
"checkpoint_sha256": "3df08bb38dce7ae30be23090524b63755c565d1a3242860aef6c9401fc125bbe",
|
| 8 |
+
"example": {
|
| 9 |
+
"source": "Slakh2100 Track01876",
|
| 10 |
+
"clip_offset_seconds": 6,
|
| 11 |
+
"duration_seconds": 2,
|
| 12 |
+
"license": "CC-BY-4.0"
|
| 13 |
+
},
|
| 14 |
"files": {
|
| 15 |
"README.md": {
|
| 16 |
+
"bytes": 2670,
|
| 17 |
+
"sha256": "6e3f1d73e894ae2b0c221cf67a249539c1f474a22dfb2485fde1c46fe7ab308b"
|
| 18 |
},
|
| 19 |
"assets/PianoRollCanvas-xSq9nagc.js": {
|
| 20 |
"bytes": 3055,
|
|
|
|
| 24 |
"bytes": 4149,
|
| 25 |
"sha256": "dfab143da9fda372f21e3513d3882baffdc7c40f4df51ad86f7ad3c01b34ef3d"
|
| 26 |
},
|
| 27 |
+
"assets/local-DNpA26UR.js": {
|
| 28 |
+
"bytes": 133985,
|
| 29 |
+
"sha256": "065a69aa447b366c140d4b15cc3390269182840da10ac416804456e0996ef163"
|
| 30 |
},
|
| 31 |
"assets/ort-wasm-simd-threaded.asyncify-CvvOzbbq.wasm": {
|
| 32 |
"bytes": 24254953,
|
|
|
|
| 45 |
"sha256": "1be18fcb99a202c31bfe5ab4154afda3aaeb95af45706ae534653910c0b914dc"
|
| 46 |
},
|
| 47 |
"diagnostic.wav": {
|
| 48 |
+
"bytes": 128044,
|
| 49 |
+
"sha256": "87586b57be103e74950daa9035b2459a000a57b19a320e1faf0649d678fbcfc4"
|
| 50 |
},
|
| 51 |
"favicon.png": {
|
| 52 |
"bytes": 4671,
|
|
|
|
| 54 |
},
|
| 55 |
"index.html": {
|
| 56 |
"bytes": 770,
|
| 57 |
+
"sha256": "40e2ccc066efb40ca142438b0d3e0bdbaf8479c74e660cb803e1d9af9f1e951c"
|
| 58 |
},
|
| 59 |
"local.html": {
|
| 60 |
"bytes": 770,
|
| 61 |
+
"sha256": "40e2ccc066efb40ca142438b0d3e0bdbaf8479c74e660cb803e1d9af9f1e951c"
|
| 62 |
},
|
| 63 |
"models/fp32/cross_cache.onnx": {
|
| 64 |
"bytes": 12648891,
|
|
|
|
| 201 |
"sha256": "461a7c37240940c440694d7a65cc18c47090b8429bbeb1daa5a6175440c75c99"
|
| 202 |
},
|
| 203 |
"source/demo/web/src/local.tsx": {
|
| 204 |
+
"bytes": 15341,
|
| 205 |
+
"sha256": "c5e348b230534646320555cdb770047b38b035fee4bf49383a1c1f30c903f5c1"
|
| 206 |
},
|
| 207 |
"source/demo/web/src/main.tsx": {
|
| 208 |
"bytes": 381,
|
|
|
|
| 237 |
"sha256": "2e3e6765cca9de53a0f23e42a52f4f152b9789b36e630345c9e2e6fb3f1b8475"
|
| 238 |
},
|
| 239 |
"source/deploy/huggingface/README.md": {
|
| 240 |
+
"bytes": 2670,
|
| 241 |
+
"sha256": "6e3f1d73e894ae2b0c221cf67a249539c1f474a22dfb2485fde1c46fe7ab308b"
|
| 242 |
},
|
| 243 |
+
"source/docs/assets/slakh_test_Track01876.wav": {
|
| 244 |
+
"bytes": 1920044,
|
| 245 |
+
"sha256": "6b514aae5163051da66d320b12957f7f90ab0aaf120b3b4fae7164b883f823ec"
|
| 246 |
},
|
| 247 |
"source/scripts/check_huggingface_space.mjs": {
|
| 248 |
+
"bytes": 4643,
|
| 249 |
+
"sha256": "38356c955cdf3f8c3592e10d56470f37e9ca8f12b0829312bb2ebf47ed8aa6c5"
|
| 250 |
},
|
| 251 |
"source/scripts/deploy_huggingface_space.py": {
|
| 252 |
+
"bytes": 8153,
|
| 253 |
+
"sha256": "a370c0ce64da666b22af4ca5d2d36dba628f5ea00cad1a646b65abaa7f0f7d85"
|
| 254 |
}
|
| 255 |
}
|
| 256 |
}
|
diagnostic.wav
CHANGED
|
Binary files a/diagnostic.wav and b/diagnostic.wav differ
|
|
|
index.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
| 6 |
<meta name="theme-color" content="#090a0d" />
|
| 7 |
<link rel="icon" href="/favicon.png" />
|
| 8 |
<title>Hendrix — on-device transcription</title>
|
| 9 |
-
<script type="module" crossorigin src="/assets/local-
|
| 10 |
<link rel="modulepreload" crossorigin href="/assets/style-CdJLhYve.js">
|
| 11 |
<link rel="modulepreload" crossorigin href="/assets/PianoRollCanvas-xSq9nagc.js">
|
| 12 |
<link rel="stylesheet" crossorigin href="/assets/style-BAFoxh21.css">
|
|
|
|
| 6 |
<meta name="theme-color" content="#090a0d" />
|
| 7 |
<link rel="icon" href="/favicon.png" />
|
| 8 |
<title>Hendrix — on-device transcription</title>
|
| 9 |
+
<script type="module" crossorigin src="/assets/local-DNpA26UR.js"></script>
|
| 10 |
<link rel="modulepreload" crossorigin href="/assets/style-CdJLhYve.js">
|
| 11 |
<link rel="modulepreload" crossorigin href="/assets/PianoRollCanvas-xSq9nagc.js">
|
| 12 |
<link rel="stylesheet" crossorigin href="/assets/style-BAFoxh21.css">
|
local.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
| 6 |
<meta name="theme-color" content="#090a0d" />
|
| 7 |
<link rel="icon" href="/favicon.png" />
|
| 8 |
<title>Hendrix — on-device transcription</title>
|
| 9 |
-
<script type="module" crossorigin src="/assets/local-
|
| 10 |
<link rel="modulepreload" crossorigin href="/assets/style-CdJLhYve.js">
|
| 11 |
<link rel="modulepreload" crossorigin href="/assets/PianoRollCanvas-xSq9nagc.js">
|
| 12 |
<link rel="stylesheet" crossorigin href="/assets/style-BAFoxh21.css">
|
|
|
|
| 6 |
<meta name="theme-color" content="#090a0d" />
|
| 7 |
<link rel="icon" href="/favicon.png" />
|
| 8 |
<title>Hendrix — on-device transcription</title>
|
| 9 |
+
<script type="module" crossorigin src="/assets/local-DNpA26UR.js"></script>
|
| 10 |
<link rel="modulepreload" crossorigin href="/assets/style-CdJLhYve.js">
|
| 11 |
<link rel="modulepreload" crossorigin href="/assets/PianoRollCanvas-xSq9nagc.js">
|
| 12 |
<link rel="stylesheet" crossorigin href="/assets/style-BAFoxh21.css">
|
source/demo/web/src/local.tsx
CHANGED
|
@@ -272,7 +272,7 @@ function LocalApp() {
|
|
| 272 |
if (selected) chooseFile(selected);
|
| 273 |
}} />
|
| 274 |
</label>
|
| 275 |
-
<button className="secondary-button" disabled={inputLocked} onClick={() => prepareInput(loadDiagnosticClip)}>{isSpace ? "Try
|
| 276 |
{!recording ? (
|
| 277 |
<button className="secondary-button" onClick={() => prepareInput(startRecording)} disabled={!capability?.supported || inputLocked}>Record here</button>
|
| 278 |
) : (
|
|
|
|
| 272 |
if (selected) chooseFile(selected);
|
| 273 |
}} />
|
| 274 |
</label>
|
| 275 |
+
<button className="secondary-button" disabled={inputLocked} onClick={() => prepareInput(loadDiagnosticClip)}>{isSpace ? "Try demo clip" : "Known check clip"}</button>
|
| 276 |
{!recording ? (
|
| 277 |
<button className="secondary-button" onClick={() => prepareInput(startRecording)} disabled={!capability?.supported || inputLocked}>Record here</button>
|
| 278 |
) : (
|
source/deploy/huggingface/README.md
CHANGED
|
@@ -21,8 +21,8 @@ custom_headers:
|
|
| 21 |
|
| 22 |
# Hendrix
|
| 23 |
|
| 24 |
-
Choose an audio file, record with your microphone, or try the short
|
| 25 |
-
|
| 26 |
plays the result, and lets you download a MIDI file.
|
| 27 |
|
| 28 |
Audio decoding and model inference run on your device. The app does not upload
|
|
@@ -36,9 +36,12 @@ depends on browser permissions. Predictions are a research result and may
|
|
| 36 |
miss notes, assign the wrong instrument, or give poor note endings. MIDI
|
| 37 |
playback uses a simple browser synth.
|
| 38 |
|
| 39 |
-
The example is a two-second excerpt
|
| 40 |
-
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
Model: 46.5M-parameter D26, derived from YPTF-MoE+Multi. `models/fp32/manifest.json`
|
| 44 |
records the source checkpoint and graph hashes. `deployment.json` records the
|
|
|
|
| 21 |
|
| 22 |
# Hendrix
|
| 23 |
|
| 24 |
+
Choose an audio file, record with your microphone, or try the short demo
|
| 25 |
+
clip. Hendrix predicts notes and instrument families, draws a piano roll,
|
| 26 |
plays the result, and lets you download a MIDI file.
|
| 27 |
|
| 28 |
Audio decoding and model inference run on your device. The app does not upload
|
|
|
|
| 36 |
miss notes, assign the wrong instrument, or give poor note endings. MIDI
|
| 37 |
playback uses a simple browser synth.
|
| 38 |
|
| 39 |
+
The example is a two-second excerpt (6–8 seconds of the repo's preview) from
|
| 40 |
+
Slakh2100 test Track01876, cropped from the existing project demo. Slakh2100
|
| 41 |
+
is by Ethan Manilow, Gordon Wichern, Prem Seetharaman, and Jonathan Le Roux,
|
| 42 |
+
available on [Zenodo](https://zenodo.org/records/4599666) under
|
| 43 |
+
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). We do not
|
| 44 |
+
redistribute the local YouTube diagnostic audio.
|
| 45 |
|
| 46 |
Model: 46.5M-parameter D26, derived from YPTF-MoE+Multi. `models/fp32/manifest.json`
|
| 47 |
records the source checkpoint and graph hashes. `deployment.json` records the
|
source/docs/assets/slakh_test_Track01876.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6b514aae5163051da66d320b12957f7f90ab0aaf120b3b4fae7164b883f823ec
|
| 3 |
+
size 1920044
|
source/scripts/check_huggingface_space.mjs
CHANGED
|
@@ -37,7 +37,7 @@ async function check(page, embedded) {
|
|
| 37 |
await page.goto(`${base}/local.html?backend=wasm`, { waitUntil: "domcontentloaded", timeout: 60_000 });
|
| 38 |
app = page.mainFrame();
|
| 39 |
}
|
| 40 |
-
await app.getByRole("button", { name: "Try
|
| 41 |
await app.waitForFunction(() => document.querySelector(".capability-card")?.textContent.includes("WebAssembly CPU"));
|
| 42 |
const isolation = await app.evaluate(() => ({
|
| 43 |
isolated: crossOriginIsolated, secure: isSecureContext,
|
|
@@ -46,7 +46,7 @@ async function check(page, embedded) {
|
|
| 46 |
}));
|
| 47 |
assert.equal(isolation.secure, true);
|
| 48 |
if (!embedded) assert.equal(isolation.isolated, true, "direct app must enable cross-origin isolation");
|
| 49 |
-
await app.getByRole("button", { name: "Try
|
| 50 |
const started = Date.now();
|
| 51 |
await app.getByRole("button", { name: "Run on this device" }).click();
|
| 52 |
await app.waitForFunction(() => {
|
|
|
|
| 37 |
await page.goto(`${base}/local.html?backend=wasm`, { waitUntil: "domcontentloaded", timeout: 60_000 });
|
| 38 |
app = page.mainFrame();
|
| 39 |
}
|
| 40 |
+
await app.getByRole("button", { name: "Try demo clip" }).waitFor({ timeout: 60_000 });
|
| 41 |
await app.waitForFunction(() => document.querySelector(".capability-card")?.textContent.includes("WebAssembly CPU"));
|
| 42 |
const isolation = await app.evaluate(() => ({
|
| 43 |
isolated: crossOriginIsolated, secure: isSecureContext,
|
|
|
|
| 46 |
}));
|
| 47 |
assert.equal(isolation.secure, true);
|
| 48 |
if (!embedded) assert.equal(isolation.isolated, true, "direct app must enable cross-origin isolation");
|
| 49 |
+
await app.getByRole("button", { name: "Try demo clip" }).click();
|
| 50 |
const started = Date.now();
|
| 51 |
await app.getByRole("button", { name: "Run on this device" }).click();
|
| 52 |
await app.waitForFunction(() => {
|
source/scripts/deploy_huggingface_space.py
CHANGED
|
@@ -81,11 +81,13 @@ def package_space(web_dir: Path, graph_dir: Path, ort_dir: Path, output: Path) -
|
|
| 81 |
for filename in ORT_FILES:
|
| 82 |
copy_file(ort_dir / filename, output / "ort" / filename)
|
| 83 |
|
| 84 |
-
#
|
| 85 |
-
|
|
|
|
| 86 |
with wave.open(str(output / "diagnostic.wav"), "wb") as target:
|
| 87 |
target.setparams(source.getparams())
|
| 88 |
-
|
|
|
|
| 89 |
|
| 90 |
copy_file(REPO / "deploy/huggingface/README.md", output / "README.md")
|
| 91 |
# Keep the exact app source next to the build for review and reproduction.
|
|
@@ -96,7 +98,7 @@ def package_space(web_dir: Path, graph_dir: Path, ort_dir: Path, output: Path) -
|
|
| 96 |
copy_file(Path(__file__), output / "source/scripts/deploy_huggingface_space.py")
|
| 97 |
copy_file(REPO / "scripts/check_huggingface_space.mjs", output / "source/scripts/check_huggingface_space.mjs")
|
| 98 |
copy_file(REPO / "deploy/huggingface/README.md", output / "source/deploy/huggingface/README.md")
|
| 99 |
-
copy_file(REPO / "docs/assets/
|
| 100 |
|
| 101 |
def git(*args: str) -> str:
|
| 102 |
return subprocess.check_output(["git", *args], cwd=REPO, text=True).strip()
|
|
@@ -108,6 +110,7 @@ def package_space(web_dir: Path, graph_dir: Path, ort_dir: Path, output: Path) -
|
|
| 108 |
"source_dirty": bool(git("status", "--porcelain")),
|
| 109 |
"build_command": "VITE_HENDRIX_SPACE=1 npx --yes pnpm@10.20.0 --dir demo/web build --manifest",
|
| 110 |
"checkpoint_sha256": manifest["checkpoint"]["sha256"],
|
|
|
|
| 111 |
"files": {
|
| 112 |
path.relative_to(output).as_posix(): {"bytes": path.stat().st_size, "sha256": sha256(path)}
|
| 113 |
for path in sorted(output.rglob("*")) if path.is_file()
|
|
|
|
| 81 |
for filename in ORT_FILES:
|
| 82 |
copy_file(ort_dir / filename, output / "ort" / filename)
|
| 83 |
|
| 84 |
+
# Use the public CC-BY demo mix, skipping its silent opening. Never copy
|
| 85 |
+
# the private YouTube jazz diagnostic or the local examples directory.
|
| 86 |
+
with wave.open(str(REPO / "docs/assets/slakh_test_Track01876.wav"), "rb") as source:
|
| 87 |
with wave.open(str(output / "diagnostic.wav"), "wb") as target:
|
| 88 |
target.setparams(source.getparams())
|
| 89 |
+
source.setpos(6 * source.getframerate())
|
| 90 |
+
target.writeframes(source.readframes(2 * source.getframerate()))
|
| 91 |
|
| 92 |
copy_file(REPO / "deploy/huggingface/README.md", output / "README.md")
|
| 93 |
# Keep the exact app source next to the build for review and reproduction.
|
|
|
|
| 98 |
copy_file(Path(__file__), output / "source/scripts/deploy_huggingface_space.py")
|
| 99 |
copy_file(REPO / "scripts/check_huggingface_space.mjs", output / "source/scripts/check_huggingface_space.mjs")
|
| 100 |
copy_file(REPO / "deploy/huggingface/README.md", output / "source/deploy/huggingface/README.md")
|
| 101 |
+
copy_file(REPO / "docs/assets/slakh_test_Track01876.wav", output / "source/docs/assets/slakh_test_Track01876.wav")
|
| 102 |
|
| 103 |
def git(*args: str) -> str:
|
| 104 |
return subprocess.check_output(["git", *args], cwd=REPO, text=True).strip()
|
|
|
|
| 110 |
"source_dirty": bool(git("status", "--porcelain")),
|
| 111 |
"build_command": "VITE_HENDRIX_SPACE=1 npx --yes pnpm@10.20.0 --dir demo/web build --manifest",
|
| 112 |
"checkpoint_sha256": manifest["checkpoint"]["sha256"],
|
| 113 |
+
"example": {"source": "Slakh2100 Track01876", "clip_offset_seconds": 6, "duration_seconds": 2, "license": "CC-BY-4.0"},
|
| 114 |
"files": {
|
| 115 |
path.relative_to(output).as_posix(): {"bytes": path.stat().st_size, "sha256": sha256(path)}
|
| 116 |
for path in sorted(output.rglob("*")) if path.is_file()
|