File size: 7,603 Bytes
dbc1132 4fa39ce dbc1132 9e600a5 dbc1132 9e600a5 dbc1132 4fa39ce dbc1132 b7e38a0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Granite Speech WebGPU</title>
<link rel="stylesheet" href="style.css?v=3">
</head>
<body>
<div class="container">
<!-- Header -->
<h1>Granite Speech WebGPU</h1>
<h2>Speech recognition and translation directly in your browser</h2>
<!-- Audio Input Card -->
<div class="input-card">
<div class="input-options">
<button id="recordBtn" class="input-tile" disabled>
<svg class="mic-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 18.75a6 6 0 006-6v-1.5m-6 7.5a6 6 0 01-6-6v-1.5m6 7.5v3.75m-3.75 0h7.5M12 15.75a3 3 0 01-3-3V4.5a3 3 0 116 0v8.25a3 3 0 01-3 3z" />
</svg>
<svg class="stop-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" style="display: none;">
<rect x="6" y="6" width="12" height="12" rx="1" />
</svg>
<span>Record</span>
</button>
<div class="divider"></div>
<label class="input-tile file-label">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5 0a2.25 2.25 0 00-1.883 2.542l.857 6a2.25 2.25 0 002.227 1.932H19.05a2.25 2.25 0 002.227-1.932l.857-6a2.25 2.25 0 00-1.883-2.542m-16.5 0V6A2.25 2.25 0 016 3.75h3.879a1.5 1.5 0 011.06.44l2.122 2.12a1.5 1.5 0 001.06.44H18A2.25 2.25 0 0120.25 9v.776" />
</svg>
<span>Upload</span>
<input type="file" id="audioFile" accept="audio/*" hidden>
</label>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
</div>
<!-- Status -->
<div class="status-section" id="statusSection">
<span class="status-dot" id="statusDot"></span>
<span id="statusText">Loading...</span>
</div>
<!-- Audio Player (hidden initially) -->
<div class="audio-player" id="audioPreview" style="display: none;">
<button class="play-btn" id="playBtn">
<svg class="play-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path d="M8 5v14l11-7z"/>
</svg>
<svg class="pause-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" style="display: none;">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
</svg>
</button>
<div class="waveform-container">
<canvas id="waveformCanvas"></canvas>
<div class="waveform-progress" id="waveformProgress"></div>
</div>
<span class="audio-time" id="audioTime">0:00</span>
<button class="clear-btn" id="clearBtn" title="Clear">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<audio id="audioPlayer" style="display: none;"></audio>
</div>
<!-- Transcribe Section -->
<div class="transcribe-section" id="transcribeSection" style="display: none;">
<div class="task-row">
<label for="promptSelect">Task:</label>
<select id="promptSelect">
<option value="transcribe">Transcribe</option>
<option value="translate_en">Translate to English</option>
<option value="translate_fr">Translate to French</option>
<option value="translate_de">Translate to German</option>
<option value="translate_es">Translate to Spanish</option>
<option value="translate_pt">Translate to Portuguese</option>
<option value="translate_ja">Translate to Japanese</option>
</select>
</div>
<label class="checkbox-row">
<input type="checkbox" id="punctuationCheckbox" checked>
<span>Add punctuation (English only)</span>
</label>
<button id="transcribeBtn" class="transcribe-btn" disabled>
Transcribe
</button>
</div>
<!-- Model Loading Progress -->
<div class="model-progress" id="progressSection" style="display: none;">
<span id="progressText">Loading model...</span>
</div>
<!-- Transcript Output -->
<div class="transcript-card" id="transcriptCard" style="display: none;">
<div class="transcript-header">
<span>Transcript</span>
<div class="transcript-actions">
<button id="copyBtn" class="icon-btn" title="Copy">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9.75a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184" />
</svg>
</button>
<button id="downloadBtn" class="icon-btn" title="Download">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
</svg>
</button>
</div>
</div>
<div class="transcript-output" id="outputText"></div>
</div>
<!-- Footer -->
<div class="footer">
Made with
<a href="https://huggingface.co/ibm-granite/granite-4.0-1b-speech" target="_blank">Granite 4.0 1B Speech</a>
and
<a href="https://huggingface.co/docs/transformers.js" target="_blank">Transformers.js</a>
<br>
<span class="privacy-note">Your audio and transcription never leave your device</span>
</div>
<div class="gpu-info" id="gpuInfo"></div>
</div>
<!-- ORT global is retained for VAD (vad.js) and punctuation (punctuator.js) which use WASM -->
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/ort.all.min.js"></script>
<script src="vad.js?v=1"></script>
<script src="punctuator.js?v=3"></script>
<script type="module" src="app.js?v=55"></script>
</body>
</html>
|