|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Whisper AI Transcription</title> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
<style> |
|
:root { |
|
--primary: #6e48aa; |
|
--primary-dark: #4a2d8a; |
|
--secondary: #9d50bb; |
|
--gradient-start: #4776e6; |
|
--gradient-end: #8e54e9; |
|
--light: #f8f9fa; |
|
--dark: #2d3748; |
|
--gray: #edf2f7; |
|
--success: #48bb78; |
|
--danger: #e53e3e; |
|
--warning: #ed8936; |
|
} |
|
|
|
* { |
|
margin: 0; |
|
padding: 0; |
|
box-sizing: border-box; |
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|
} |
|
|
|
body { |
|
background-color: #f0f4f8; |
|
color: var(--dark); |
|
line-height: 1.6; |
|
} |
|
|
|
.container { |
|
max-width: 1000px; |
|
margin: 2rem auto; |
|
padding: 0 1rem; |
|
} |
|
|
|
header { |
|
text-align: center; |
|
margin-bottom: 2rem; |
|
} |
|
|
|
.logo { |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
gap: 0.5rem; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.logo i { |
|
font-size: 2.5rem; |
|
color: var(--primary); |
|
} |
|
|
|
h1 { |
|
font-size: 2.5rem; |
|
background: linear-gradient(to right, var(--gradient-start), var(--gradient-end)); |
|
-webkit-background-clip: text; |
|
-webkit-text-fill-color: transparent; |
|
font-weight: 700; |
|
margin-bottom: 0.5rem; |
|
} |
|
|
|
.subtitle { |
|
color: #718096; |
|
font-size: 1.1rem; |
|
max-width: 600px; |
|
margin: 0 auto; |
|
} |
|
|
|
.card { |
|
background: white; |
|
border-radius: 12px; |
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); |
|
padding: 2rem; |
|
margin-bottom: 2rem; |
|
} |
|
|
|
.card-title { |
|
font-size: 1.4rem; |
|
margin-bottom: 1.5rem; |
|
color: var(--primary-dark); |
|
display: flex; |
|
align-items: center; |
|
gap: 0.8rem; |
|
} |
|
|
|
.card-title i { |
|
font-size: 1.8rem; |
|
color: var(--secondary); |
|
} |
|
|
|
.controls { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 1.5rem; |
|
} |
|
|
|
.input-group { |
|
display: flex; |
|
gap: 1rem; |
|
} |
|
|
|
@media (max-width: 768px) { |
|
.input-group { |
|
flex-direction: column; |
|
} |
|
} |
|
|
|
.btn { |
|
padding: 0.8rem 1.5rem; |
|
border-radius: 8px; |
|
border: none; |
|
font-weight: 600; |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
gap: 0.5rem; |
|
font-size: 1rem; |
|
} |
|
|
|
.btn-primary { |
|
background-color: var(--primary); |
|
color: white; |
|
} |
|
|
|
.btn-primary:hover { |
|
background-color: var(--primary-dark); |
|
transform: translateY(-2px); |
|
box-shadow: 0 4px 12px rgba(110, 72, 170, 0.3); |
|
} |
|
|
|
.btn-outline { |
|
background-color: transparent; |
|
border: 2px solid var(--primary); |
|
color: var(--primary); |
|
} |
|
|
|
.btn-outline:hover { |
|
background-color: var(--primary); |
|
color: white; |
|
} |
|
|
|
.btn-danger { |
|
background-color: var(--danger); |
|
color: white; |
|
} |
|
|
|
.btn-danger:hover { |
|
background-color: #c53030; |
|
transform: translateY(-2px); |
|
box-shadow: 0 4px 12px rgba(229, 62, 62, 0.3); |
|
} |
|
|
|
.btn:disabled { |
|
opacity: 0.7; |
|
cursor: not-allowed; |
|
transform: none !important; |
|
box-shadow: none !important; |
|
} |
|
|
|
.file-upload { |
|
display: none; |
|
} |
|
|
|
.audio-visualizer { |
|
width: 100%; |
|
height: 100px; |
|
background-color: #f5f3ff; |
|
border-radius: 8px; |
|
margin: 1rem 0; |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
.visualizer-bars { |
|
display: flex; |
|
align-items: flex-end; |
|
justify-content: space-around; |
|
height: 100%; |
|
width: 100%; |
|
padding: 0.5rem; |
|
} |
|
|
|
.bar { |
|
background-color: var(--primary); |
|
width: 6px; |
|
border-radius: 3px; |
|
transition: height 0.1s ease; |
|
} |
|
|
|
.recording-indicator { |
|
display: flex; |
|
align-items: center; |
|
gap: 0.5rem; |
|
color: var(--danger); |
|
font-weight: 600; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.pulse { |
|
width: 12px; |
|
height: 12px; |
|
border-radius: 50%; |
|
background-color: var(--danger); |
|
animation: pulse 1.5s infinite; |
|
} |
|
|
|
@keyframes pulse { |
|
0% { |
|
transform: scale(0.95); |
|
box-shadow: 0 0 0 0 rgba(229, 62, 62, 0.7); |
|
} |
|
70% { |
|
transform: scale(1); |
|
box-shadow: 0 0 0 10px rgba(229, 62, 62, 0); |
|
} |
|
100% { |
|
transform: scale(0.95); |
|
box-shadow: 0 0 0 0 rgba(229, 62, 62, 0); |
|
} |
|
} |
|
|
|
.timer { |
|
font-family: 'Courier New', monospace; |
|
font-size: 1.2rem; |
|
} |
|
|
|
.transcription-card { |
|
position: relative; |
|
} |
|
|
|
.transcription-content { |
|
min-height: 200px; |
|
max-height: 400px; |
|
overflow-y: auto; |
|
padding: 1rem; |
|
background-color: var(--gray); |
|
border-radius: 8px; |
|
white-space: pre-wrap; |
|
line-height: 1.8; |
|
font-size: 1.1rem; |
|
} |
|
|
|
.copy-btn { |
|
position: absolute; |
|
top: 1rem; |
|
right: 1rem; |
|
background-color: rgba(255, 255, 255, 0.8); |
|
border-radius: 6px; |
|
padding: 0.5rem; |
|
cursor: pointer; |
|
transition: all 0.2s ease; |
|
} |
|
|
|
.copy-btn:hover { |
|
background-color: white; |
|
transform: scale(1.05); |
|
} |
|
|
|
.copy-btn i { |
|
color: var(--primary); |
|
font-size: 1.2rem; |
|
} |
|
|
|
.language-selector { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 0.5rem; |
|
} |
|
|
|
select { |
|
padding: 0.8rem; |
|
border-radius: 8px; |
|
border: 1px solid #cbd5e0; |
|
background-color: white; |
|
font-size: 1rem; |
|
color: var(--dark); |
|
cursor: pointer; |
|
} |
|
|
|
select:focus { |
|
outline: none; |
|
border-color: var(--primary); |
|
box-shadow: 0 0 0 3px rgba(110, 72, 170, 0.2); |
|
} |
|
|
|
.file-info { |
|
display: flex; |
|
align-items: center; |
|
gap: 0.5rem; |
|
margin-top: 0.5rem; |
|
color: #4a5568; |
|
} |
|
|
|
.file-info i { |
|
color: var(--primary); |
|
} |
|
|
|
.status-message { |
|
padding: 1rem; |
|
border-radius: 8px; |
|
margin-bottom: 1rem; |
|
display: flex; |
|
align-items: center; |
|
gap: 0.8rem; |
|
} |
|
|
|
.status-processing { |
|
background-color: #feebc8; |
|
color: #b7791f; |
|
} |
|
|
|
.status-success { |
|
background-color: #c6f6d5; |
|
color: #25855a; |
|
} |
|
|
|
.status-error { |
|
background-color: #fed7d7; |
|
color: #c53030; |
|
} |
|
|
|
.progress-container { |
|
width: 100%; |
|
height: 8px; |
|
background-color: #e2e8f0; |
|
border-radius: 4px; |
|
margin-top: 1rem; |
|
overflow: hidden; |
|
} |
|
|
|
.progress-bar { |
|
height: 100%; |
|
background: linear-gradient(to right, var(--gradient-start), var(--gradient-end)); |
|
border-radius: 4px; |
|
width: 0%; |
|
transition: width 0.3s ease; |
|
} |
|
|
|
.settings-toggle { |
|
display: flex; |
|
align-items: center; |
|
gap: 0.5rem; |
|
color: #4a5568; |
|
cursor: pointer; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.settings-toggle i { |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.settings-container { |
|
max-height: 0; |
|
overflow: hidden; |
|
transition: max-height 0.3s ease; |
|
background-color: #f8f9fa; |
|
border-radius: 8px; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.settings-container.open { |
|
max-height: 300px; |
|
padding: 1rem; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.setting-item { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.checkbox-container { |
|
display: flex; |
|
align-items: center; |
|
gap: 0.5rem; |
|
} |
|
|
|
input[type="checkbox"] { |
|
-webkit-appearance: none; |
|
appearance: none; |
|
width: 20px; |
|
height: 20px; |
|
border: 2px solid #cbd5e0; |
|
border-radius: 4px; |
|
cursor: pointer; |
|
position: relative; |
|
transition: all 0.2s ease; |
|
} |
|
|
|
input[type="checkbox"]:checked { |
|
background-color: var(--primary); |
|
border-color: var(--primary); |
|
} |
|
|
|
input[type="checkbox"]:checked::after { |
|
content: '\f00c'; |
|
font-family: 'Font Awesome 6 Free'; |
|
font-weight: 900; |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
color: white; |
|
font-size: 12px; |
|
} |
|
|
|
.history-item { |
|
padding: 1rem; |
|
border-bottom: 1px solid #e2e8f0; |
|
cursor: pointer; |
|
transition: background-color 0.2s ease; |
|
} |
|
|
|
.history-item:hover { |
|
background-color: #f7fafc; |
|
} |
|
|
|
.history-item-time { |
|
font-size: 0.9rem; |
|
color: #718096; |
|
} |
|
|
|
.history-item-preview { |
|
display: -webkit-box; |
|
-webkit-line-clamp: 2; |
|
-webkit-box-orient: vertical; |
|
overflow: hidden; |
|
text-overflow: ellipsis; |
|
margin-top: 0.3rem; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="container"> |
|
<header> |
|
<div class="logo"> |
|
<i class="fas fa-comment-dots"></i> |
|
<h1>Whisper AI</h1> |
|
</div> |
|
<p class="subtitle">Advanced speech recognition powered by OpenAI's Whisper model. Convert speech to text with remarkable accuracy.</p> |
|
</header> |
|
|
|
<div class="card"> |
|
<h2 class="card-title"> |
|
<i class="fas fa-microphone"></i> |
|
Audio Input |
|
</h2> |
|
|
|
<div class="controls"> |
|
<div class="input-group"> |
|
<button id="recordBtn" class="btn btn-primary"> |
|
<i class="fas fa-microphone"></i> Start Recording |
|
</button> |
|
<button id="uploadBtn" class="btn btn-outline"> |
|
<i class="fas fa-upload"></i> Upload Audio |
|
</button> |
|
<input type="file" id="fileInput" class="file-upload" accept="audio/*,video/*,.wav,.mp3,.ogg,.m4a,.mp4,.webm"> |
|
</div> |
|
|
|
<div class="language-selector"> |
|
<label for="language">Select Language</label> |
|
<select id="language"> |
|
<option value="auto">Auto-detect</option> |
|
<option value="en">English</option> |
|
<option value="es">Spanish</option> |
|
<option value="fr">French</option> |
|
<option value="de">German</option> |
|
<option value="it">Italian</option> |
|
<option value="pt">Portuguese</option> |
|
<option value="ru">Russian</option> |
|
<option value="ja">Japanese</option> |
|
<option value="zh">Chinese</option> |
|
<option value="hi">Hindi</option> |
|
<option value="ar">Arabic</option> |
|
</select> |
|
</div> |
|
|
|
<div class="audio-visualizer" id="visualizer"> |
|
<div class="visualizer-bars" id="visualizerBars"></div> |
|
</div> |
|
|
|
<div id="recordingUI" style="display: none;"> |
|
<div class="recording-indicator"> |
|
<div class="pulse"></div> |
|
<span>Recording</span> |
|
<span class="timer" id="timer">00:00</span> |
|
</div> |
|
<button id="stopBtn" class="btn btn-danger"> |
|
<i class="fas fa-stop"></i> Stop & Process |
|
</button> |
|
</div> |
|
|
|
<div id="fileInfo" style="display: none;"> |
|
<div class="file-info"> |
|
<i class="fas fa-file-audio"></i> |
|
<span id="fileName"></span> |
|
</div> |
|
<button id="processFileBtn" class="btn btn-primary"> |
|
<i class="fas fa-cog"></i> Process File |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="settings-toggle" id="settingsToggle"> |
|
<i class="fas fa-cog"></i> |
|
<span>Advanced Settings</span> |
|
</div> |
|
|
|
<div class="settings-container" id="settingsContainer"> |
|
<div class="setting-item"> |
|
<span>Transcription Task</span> |
|
<select id="taskType"> |
|
<option value="transcribe">Transcribe (default)</option> |
|
<option value="translate">Translate to English</option> |
|
</select> |
|
</div> |
|
<div class="setting-item"> |
|
<span>Temperature</span> |
|
<input type="range" id="temperature" min="0" max="1" step="0.1" value="0"> |
|
<span id="temperatureValue">0</span> |
|
</div> |
|
<div class="checkbox-container"> |
|
<input type="checkbox" id="timestamps" checked> |
|
<label for="timestamps">Include timestamps</label> |
|
</div> |
|
<div class="checkbox-container"> |
|
<input type="checkbox" id="diarization"> |
|
<label for="diarization">Speaker diarization (beta)</label> |
|
</div> |
|
</div> |
|
|
|
<div class="card transcription-card"> |
|
<h2 class="card-title"> |
|
<i class="fas fa-keyboard"></i> |
|
Transcription |
|
</h2> |
|
|
|
<div id="statusMessage" style="display: none;"></div> |
|
|
|
<div class="progress-container" id="progressContainer" style="display: none;"> |
|
<div class="progress-bar" id="progressBar"></div> |
|
</div> |
|
|
|
<div class="transcription-content" id="transcriptionResult"> |
|
<div style="text-align: center; padding: 4rem 0; color: #a0aec0;"> |
|
<i class="fas fa-comment-slash" style="font-size: 3rem; margin-bottom: 1rem;"></i> |
|
<h3>No transcription yet</h3> |
|
<p>Record audio or upload a file to get started</p> |
|
</div> |
|
</div> |
|
|
|
<div class="copy-btn" id="copyBtn" title="Copy to clipboard" style="display: none;"> |
|
<i class="fas fa-copy"></i> |
|
</div> |
|
</div> |
|
|
|
<div class="card"> |
|
<h2 class="card-title"> |
|
<i class="fas fa-history"></i> |
|
Recent Transcripts |
|
</h2> |
|
|
|
<div id="historyList"> |
|
<div class="history-item"> |
|
<div class="history-item-time">5 minutes ago</div> |
|
<div class="history-item-preview">Lorem ipsum dolor sit amet, consectetur adipiscing elit...</div> |
|
</div> |
|
<div class="history-item"> |
|
<div class="history-item-time">2 hours ago</div> |
|
<div class="history-item-preview">Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua...</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
const recordBtn = document.getElementById('recordBtn'); |
|
const stopBtn = document.getElementById('stopBtn'); |
|
const uploadBtn = document.getElementById('uploadBtn'); |
|
const fileInput = document.getElementById('fileInput'); |
|
const processFileBtn = document.getElementById('processFileBtn'); |
|
const fileName = document.getElementById('fileName'); |
|
const fileInfo = document.getElementById('fileInfo'); |
|
const recordingUI = document.getElementById('recordingUI'); |
|
const timer = document.getElementById('timer'); |
|
const visualizer = document.getElementById('visualizer'); |
|
const visualizerBars = document.getElementById('visualizerBars'); |
|
const transcriptionResult = document.getElementById('transcriptionResult'); |
|
const statusMessage = document.getElementById('statusMessage'); |
|
const progressContainer = document.getElementById('progressContainer'); |
|
const progressBar = document.getElementById('progressBar'); |
|
const copyBtn = document.getElementById('copyBtn'); |
|
const settingsToggle = document.getElementById('settingsToggle'); |
|
const settingsContainer = document.getElementById('settingsContainer'); |
|
const temperature = document.getElementById('temperature'); |
|
const temperatureValue = document.getElementById('temperatureValue'); |
|
|
|
|
|
let mediaRecorder; |
|
let audioChunks = []; |
|
let audioContext; |
|
let analyser; |
|
let timerInterval; |
|
let seconds = 0; |
|
let isRecording = false; |
|
|
|
|
|
for (let i = 0; i < 40; i++) { |
|
const bar = document.createElement('div'); |
|
bar.className = 'bar'; |
|
bar.style.height = '0%'; |
|
visualizerBars.appendChild(bar); |
|
} |
|
const bars = document.querySelectorAll('.bar'); |
|
|
|
|
|
recordBtn.addEventListener('click', startRecording); |
|
stopBtn.addEventListener('click', stopRecording); |
|
uploadBtn.addEventListener('click', () => fileInput.click()); |
|
fileInput.addEventListener('change', handleFileUpload); |
|
processFileBtn.addEventListener('click', processUploadedFile); |
|
copyBtn.addEventListener('click', copyTranscription); |
|
settingsToggle.addEventListener('click', toggleSettings); |
|
temperature.addEventListener('input', updateTemperatureValue); |
|
|
|
|
|
updateTemperatureValue(); |
|
|
|
async function startRecording() { |
|
try { |
|
|
|
recordBtn.style.display = 'none'; |
|
recordingUI.style.display = 'block'; |
|
|
|
|
|
seconds = 0; |
|
updateTimer(); |
|
timerInterval = setInterval(updateTimer, 1000); |
|
|
|
|
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); |
|
mediaRecorder = new MediaRecorder(stream); |
|
isRecording = true; |
|
|
|
|
|
audioContext = new (window.AudioContext || window.webkitAudioContext)(); |
|
const source = audioContext.createMediaStreamSource(stream); |
|
analyser = audioContext.createAnalyser(); |
|
analyser.fftSize = 64; |
|
source.connect(analyser); |
|
|
|
|
|
visualize(); |
|
|
|
|
|
mediaRecorder.ondataavailable = event => { |
|
audioChunks.push(event.data); |
|
}; |
|
|
|
mediaRecorder.onstop = async () => { |
|
clearInterval(timerInterval); |
|
|
|
|
|
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' }); |
|
audioChunks = []; |
|
|
|
|
|
await processAudio(audioBlob, 'recording.wav'); |
|
}; |
|
|
|
mediaRecorder.start(100); |
|
|
|
|
|
showStatus('Processing your recording...', 'processing'); |
|
|
|
} catch (error) { |
|
console.error('Error accessing microphone:', error); |
|
stopRecording(); |
|
showStatus('Error accessing microphone. Please check permissions.', 'error'); |
|
recordBtn.style.display = 'block'; |
|
recordingUI.style.display = 'none'; |
|
} |
|
} |
|
|
|
function stopRecording() { |
|
if (mediaRecorder && isRecording) { |
|
mediaRecorder.stop(); |
|
isRecording = false; |
|
|
|
|
|
mediaRecorder.stream.getTracks().forEach(track => track.stop()); |
|
|
|
|
|
cancelAnimationFrame(visualize); |
|
|
|
clearInterval(timerInterval); |
|
} |
|
} |
|
|
|
function updateTimer() { |
|
seconds++; |
|
const minutes = Math.floor(seconds / 60); |
|
const remainingSeconds = seconds % 60; |
|
timer.textContent = `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; |
|
} |
|
|
|
function visualize() { |
|
if (!isRecording) return; |
|
|
|
const bufferLength = analyser.frequencyBinCount; |
|
const dataArray = new Uint8Array(bufferLength); |
|
analyser.getByteFrequencyData(dataArray); |
|
|
|
for (let i = 0; i < bars.length; i++) { |
|
const barHeight = (dataArray[i % bufferLength] / 255) * 100; |
|
bars[i].style.height = `${barHeight}%`; |
|
} |
|
|
|
requestAnimationFrame(visualize); |
|
} |
|
|
|
function handleFileUpload(event) { |
|
const file = event.target.files[0]; |
|
if (file) { |
|
fileName.textContent = file.name; |
|
fileInfo.style.display = 'block'; |
|
|
|
|
|
fileInput.value = ''; |
|
} else { |
|
fileInfo.style.display = 'none'; |
|
} |
|
} |
|
|
|
async function processUploadedFile() { |
|
const file = fileInput.files[0]; |
|
if (!file) return; |
|
|
|
showStatus('Processing uploaded file...', 'processing'); |
|
progressContainer.style.display = 'block'; |
|
|
|
|
|
simulateProcessing(() => { |
|
processAudio(file, file.name); |
|
}); |
|
} |
|
|
|
async function processAudio(audioBlob, fileName) { |
|
try { |
|
|
|
|
|
|
|
|
|
progressBar.style.width = '40%'; |
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1500)); |
|
|
|
progressBar.style.width = '70%'; |
|
|
|
|
|
setTimeout(() => { |
|
const mockResults = getMockTranscription(fileName); |
|
displayResults(mockResults); |
|
showStatus('Transcription completed successfully!', 'success'); |
|
}, 1000); |
|
|
|
} catch (error) { |
|
console.error('Error processing audio:', error); |
|
showStatus('Error processing audio. Please try again.', 'error'); |
|
} finally { |
|
|
|
recordBtn.style.display = 'block'; |
|
recordingUI.style.display = 'none'; |
|
fileInfo.style.display = 'none'; |
|
progressBar.style.width = '100%'; |
|
} |
|
} |
|
|
|
function displayResults(results) { |
|
transcriptionResult.innerHTML = results; |
|
|
|
|
|
const isEmpty = results.includes('No transcription yet'); |
|
copyBtn.style.display = isEmpty ? 'none' : 'block'; |
|
} |
|
|
|
function showStatus(message, type) { |
|
statusMessage.style.display = 'block'; |
|
statusMessage.textContent = message; |
|
statusMessage.className = 'status-message'; |
|
|
|
switch (type) { |
|
case 'processing': |
|
statusMessage.classList.add('status-processing'); |
|
progressContainer.style.display = 'block'; |
|
progressBar.style.width = '10%'; |
|
break; |
|
case 'success': |
|
statusMessage.classList.add('status-success'); |
|
progressContainer.style.display = 'none'; |
|
break; |
|
case 'error': |
|
statusMessage.classList.add('status-error'); |
|
progressContainer.style.display = 'none'; |
|
break; |
|
} |
|
} |
|
|
|
function copyTranscription() { |
|
const text = transcriptionResult.innerText; |
|
navigator.clipboard.writeText(text).then(() => { |
|
|
|
const originalIcon = copyBtn.innerHTML; |
|
copyBtn.innerHTML = '<i class="fas fa-check"></i>'; |
|
|
|
setTimeout(() => { |
|
copyBtn.innerHTML = originalIcon; |
|
}, 2000); |
|
}).catch(err => { |
|
console.error('Failed to copy text: ', err); |
|
}); |
|
} |
|
|
|
function toggleSettings() { |
|
settingsContainer.classList.toggle('open'); |
|
const icon = settingsToggle.querySelector('i'); |
|
icon.style.transform = settingsContainer.classList.contains('open') ? 'rotate(90deg)' : 'rotate(0)'; |
|
} |
|
|
|
function updateTemperatureValue() { |
|
temperatureValue.textContent = temperature.value; |
|
} |
|
|
|
function simulateProcessing(callback) { |
|
let progress = 0; |
|
const interval = setInterval(() => { |
|
progress += Math.random() * 10; |
|
if (progress >= 90) { |
|
progress = 90; |
|
clearInterval(interval); |
|
callback(); |
|
} |
|
progressBar.style.width = `${progress}%`; |
|
}, 300); |
|
} |
|
|
|
function getMockTranscription(filename) { |
|
const now = new Date(); |
|
const languages = ['English', 'Spanish', 'French', 'German']; |
|
const randomLanguage = languages[Math.floor(Math.random() * languages.length)]; |
|
|
|
return `Filename: ${filename}\n` + |
|
`Detected language: ${randomLanguage}\n` + |
|
`Transcribed at: ${now.toLocaleString()}\n\n` + |
|
`[00:00:00 --> 00:00:03] Hello there! This is a mock transcription from the Whisper speech recognition model.\n` + |
|
`[00:00:03 --> 00:00:07] It demonstrates what the real output would look like when using the actual Whisper API.\n` + |
|
`[00:00:07 --> 00:00:12] In a real implementation, this text would come from OpenAI's Whisper model processing your audio.\n` + |
|
`[00:00:12 --> 00:00:15] Whisper is great for transcribing meetings, lectures, interviews, and more.\n` + |
|
`[00:00:15 --> 00:00:18] Thank you for trying out this demo interface!\n`; |
|
} |
|
}); |
|
</script> |
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> |
|
</html> |