feat(transcribe): Norwegian defaults, vocabulary presets, multi-file court day queue

- Default language → nb (Bokmål); auto-detect demoted with warning note
- Default model → large-v3; VAD filter on by default
- Vocabulary prompt promoted to main form with 4 preset buttons
  (Barnerett/CPS, Rettssak/tingrett, Generell norsk, Egendefinert)
- Multi-file upload queue: drop/select multiple clips, numbered list UI
- Sequential queue processing with cumulative time_offset per clip
- Backend shifts segment timestamps so SRT/VTT covers full court day
- Merged transcript + segments across all clips for single download

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 22:20:11 +02:00
parent df31674f2e
commit 26f4e2231b
4 changed files with 356 additions and 138 deletions
+40 -30
View File
@@ -30,65 +30,75 @@ require_once __DIR__ . '/includes/layout.php';
<div class="control-row" id="modelControl">
<span class="control-label">Model</span>
<label><input type="radio" name="model" value="small" checked> small <small class="control-hint">(fast)</small></label>
<label><input type="radio" name="model" value="medium"> medium <small class="control-hint">(balanced)</small></label>
<label><input type="radio" name="model" value="large-v3"> large-v3 <small class="control-hint">(best quality)</small></label>
<label><input type="radio" name="model" value="small"> Raskest <small class="control-hint">(small)</small></label>
<label><input type="radio" name="model" value="medium"> Balansert <small class="control-hint">(medium)</small></label>
<label><input type="radio" name="model" value="large-v3" checked> Beste kvalitet &#9733; <small class="control-hint">(large-v3)</small></label>
</div>
<div class="control-row" id="transcribeLangControl">
<span class="control-label">Language</span>
<label><input type="radio" name="transcribeLang" value="auto" checked> Auto-detect</label>
<label><input type="radio" name="transcribeLang" value="no"> Norsk (nb)</label>
<span class="control-label">Spr&aring;k</span>
<label><input type="radio" name="transcribeLang" value="no" checked> Norsk (nb)</label>
<label><input type="radio" name="transcribeLang" value="nn"> Nynorsk</label>
<label><input type="radio" name="transcribeLang" value="en"> English</label>
<label><input type="radio" name="transcribeLang" value="sv"> Svenska</label>
<label><input type="radio" name="transcribeLang" value="da"> Dansk</label>
<label><input type="radio" name="transcribeLang" value="de"> Deutsch</label>
<label><input type="radio" name="transcribeLang" value="fr"> Fran&ccedil;ais</label>
<label><input type="radio" name="transcribeLang" value="auto"> Auto-detect <small class="control-hint">(kan forveksle nb/da/sv)</small></label>
</div>
<div class="control-row" id="diarizeControl">
<span class="control-label">Speakers</span>
<label><input type="checkbox" id="diarizeCheck" name="diarize"> Separate speakers</label>
<span class="control-label" style="margin-left:1.25rem">Count</span>
<input type="number" id="numSpeakersInput" name="num_speakers" min="2" max="20" placeholder="auto" class="num-speakers-input" aria-label="Expected speaker count">
<span class="control-label">Talere</span>
<label><input type="checkbox" id="diarizeCheck" name="diarize"> Skill ut talere</label>
<span class="control-label" style="margin-left:1.25rem">Antall</span>
<input type="number" id="numSpeakersInput" name="num_speakers" min="2" max="20" placeholder="auto" class="num-speakers-input" aria-label="Forventet antall talere">
</div>
<div class="expert-field" id="vocabControl">
<div class="vocab-presets" id="vocabPresets">
<span class="control-label">Ordliste</span>
<button type="button" class="vocab-btn" data-preset="barnerett">Barnerett / CPS</button>
<button type="button" class="vocab-btn" data-preset="rettssak">Rettssak / tingrett</button>
<button type="button" class="vocab-btn" data-preset="generell">Generell norsk</button>
<button type="button" class="vocab-btn" data-preset="custom">Egendefinert</button>
</div>
<textarea id="initPromptInput" name="initial_prompt" rows="2" placeholder="Fagord og navn Whisper skal gjenkjenne, f.eks. Barnevernet, Fylkesnemnda, advokat, tingrett…" class="prompt-textarea"></textarea>
<p class="upload-hint">Hjelper Whisper gjenkjenne fagtermer. Ikke inkludert i utskriften.</p>
</div>
<div class="upload-zone" id="audioZone" role="region" aria-label="Audio upload">
<input type="file" id="audioInput" accept="audio/*,video/mp4,video/webm" aria-label="Choose audio file">
<input type="file" id="audioInput" accept="audio/*,video/mp4,video/webm" multiple aria-label="Choose audio files">
<div id="audioPrompt" class="upload-prompt">
<span class="upload-icon" aria-hidden="true">&#9654;</span>
<p>Drop audio file here, or <label for="audioInput" class="upload-browse">browse</label></p>
<p class="upload-hint"><strong>MP3</strong>, <strong>WAV</strong>, <strong>OGG</strong>, <strong>M4A</strong>, <strong>FLAC</strong>, <strong>WEBM</strong> &mdash; max 200&thinsp;MB</p>
<p>Slipp lydfil(er) her, eller <label for="audioInput" class="upload-browse">bla</label></p>
<p class="upload-hint"><strong>MP3</strong>, <strong>WAV</strong>, <strong>OGG</strong>, <strong>M4A</strong>, <strong>FLAC</strong>, <strong>WEBM</strong> &mdash; maks 200&thinsp;MB per fil</p>
</div>
<div id="audioFileInfo" class="upload-file is-hidden">
<ul class="upload-file-list"><li id="audioFileLine"><span id="audioFileName" class="upload-filename"></span><span id="audioFileSize" class="upload-chars"></span></li></ul>
<button type="button" id="audioClear" class="upload-clear" aria-label="Clear audio file">&times;</button>
<ol id="audioQueueList" class="audio-queue-list"></ol>
<div class="audio-queue-actions">
<label for="audioInput" class="upload-browse">+ Legg til filer</label>
<button type="button" id="audioClear" class="upload-clear" aria-label="T&oslash;m k&oslash;">&times; T&oslash;m k&oslash;</button>
</div>
</div>
</div>
<details class="expert-settings" id="expertSettings">
<summary class="expert-summary">Expert settings</summary>
<summary class="expert-summary">Ekspertinnstillinger</summary>
<div class="expert-body">
<div class="control-row">
<span class="control-label">Task</span>
<label><input type="radio" name="task" value="transcribe" checked> Transcribe</label>
<label><input type="radio" name="task" value="translate"> Translate to English</label>
<span class="control-label">Oppgave</span>
<label><input type="radio" name="task" value="transcribe" checked> Transkriber</label>
<label><input type="radio" name="task" value="translate"> Oversett til engelsk</label>
</div>
<div class="control-row">
<span class="control-label">Beam size</span>
<label><input type="radio" name="beam_size" value="1"> 1 <small class="control-hint">(fastest)</small></label>
<label><input type="radio" name="beam_size" value="1"> 1 <small class="control-hint">(raskest)</small></label>
<label><input type="radio" name="beam_size" value="3"> 3</label>
<label><input type="radio" name="beam_size" value="5" checked> 5 <small class="control-hint">(best)</small></label>
</div>
<div class="control-row">
<span class="control-label">VAD filter</span>
<label><input type="checkbox" name="vad_filter" id="vadFilterCheck" value="1"> Strip silence</label>
</div>
<div class="expert-field">
<label class="control-label" for="initPromptInput">Initial prompt</label>
<textarea id="initPromptInput" name="initial_prompt" rows="2" placeholder="Seed with domain vocabulary, e.g. Barnevernet, Fylkesnemnd, advokat, tingrett…" class="prompt-textarea"></textarea>
<p class="upload-hint">Helps Whisper recognise specialist terms. Not included in output.</p>
<span class="control-label">VAD-filter</span>
<label><input type="checkbox" name="vad_filter" id="vadFilterCheck" value="1" checked> Fjern stillhet</label>
</div>
</div>
</details>
@@ -110,14 +120,14 @@ require_once __DIR__ . '/includes/layout.php';
<div class="form-footer">
<p id="toolStatus" class="form-status" role="status" aria-live="polite"></p>
<button id="runButton" type="submit">Run Tool</button>
<button id="runButton" type="submit">Kj&oslash;r</button>
</div>
</form>
<section id="results" class="results" aria-live="polite">
<div class="empty-state">
<h3>Ready</h3>
<p>Choose a tool, run a request, and the answer will show the evidence trail beside it.</p>
<h3>Klar</h3>
<p>Velg et verkt&oslash;y, kj&oslash;r en foresp&oslash;rsel, og svaret vises her.</p>
</div>
</section>
<?php require_once __DIR__ . '/includes/layout_footer.php'; ?>