sp/src/pages/web-tools/articulate.astro

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>