Spaces:
Running on Zero
Running on Zero
Update transcription-editor.html
Browse files- transcription-editor.html +47 -4
transcription-editor.html
CHANGED
|
@@ -192,7 +192,7 @@
|
|
| 192 |
.pmi-slot.filled{color:#2a7; border-color:#bfe0cd; font-weight:600}
|
| 193 |
.pmi-result{margin-top:14px; font-size:13px; color:var(--ink)}
|
| 194 |
.pmi-result.stale{opacity:.5}
|
| 195 |
-
.pmi-result.stale::before{content:"An excerpt changed since this was computed \2014 compute again to update it";
|
| 196 |
display:block; margin-bottom:8px; font-size:11.5px; color:#9a6a1f; opacity:1}
|
| 197 |
.pmi-score{font-size:30px; font-weight:600; letter-spacing:-.01em; font-variant-numeric:tabular-nums}
|
| 198 |
.pmi-keys{font-size:12px; color:var(--muted); margin:4px 0 10px}
|
|
@@ -635,7 +635,14 @@ function startSharedTimer(estLo, estHi){
|
|
| 635 |
const tStart = Date.now();
|
| 636 |
const frames = ["\u280b","\u2819","\u2839","\u2838","\u283c","\u2834","\u2826","\u2827","\u2807","\u280f"];
|
| 637 |
let k = 0;
|
| 638 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 639 |
const tick = ()=>{
|
| 640 |
const el = (Date.now()-tStart)/1000;
|
| 641 |
const sp = frames[k++ % frames.length];
|
|
@@ -1787,6 +1794,11 @@ function createPanel(KEY, root){
|
|
| 1787 |
+ `Not right? Drag the handles to adjust and transcribe again.`;
|
| 1788 |
$(".js-stage").hidden = false;
|
| 1789 |
refreshReadout(); drawWave(); draw();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1790 |
await analyseKey(); // key estimate is ready before you look for it
|
| 1791 |
}
|
| 1792 |
|
|
@@ -2244,6 +2256,10 @@ function createPanel(KEY, root){
|
|
| 2244 |
the only path, which halves the run count and pays the fixed GPU overhead
|
| 2245 |
(fork, CUDA attach, weight streaming) once instead of twice. */
|
| 2246 |
let pairBusy = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2247 |
// The shared button clears instead of transcribing once both excerpts hold
|
| 2248 |
// notes, however they arrived -- transcribed, imported or restored.
|
| 2249 |
function bothHaveNotes(){
|
|
@@ -2252,8 +2268,12 @@ function bothHaveNotes(){
|
|
| 2252 |
}
|
| 2253 |
function syncPairButton(){
|
| 2254 |
const btn = document.getElementById("btnTranscribePair");
|
| 2255 |
-
if(!btn
|
| 2256 |
const done = bothHaveNotes();
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2257 |
btn.textContent = done ? "Clear" : "Transcribe both excerpts \u2192";
|
| 2258 |
btn.title = done ? "Clear both excerpts and start over" : "";
|
| 2259 |
btn.classList.toggle("danger", done);
|
|
@@ -2267,6 +2287,7 @@ async function transcribeBoth(){
|
|
| 2267 |
if(bothHaveNotes()){
|
| 2268 |
if(!confirm("Clear both excerpts and start over?")) return;
|
| 2269 |
resetPanel("A"); resetPanel("B");
|
|
|
|
| 2270 |
clearSnapshot();
|
| 2271 |
document.getElementById("dualName").textContent =
|
| 2272 |
"Load two audio files";
|
|
@@ -2309,6 +2330,7 @@ async function transcribeBoth(){
|
|
| 2309 |
await B.pairApply(data.b);
|
| 2310 |
stopSharedTimer();
|
| 2311 |
sharedStatus().textContent = `A: ${A.doneMsg()} | B: ${B.doneMsg()}`;
|
|
|
|
| 2312 |
writeSnapshot(); // a fresh transcription is worth persisting at once
|
| 2313 |
}catch(err){
|
| 2314 |
stopSharedTimer();
|
|
@@ -2559,7 +2581,28 @@ function stopEveryPanel(except){
|
|
| 2559 |
}
|
| 2560 |
function markStale(){
|
| 2561 |
const box=document.getElementById("pmiResult");
|
| 2562 |
-
if(box && !box.hidden)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2563 |
refreshPmiState();
|
| 2564 |
}
|
| 2565 |
function refreshPmiState(){
|
|
|
|
| 192 |
.pmi-slot.filled{color:#2a7; border-color:#bfe0cd; font-weight:600}
|
| 193 |
.pmi-result{margin-top:14px; font-size:13px; color:var(--ink)}
|
| 194 |
.pmi-result.stale{opacity:.5}
|
| 195 |
+
.pmi-result.stale::before{content:"An excerpt changed since this was computed \2014 compute again to update it, and to export a report";
|
| 196 |
display:block; margin-bottom:8px; font-size:11.5px; color:#9a6a1f; opacity:1}
|
| 197 |
.pmi-score{font-size:30px; font-weight:600; letter-spacing:-.01em; font-variant-numeric:tabular-nums}
|
| 198 |
.pmi-keys{font-size:12px; color:var(--muted); margin:4px 0 10px}
|
|
|
|
| 635 |
const tStart = Date.now();
|
| 636 |
const frames = ["\u280b","\u2819","\u2839","\u2838","\u283c","\u2834","\u2826","\u2827","\u2807","\u280f"];
|
| 637 |
let k = 0;
|
| 638 |
+
// The estimate describes a warm Space. The first call of a session also pays
|
| 639 |
+
// for waking the Space and streaming the model weights onto the GPU, which is
|
| 640 |
+
// the difference between "slow" and "stuck" from where the user is sitting --
|
| 641 |
+
// so say it while it is happening, not afterwards.
|
| 642 |
+
const est = ` (both excerpts together usually take ~${estLo}\u2013${estHi}s on GPU`
|
| 643 |
+
+ (firstRunDone ? ")"
|
| 644 |
+
: "; the first run can take considerably longer while the "
|
| 645 |
+
+ "Space wakes up and loads the models)");
|
| 646 |
const tick = ()=>{
|
| 647 |
const el = (Date.now()-tStart)/1000;
|
| 648 |
const sp = frames[k++ % frames.length];
|
|
|
|
| 1794 |
+ `Not right? Drag the handles to adjust and transcribe again.`;
|
| 1795 |
$(".js-stage").hidden = false;
|
| 1796 |
refreshReadout(); drawWave(); draw();
|
| 1797 |
+
// Flip the shared button HERE, not after the awaits below: analyseKey is a
|
| 1798 |
+
// round trip to /analyze, and waiting for both panels' key estimates left
|
| 1799 |
+
// the button reading "Transcribe" for a beat after the notes were already
|
| 1800 |
+
// drawn. The notes are what the button's state depends on, and they are in.
|
| 1801 |
+
syncPairButton();
|
| 1802 |
await analyseKey(); // key estimate is ready before you look for it
|
| 1803 |
}
|
| 1804 |
|
|
|
|
| 2256 |
the only path, which halves the run count and pays the fixed GPU overhead
|
| 2257 |
(fork, CUDA attach, weight streaming) once instead of twice. */
|
| 2258 |
let pairBusy = false;
|
| 2259 |
+
// Set once a transcription has actually come back, so the cold-start warning in
|
| 2260 |
+
// the progress line stops being shown after the Space is demonstrably awake. A
|
| 2261 |
+
// failed call leaves it false: the next attempt is still a first run.
|
| 2262 |
+
let firstRunDone = false;
|
| 2263 |
// The shared button clears instead of transcribing once both excerpts hold
|
| 2264 |
// notes, however they arrived -- transcribed, imported or restored.
|
| 2265 |
function bothHaveNotes(){
|
|
|
|
| 2268 |
}
|
| 2269 |
function syncPairButton(){
|
| 2270 |
const btn = document.getElementById("btnTranscribePair");
|
| 2271 |
+
if(!btn) return;
|
| 2272 |
const done = bothHaveNotes();
|
| 2273 |
+
// Mid-flight the label must not move until BOTH excerpts have landed, but
|
| 2274 |
+
// once they have there is no reason to wait for the call to unwind: the
|
| 2275 |
+
// notes are on screen, so the button should already say what it now does.
|
| 2276 |
+
if(pairBusy && !done) return;
|
| 2277 |
btn.textContent = done ? "Clear" : "Transcribe both excerpts \u2192";
|
| 2278 |
btn.title = done ? "Clear both excerpts and start over" : "";
|
| 2279 |
btn.classList.toggle("danger", done);
|
|
|
|
| 2287 |
if(bothHaveNotes()){
|
| 2288 |
if(!confirm("Clear both excerpts and start over?")) return;
|
| 2289 |
resetPanel("A"); resetPanel("B");
|
| 2290 |
+
clearPmiResult(); // the score belongs to the notes that just went away
|
| 2291 |
clearSnapshot();
|
| 2292 |
document.getElementById("dualName").textContent =
|
| 2293 |
"Load two audio files";
|
|
|
|
| 2330 |
await B.pairApply(data.b);
|
| 2331 |
stopSharedTimer();
|
| 2332 |
sharedStatus().textContent = `A: ${A.doneMsg()} | B: ${B.doneMsg()}`;
|
| 2333 |
+
firstRunDone = true; // the Space is awake; later runs get the plain estimate
|
| 2334 |
writeSnapshot(); // a fresh transcription is worth persisting at once
|
| 2335 |
}catch(err){
|
| 2336 |
stopSharedTimer();
|
|
|
|
| 2581 |
}
|
| 2582 |
function markStale(){
|
| 2583 |
const box=document.getElementById("pmiResult");
|
| 2584 |
+
if(box && !box.hidden){
|
| 2585 |
+
box.classList.add("stale");
|
| 2586 |
+
// The score stays on screen, greyed, because it still says something about
|
| 2587 |
+
// what the user just changed. The REPORT does not: a PDF pairs that number
|
| 2588 |
+
// with freshly captured rolls, so an edited excerpt would be documented
|
| 2589 |
+
// against a score it no longer belongs to. Recompute to get it back.
|
| 2590 |
+
const bar = document.getElementById("pdfBar");
|
| 2591 |
+
if(bar) bar.hidden = true;
|
| 2592 |
+
}
|
| 2593 |
+
refreshPmiState();
|
| 2594 |
+
}
|
| 2595 |
+
/* Editing the notes only marks the score stale -- it still describes something
|
| 2596 |
+
the user can see. Clearing the excerpts is different: the notes it was
|
| 2597 |
+
computed from are gone, so leaving the number on screen lets a PDF pair the
|
| 2598 |
+
old score with new rolls. Remove it outright, along with the alignment state
|
| 2599 |
+
and the report button it enabled. */
|
| 2600 |
+
function clearPmiResult(){
|
| 2601 |
+
const box = document.getElementById("pmiResult");
|
| 2602 |
+
if(box){ box.hidden = true; box.classList.remove("stale"); box.innerHTML = ""; }
|
| 2603 |
+
const bar = document.getElementById("pdfBar");
|
| 2604 |
+
if(bar) bar.hidden = true;
|
| 2605 |
+
alnEdit = null;
|
| 2606 |
refreshPmiState();
|
| 2607 |
}
|
| 2608 |
function refreshPmiState(){
|