Use local faster-whisper only for transcription.
Drop cloud and Ollama engine choices so audio stays on-machine via Docker Whisper, and tighten orphan detection plus UI around a single local flow.
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
x-data="transcriptionMonitor(@js([
|
||||
'statusUrl' => route('recordings.transcription-status', $recording),
|
||||
'initial' => $recording->transcriptionStatusPayload(),
|
||||
'driver' => old('driver', $recording->transcription_driver ?: 'cloud'),
|
||||
]))"
|
||||
x-init="start()"
|
||||
>
|
||||
@@ -67,68 +66,25 @@
|
||||
<dt class="text-stone-500">Uploaded</dt>
|
||||
<dd class="font-medium">{{ $recording->created_at?->format('Y-m-d H:i') }}</dd>
|
||||
</div>
|
||||
@if ($recording->ollama_url)
|
||||
<div class="flex justify-between gap-4">
|
||||
<dt class="text-stone-500">Ollama host</dt>
|
||||
<dd class="max-w-[60%] break-all text-right font-medium">{{ $recording->ollama_url }}</dd>
|
||||
</div>
|
||||
@endif
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<section class="rounded border border-stone-200 bg-white p-6 shadow-sm">
|
||||
<h2 class="text-sm font-semibold uppercase tracking-wide text-stone-500">Transcribe</h2>
|
||||
<p class="mt-2 text-sm text-stone-600">Choose an engine anytime — starting a new run stops the current one.</p>
|
||||
<p class="mt-2 text-sm text-stone-600">
|
||||
Audio stays on this machine. Requires
|
||||
<code class="text-[11px]">docker compose up -d whisper</code>
|
||||
(port 8090).
|
||||
</p>
|
||||
|
||||
<form method="POST" action="{{ route('recordings.transcribe', $recording) }}" class="mt-4 space-y-4">
|
||||
<form method="POST" action="{{ route('recordings.transcribe', $recording) }}" class="mt-4">
|
||||
@csrf
|
||||
|
||||
<label class="flex cursor-pointer gap-3 rounded border border-stone-200 p-3 hover:bg-stone-50">
|
||||
<input type="radio" name="driver" value="cloud" x-model="driver" class="mt-1 text-teal-700 focus:ring-teal-600">
|
||||
<span>
|
||||
<span class="block text-sm font-medium">Cloud (OpenAI Whisper)</span>
|
||||
<span class="block text-xs text-stone-500">Fast; audio is sent to OpenAI.</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="flex cursor-pointer gap-3 rounded border border-stone-200 p-3 hover:bg-stone-50">
|
||||
<input type="radio" name="driver" value="local" x-model="driver" class="mt-1 text-teal-700 focus:ring-teal-600">
|
||||
<span>
|
||||
<span class="block text-sm font-medium">Local — confidential (faster-whisper)</span>
|
||||
<span class="block text-xs text-stone-500">Runs via Docker Compose (<code class="text-[11px]">docker compose up -d whisper</code>) on port 8090.</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="flex cursor-pointer gap-3 rounded border border-stone-200 p-3 hover:bg-stone-50">
|
||||
<input type="radio" name="driver" value="ollama" x-model="driver" class="mt-1 text-teal-700 focus:ring-teal-600">
|
||||
<span>
|
||||
<span class="block text-sm font-medium">Ollama host</span>
|
||||
<span class="block text-xs text-stone-500">
|
||||
Remote host URL. Must expose OpenAI-compatible <code class="text-[11px]">/v1/audio/transcriptions</code>.
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div x-show="driver === 'ollama'" x-cloak class="space-y-2">
|
||||
<label for="ollama_url" class="block text-sm font-medium text-stone-700">Host URL</label>
|
||||
<input
|
||||
id="ollama_url"
|
||||
type="url"
|
||||
name="ollama_url"
|
||||
value="{{ old('ollama_url', $recording->ollama_url) }}"
|
||||
placeholder="http://192.168.1.50:8000"
|
||||
class="w-full rounded border border-stone-300 px-3 py-2 text-sm shadow-sm focus:border-teal-600 focus:outline-none focus:ring-1 focus:ring-teal-600"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<button
|
||||
type="submit"
|
||||
class="rounded bg-teal-700 px-4 py-2 text-sm font-medium text-white hover:bg-teal-800"
|
||||
>
|
||||
<span x-text="startButtonLabel"></span>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="rounded bg-teal-700 px-4 py-2 text-sm font-medium text-white hover:bg-teal-800"
|
||||
>
|
||||
<span x-text="startButtonLabel"></span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<form
|
||||
@@ -227,11 +183,10 @@
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
<style>[x-cloak]{display:none!important}</style>
|
||||
<script>
|
||||
function transcriptionMonitor({ statusUrl, initial, driver }) {
|
||||
function transcriptionMonitor({ statusUrl, initial }) {
|
||||
return {
|
||||
statusUrl,
|
||||
status: initial,
|
||||
driver: driver || 'cloud',
|
||||
pollError: null,
|
||||
timer: null,
|
||||
tickTimer: null,
|
||||
@@ -250,7 +205,7 @@
|
||||
|
||||
get startButtonLabel() {
|
||||
if (this.status.is_active) {
|
||||
return 'Switch engine / restart';
|
||||
return 'Restart transcription';
|
||||
}
|
||||
|
||||
return this.status.has_transcript ? 'Re-transcribe' : 'Start transcription';
|
||||
@@ -313,15 +268,17 @@
|
||||
},
|
||||
|
||||
formatElapsed(seconds) {
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remain = seconds % 60;
|
||||
const total = Math.max(0, Math.round(Number(seconds) || 0));
|
||||
const minutes = Math.floor(total / 60);
|
||||
const remain = total % 60;
|
||||
if (minutes === 0) return remain + 's';
|
||||
return minutes + 'm ' + String(remain).padStart(2, '0') + 's';
|
||||
},
|
||||
|
||||
formatDuration(seconds) {
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remain = seconds % 60;
|
||||
const total = Math.max(0, Math.round(Number(seconds) || 0));
|
||||
const minutes = Math.floor(total / 60);
|
||||
const remain = total % 60;
|
||||
return minutes + ':' + String(remain).padStart(2, '0');
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user