168 lines
7.8 KiB
Plaintext
168 lines
7.8 KiB
Plaintext
---
|
|
import Layout from "../../layouts/Layout.astro"
|
|
---
|
|
|
|
<Layout title="">
|
|
<div class="min-h-screen flex items-center justify-center p-4">
|
|
<div class="w-full max-w-2xl bg-white rounded-lg shadow-lg overflow-hidden">
|
|
<!-- Header -->
|
|
<div class="bg-blue-600 text-white p-4">
|
|
<h1 class="text-2xl font-bold">Real-Time Transcription</h1>
|
|
<p class="text-blue-100">Using Articulate.js</p>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<div class="p-6">
|
|
<!-- Status Indicator -->
|
|
<div id="status" class="mb-4 flex items-center">
|
|
<div id="statusDot" class="w-3 h-3 rounded-full bg-gray-400 mr-2"></div>
|
|
<span id="statusText" class="text-sm">Ready to start</span>
|
|
</div>
|
|
|
|
<!-- Transcription Output -->
|
|
<div class="mb-6">
|
|
<label class="block text-gray-700 font-medium mb-2">Transcription</label>
|
|
<div id="transcriptOutput" class="min-h-32 border border-gray-300 rounded-lg p-4 bg-gray-50 overflow-y-auto max-h-64">
|
|
<p id="interimText" class="text-gray-500 italic">Your transcription will appear here...</p>
|
|
<p id="finalText" class="text-gray-800"></p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Controls -->
|
|
<div class="flex flex-wrap gap-3">
|
|
<button id="startBtn" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg flex items-center">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M7 4a3 3 0 016 0v4a3 3 0 11-6 0V4zm4 10.93A7.001 7.001 0 0017 8a1 1 0 10-2 0A5 5 0 015 8a1 1 0 00-2 0 7.001 7.001 0 006 6.93V17H6a1 1 0 100 2h8a1 1 0 100-2h-3v-2.07z" clip-rule="evenodd" />
|
|
</svg>
|
|
Start
|
|
</button>
|
|
<button id="stopBtn" disabled class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg flex items-center opacity-50 cursor-not-allowed">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8 7a1 1 0 00-1 1v4a1 1 0 001 1h4a1 1 0 001-1V8a1 1 0 00-1-1H8z" clip-rule="evenodd" />
|
|
</svg>
|
|
Stop
|
|
</button>
|
|
<button id="clearBtn" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg flex items-center">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
|
|
</svg>
|
|
Clear
|
|
</button>
|
|
|
|
<!-- Language Selector -->
|
|
<select id="languageSelect" class="border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
|
<option value="en-US">English (US)</option>
|
|
<option value="en-GB">English (UK)</option>
|
|
<option value="es-ES">Spanish</option>
|
|
<option value="fr-FR">French</option>
|
|
<option value="de-DE">German</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div class="bg-gray-100 p-3 text-center text-sm text-gray-600">
|
|
<p>Click "Start" and begin speaking. Transcription will appear in real-time.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Layout>
|
|
<script is:inline src="https://cdn.jsdelivr.net/npm/@articulate/chromeless@1.3.0-beta5/dist/src/index.js"></script>
|
|
<script is:inline>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// DOM Elements
|
|
const startBtn = document.getElementById('startBtn');
|
|
const stopBtn = document.getElementById('stopBtn');
|
|
const clearBtn = document.getElementById('clearBtn');
|
|
const languageSelect = document.getElementById('languageSelect');
|
|
const statusDot = document.getElementById('statusDot');
|
|
const statusText = document.getElementById('statusText');
|
|
const interimText = document.getElementById('interimText');
|
|
const finalText = document.getElementById('finalText');
|
|
|
|
// Initialize Articulate.js
|
|
const articulate = new Articulate();
|
|
let isListening = false;
|
|
|
|
// Configure Articulate
|
|
function configureArticulate() {
|
|
articulate.configure({
|
|
continuous: true,
|
|
interimResults: true,
|
|
language: languageSelect.value,
|
|
onError: (error) => {
|
|
console.error('Recognition error:', error);
|
|
updateStatus('Error: ' + error.message, 'red');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Update status UI
|
|
function updateStatus(text, color = 'gray') {
|
|
statusText.textContent = text;
|
|
statusDot.className = `w-3 h-3 rounded-full mr-2 bg-${color}-500`;
|
|
|
|
// Handle special colors
|
|
if (color === 'green') {
|
|
statusDot.classList.add('animate-pulse');
|
|
} else {
|
|
statusDot.classList.remove('animate-pulse');
|
|
}
|
|
}
|
|
|
|
// Start transcription
|
|
startBtn.addEventListener('click', () => {
|
|
configureArticulate();
|
|
|
|
articulate.start()
|
|
.on('transcript', (text, isFinal) => {
|
|
if (isFinal) {
|
|
finalText.textContent += text + ' ';
|
|
interimText.textContent = '';
|
|
} else {
|
|
interimText.textContent = text;
|
|
}
|
|
|
|
// Auto-scroll to bottom
|
|
document.getElementById('transcriptOutput').scrollTop =
|
|
document.getElementById('transcriptOutput').scrollHeight;
|
|
})
|
|
.on('start', () => {
|
|
isListening = true;
|
|
updateStatus('Listening...', 'green');
|
|
startBtn.disabled = true;
|
|
stopBtn.disabled = false;
|
|
stopBtn.classList.remove('opacity-50', 'cursor-not-allowed');
|
|
});
|
|
});
|
|
|
|
// Stop transcription
|
|
stopBtn.addEventListener('click', () => {
|
|
articulate.stop();
|
|
isListening = false;
|
|
updateStatus('Ready to continue', 'blue');
|
|
startBtn.disabled = false;
|
|
stopBtn.disabled = true;
|
|
stopBtn.classList.add('opacity-50', 'cursor-not-allowed');
|
|
});
|
|
|
|
// Clear transcription
|
|
clearBtn.addEventListener('click', () => {
|
|
finalText.textContent = '';
|
|
interimText.textContent = 'Your transcription will appear here...';
|
|
});
|
|
|
|
// Change language
|
|
languageSelect.addEventListener('change', () => {
|
|
if (isListening) {
|
|
articulate.stop();
|
|
configureArticulate();
|
|
articulate.start();
|
|
}
|
|
});
|
|
|
|
// Initial configuration
|
|
configureArticulate();
|
|
updateStatus('Ready to start', 'blue');
|
|
});
|
|
</script> |