b84827ecea
- New: transcribe-about.php, transcribe-guide.php, transcribe-tech.php with full en/no/uk/pl translations (3-engine cascade, diarization, vocab) - New: translations/transcribe-about|guide|tech.php (4-lang strings) - New: scripts/translate-pages.php (Azure gpt-4o CLI translation helper) - Add korr-doc-links nav to transcribe.php - Refresh redact-about|guide|tech.php — point to assets/images/redact/ - Fix all "never written to disk" wording in redact translations - Add Min Sak/corpus save workflow to redact guide and tech privacy section - redact.php upload hint: correct in-memory wording Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
263 lines
14 KiB
PHP
263 lines
14 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
require_once __DIR__ . '/includes/bootstrap.php';
|
||
|
||
$uiLang = dbnToolsCurrentLanguage();
|
||
$isAuthed = dbnToolsIsAuthenticated();
|
||
$langPath = '/transcribe-tech.php';
|
||
$toolsLogin = 'https://dobetternorge.no/tools-login.php?return=' . urlencode('/transcribe.php');
|
||
|
||
$_pt = require __DIR__ . '/translations/transcribe-tech.php';
|
||
$t = $_pt[$uiLang] ?? $_pt['en'];
|
||
?>
|
||
<!doctype html>
|
||
<html lang="<?= htmlspecialchars($uiLang) ?>">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>How Transcribe Works — Three-engine cascade, Whisper GPU, pyannote diarization · Do Better Norge Tools</title>
|
||
<meta name="description" content="Technical deep-dive: Azure Batch Speech → Google Cloud Speech-to-Text v2 → Whisper large-v3 GPU cascade, pyannote.audio speaker diarization, vocabulary injection, and GPT-4o cleanup pipeline.">
|
||
<meta name="robots" content="index, follow">
|
||
<link rel="canonical" href="https://tools.dobetternorge.no/transcribe-tech.php">
|
||
<meta property="og:title" content="How Transcribe Works — Technical Reference">
|
||
<meta property="og:description" content="Three-engine cascade: Azure Speech, Google Cloud Chirp, Whisper GPU. Speaker diarization with pyannote.audio. Optional GPT-4o cleanup. Privacy-first data handling.">
|
||
<meta name="theme-color" content="#00205B">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Crimson+Pro:wght@400;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap">
|
||
<link rel="stylesheet" href="assets/css/tools.css">
|
||
<link rel="stylesheet" href="assets/css/dbn-tools-redesign.css">
|
||
</head>
|
||
<body class="kdoc-page">
|
||
|
||
<header class="lt-nav">
|
||
<a href="https://dobetternorge.no" class="lt-nav__brand">
|
||
<picture>
|
||
<source srcset="assets/images/logo-header.webp" type="image/webp">
|
||
<img class="lt-nav__logo" src="assets/images/logo-header.png" alt="Do Better Norge" width="140" height="36" loading="eager">
|
||
</picture>
|
||
<span class="lt-nav__badge">Legal Tools</span>
|
||
</a>
|
||
<div class="lt-nav__right">
|
||
<nav class="shell-lang-switcher" aria-label="Language">
|
||
<?php foreach (dbnToolsSupportedLanguages() as $langCode): ?>
|
||
<a href="<?= htmlspecialchars($langPath . '?lang=' . $langCode) ?>" class="<?= $langCode === $uiLang ? 'is-active' : '' ?>"><?= htmlspecialchars(dbnToolsLanguageLabel($langCode)) ?></a>
|
||
<?php endforeach; ?>
|
||
</nav>
|
||
<?php if ($isAuthed): ?>
|
||
<a href="/transcribe.php" class="lt-nav__cta lt-nav__cta--enter"><?= htmlspecialchars($t['nav_open']) ?></a>
|
||
<?php else: ?>
|
||
<a href="<?= htmlspecialchars($toolsLogin) ?>" class="lt-nav__cta"><?= htmlspecialchars($t['nav_signin']) ?></a>
|
||
<?php endif; ?>
|
||
</div>
|
||
</header>
|
||
|
||
<nav class="kdoc-doc-nav" aria-label="Transcribe documentation">
|
||
<div class="kdoc-doc-nav__inner">
|
||
<a href="/transcribe-about.php"><?= htmlspecialchars($t['nav_about']) ?></a>
|
||
<a href="/transcribe-guide.php"><?= htmlspecialchars($t['nav_guide']) ?></a>
|
||
<a href="/transcribe-tech.php" class="is-active"><?= htmlspecialchars($t['nav_howit']) ?></a>
|
||
<?php if ($isAuthed): ?><a href="/transcribe.php"><?= htmlspecialchars($t['nav_opentool']) ?></a><?php endif; ?>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- Hero -->
|
||
<section class="kdoc-hero" style="background: linear-gradient(rgba(0,15,50,0.88),rgba(0,15,50,0.93)), url('assets/images/transcribe/hero-tech.png') center/cover no-repeat;">
|
||
<div class="kdoc-hero__inner">
|
||
<p class="kdoc-hero__kicker"><?= htmlspecialchars($t['hero_kicker']) ?></p>
|
||
<h1 class="kdoc-hero__title"><?= htmlspecialchars($t['hero_title']) ?></h1>
|
||
<p class="kdoc-hero__sub"><?= htmlspecialchars($t['hero_sub']) ?></p>
|
||
|
||
<div class="kdoc-hero__stats">
|
||
<div class="kdoc-hero__stat">
|
||
<strong>3</strong>
|
||
<span><?= htmlspecialchars($t['stat_engines']) ?></span>
|
||
</div>
|
||
<div class="kdoc-hero__stat">
|
||
<strong>2–4×</strong>
|
||
<span><?= htmlspecialchars($t['stat_latency']) ?></span>
|
||
</div>
|
||
<div class="kdoc-hero__stat">
|
||
<strong><5%</strong>
|
||
<span><?= htmlspecialchars($t['stat_wer']) ?></span>
|
||
</div>
|
||
<div class="kdoc-hero__stat">
|
||
<strong>20</strong>
|
||
<span><?= htmlspecialchars($t['stat_speakers']) ?></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="kdoc-section">
|
||
|
||
<div class="kdoc-toc">
|
||
<p class="kdoc-toc__title"><?= htmlspecialchars($t['toc_title']) ?></p>
|
||
<ol>
|
||
<li><a href="#arch"><?= htmlspecialchars($t['toc_1']) ?></a></li>
|
||
<li><a href="#azure"><?= htmlspecialchars($t['toc_2']) ?></a></li>
|
||
<li><a href="#google"><?= htmlspecialchars($t['toc_3']) ?></a></li>
|
||
<li><a href="#whisper"><?= htmlspecialchars($t['toc_4']) ?></a></li>
|
||
<li><a href="#diarization"><?= htmlspecialchars($t['toc_5']) ?></a></li>
|
||
<li><a href="#vocab"><?= htmlspecialchars($t['toc_6']) ?></a></li>
|
||
<li><a href="#cleanup"><?= htmlspecialchars($t['toc_7']) ?></a></li>
|
||
<li><a href="#languages"><?= htmlspecialchars($t['toc_8']) ?></a></li>
|
||
<li><a href="#privacy"><?= htmlspecialchars($t['toc_9']) ?></a></li>
|
||
</ol>
|
||
</div>
|
||
|
||
<!-- Architecture -->
|
||
<div class="kdoc-guide-step" id="arch">
|
||
<h2 class="kdoc-guide-step__title"><?= htmlspecialchars($t['arch_title']) ?></h2>
|
||
<p><?= htmlspecialchars($t['arch_intro']) ?></p>
|
||
|
||
<div class="kdoc-pipeline">
|
||
<p class="kdoc-pipeline__label"><?= htmlspecialchars($t['arch_cascade_label']) ?></p>
|
||
<div class="kdoc-pipeline__stages">
|
||
<div class="kdoc-pipeline__stage kdoc-pipeline__stage--primary">
|
||
<span class="kdoc-pipeline__num">1</span>
|
||
<strong><?= htmlspecialchars($t['arch_e1']) ?></strong>
|
||
<small><?= htmlspecialchars($t['arch_e1_sub']) ?></small>
|
||
</div>
|
||
<span class="kdoc-pipeline__arrow" aria-hidden="true">↓</span>
|
||
<div class="kdoc-pipeline__stage">
|
||
<span class="kdoc-pipeline__num">2</span>
|
||
<strong><?= htmlspecialchars($t['arch_e2']) ?></strong>
|
||
<small><?= htmlspecialchars($t['arch_e2_sub']) ?></small>
|
||
</div>
|
||
<span class="kdoc-pipeline__arrow" aria-hidden="true">↓</span>
|
||
<div class="kdoc-pipeline__stage">
|
||
<span class="kdoc-pipeline__num">3</span>
|
||
<strong><?= htmlspecialchars($t['arch_e3']) ?></strong>
|
||
<small><?= htmlspecialchars($t['arch_e3_sub']) ?></small>
|
||
</div>
|
||
<span class="kdoc-pipeline__arrow kdoc-pipeline__arrow--right" aria-hidden="true">→</span>
|
||
<div class="kdoc-pipeline__stage kdoc-pipeline__stage--optional">
|
||
<strong><?= htmlspecialchars($t['arch_post1']) ?></strong>
|
||
<small><?= htmlspecialchars($t['arch_post1_sub']) ?></small>
|
||
</div>
|
||
<span class="kdoc-pipeline__arrow" aria-hidden="true">↓</span>
|
||
<div class="kdoc-pipeline__stage kdoc-pipeline__stage--optional">
|
||
<strong><?= htmlspecialchars($t['arch_post2']) ?></strong>
|
||
<small><?= htmlspecialchars($t['arch_post2_sub']) ?></small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Engine 1: Azure -->
|
||
<div class="kdoc-guide-step" id="azure">
|
||
<h2 class="kdoc-guide-step__title"><?= htmlspecialchars($t['e1_title']) ?></h2>
|
||
<p><?= htmlspecialchars($t['e1_intro']) ?></p>
|
||
<ul class="kdoc-list">
|
||
<li><?= $t['e1_model'] ?></li>
|
||
<li><?= htmlspecialchars($t['e1_latency']) ?></li>
|
||
<li><?= htmlspecialchars($t['e1_format']) ?></li>
|
||
<li><?= htmlspecialchars($t['e1_auth']) ?></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- Engine 2: Google -->
|
||
<div class="kdoc-guide-step" id="google">
|
||
<h2 class="kdoc-guide-step__title"><?= htmlspecialchars($t['e2_title']) ?></h2>
|
||
<p><?= htmlspecialchars($t['e2_intro']) ?></p>
|
||
<ul class="kdoc-list">
|
||
<li><?= $t['e2_model'] ?></li>
|
||
<li><?= htmlspecialchars($t['e2_latency']) ?></li>
|
||
<li><?= htmlspecialchars($t['e2_format']) ?></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- Engine 3: Whisper -->
|
||
<div class="kdoc-guide-step" id="whisper">
|
||
<h2 class="kdoc-guide-step__title"><?= htmlspecialchars($t['e3_title']) ?></h2>
|
||
<p><?= htmlspecialchars($t['e3_intro']) ?></p>
|
||
<ul class="kdoc-list">
|
||
<li><?= $t['e3_model'] ?></li>
|
||
<li><?= $t['e3_vocab'] ?></li>
|
||
<li><?= $t['e3_vad'] ?></li>
|
||
<li><?= htmlspecialchars($t['e3_latency']) ?></li>
|
||
</ul>
|
||
<p class="kdoc-guide-note">🏠 <?= htmlspecialchars($t['e3_note']) ?></p>
|
||
</div>
|
||
|
||
<!-- Speaker diarization -->
|
||
<div class="kdoc-guide-step" id="diarization">
|
||
<h2 class="kdoc-guide-step__title"><?= htmlspecialchars($t['diar_title']) ?></h2>
|
||
<p><?= $t['diar_intro'] ?></p>
|
||
<p><strong><?= $t['diar_pipeline'] ?></strong></p>
|
||
<p><?= htmlspecialchars($t['diar_flow']) ?></p>
|
||
<ol class="kdoc-list">
|
||
<li><?= htmlspecialchars($t['diar_f1']) ?></li>
|
||
<li><?= htmlspecialchars($t['diar_f2']) ?></li>
|
||
<li><?= htmlspecialchars($t['diar_f3']) ?></li>
|
||
<li><?= htmlspecialchars($t['diar_f4']) ?></li>
|
||
</ol>
|
||
<p><?= $t['diar_count'] ?></p>
|
||
<p class="kdoc-guide-note"><?= htmlspecialchars($t['diar_limit']) ?></p>
|
||
</div>
|
||
|
||
<!-- Vocabulary -->
|
||
<div class="kdoc-guide-step" id="vocab">
|
||
<h2 class="kdoc-guide-step__title"><?= htmlspecialchars($t['vocab_title']) ?></h2>
|
||
<p><?= $t['vocab_intro'] ?></p>
|
||
<p><?= htmlspecialchars($t['vocab_limit']) ?></p>
|
||
<p><?= htmlspecialchars($t['vocab_builtin']) ?></p>
|
||
<p class="kdoc-guide-note">⚠️ <?= htmlspecialchars($t['vocab_note']) ?></p>
|
||
</div>
|
||
|
||
<!-- Cleanup -->
|
||
<div class="kdoc-guide-step" id="cleanup">
|
||
<h2 class="kdoc-guide-step__title"><?= htmlspecialchars($t['cleanup_title']) ?></h2>
|
||
<p><?= htmlspecialchars($t['cleanup_intro']) ?></p>
|
||
<p><?= htmlspecialchars($t['cleanup_prompt']) ?></p>
|
||
<ul class="kdoc-list">
|
||
<li><?= $t['cleanup_mini'] ?></li>
|
||
<li><?= $t['cleanup_full'] ?></li>
|
||
</ul>
|
||
<p class="kdoc-guide-note">🔒 <?= htmlspecialchars($t['cleanup_privacy']) ?></p>
|
||
</div>
|
||
|
||
<!-- Language support -->
|
||
<div class="kdoc-guide-step" id="languages">
|
||
<h2 class="kdoc-guide-step__title"><?= htmlspecialchars($t['lang_title']) ?></h2>
|
||
<p><?= htmlspecialchars($t['lang_intro']) ?></p>
|
||
<table class="kdoc-table">
|
||
<thead><tr>
|
||
<th><?= htmlspecialchars($t['lang_table_lang']) ?></th>
|
||
<th><?= htmlspecialchars($t['lang_table_engine']) ?></th>
|
||
<th><?= htmlspecialchars($t['lang_table_notes']) ?></th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr><td><?= htmlspecialchars($t['lang_nb']) ?></td><td><code><?= htmlspecialchars($t['lang_nb_engine']) ?></code></td><td><?= htmlspecialchars($t['lang_nb_notes']) ?></td></tr>
|
||
<tr><td><?= htmlspecialchars($t['lang_nn']) ?></td><td><code><?= htmlspecialchars($t['lang_nn_engine']) ?></code></td><td><?= htmlspecialchars($t['lang_nn_notes']) ?></td></tr>
|
||
<tr><td><?= htmlspecialchars($t['lang_en']) ?></td><td><code><?= htmlspecialchars($t['lang_en_engine']) ?></code></td><td><?= htmlspecialchars($t['lang_en_notes']) ?></td></tr>
|
||
<tr><td><?= htmlspecialchars($t['lang_pl']) ?></td><td><code><?= htmlspecialchars($t['lang_pl_engine']) ?></code></td><td><?= htmlspecialchars($t['lang_pl_notes']) ?></td></tr>
|
||
<tr><td><?= htmlspecialchars($t['lang_uk']) ?></td><td><code><?= htmlspecialchars($t['lang_uk_engine']) ?></code></td><td><?= htmlspecialchars($t['lang_uk_notes']) ?></td></tr>
|
||
<tr><td><?= htmlspecialchars($t['lang_sv']) ?></td><td><code><?= htmlspecialchars($t['lang_sv_engine']) ?></code></td><td><?= htmlspecialchars($t['lang_sv_notes']) ?></td></tr>
|
||
<tr><td><?= htmlspecialchars($t['lang_da']) ?></td><td><code><?= htmlspecialchars($t['lang_da_engine']) ?></code></td><td><?= htmlspecialchars($t['lang_da_notes']) ?></td></tr>
|
||
<tr><td><?= htmlspecialchars($t['lang_de']) ?></td><td><code><?= htmlspecialchars($t['lang_de_engine']) ?></code></td><td><?= htmlspecialchars($t['lang_de_notes']) ?></td></tr>
|
||
<tr><td><?= htmlspecialchars($t['lang_fr']) ?></td><td><code><?= htmlspecialchars($t['lang_fr_engine']) ?></code></td><td><?= htmlspecialchars($t['lang_fr_notes']) ?></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- Privacy -->
|
||
<div class="kdoc-guide-step" id="privacy">
|
||
<h2 class="kdoc-guide-step__title"><?= htmlspecialchars($t['priv_title']) ?></h2>
|
||
<ul class="kdoc-list">
|
||
<li>🔒 <?= htmlspecialchars($t['priv_1']) ?></li>
|
||
<li>☁️ <?= htmlspecialchars($t['priv_2']) ?></li>
|
||
<li>🏠 <?= htmlspecialchars($t['priv_3']) ?></li>
|
||
<li>🤖 <?= htmlspecialchars($t['priv_4']) ?></li>
|
||
<li>✅ <?= htmlspecialchars($t['priv_5']) ?></li>
|
||
</ul>
|
||
</div>
|
||
|
||
</div><!-- /.kdoc-section -->
|
||
|
||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||
<script src="assets/js/tools.js" defer></script>
|
||
</body>
|
||
</html>
|