Spaces:
Runtime error
Runtime error
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Speech Analysis</title> | |
<!-- Bootstrap CSS --> | |
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> | |
<style> | |
body { | |
background-color: #f4f7f8; | |
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; | |
} | |
.container { | |
margin-top: 50px; | |
padding: 20px; | |
background: #fff; | |
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1); | |
border-radius: 10px; | |
} | |
.progress-bar-inner { | |
width: 0%; | |
transition: width 1s ease-in-out; | |
} | |
.audio-player { | |
margin-top: 20px; | |
} | |
.btn-analyze { | |
background-color: #007bff; | |
color: white; | |
border-radius: 5px; | |
padding: 10px 20px; | |
} | |
.btn-analyze:hover { | |
background-color: #0056b3; | |
} | |
.score-label { | |
display: flex; | |
justify-content: space-between; | |
font-weight: 600; | |
} | |
.feedback-section { | |
margin-top: 30px; | |
} | |
.highlight-mispronounced { | |
background-color: yellow; | |
font-weight: bold; | |
} | |
.highlight { | |
background-color: yellow; | |
font-weight: bold; | |
} | |
.highlight-grammar { | |
background-color: lightpink; | |
/* or any other color */ | |
font-weight: bold; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1 class="text-center mb-4">Speech Analysis</h1> | |
<div class="mb-3"> | |
<label for="audio-file" class="form-label">Upload your audio file:</label> | |
<input type="file" class="form-control" id="audio-file" accept="audio/*"> | |
</div> | |
<!-- Language Dropdown --> | |
<div class="mb-3"> | |
<label for="language-select" class="form-label">Select Language:</label> | |
<select class="form-select" id="language-select"> | |
<option value="en-GB">English (United Kingdom)</option> | |
<option value="nb-NO">Norwegian</option> | |
</select> | |
</div> | |
<div class="text-center mb-4"> | |
<button class="btn btn-analyze" onclick="analyzeAudio()">Analyze Speech</button> | |
</div> | |
<div class="audio-player text-center" id="audio-player-container" style="display: none;"> | |
<audio id="audio-player" controls></audio> | |
</div> | |
<h3 class="mt-5">Speech Scores</h3> | |
<!-- Scores with Progress Bars --> | |
<div id="scores-container"> | |
<div class="mb-3"> | |
<div class="score-label"> | |
<span>Fluency Score</span> | |
<span id="fluency-score">0%</span> | |
</div> | |
<div class="progress"> | |
<div class="progress-bar progress-bar-inner bg-success" id="fluency-progress" role="progressbar" | |
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<div class="score-label"> | |
<span>Pronunciation Score</span> | |
<span id="pronunciation-score">0%</span> | |
</div> | |
<div class="progress"> | |
<div class="progress-bar progress-bar-inner bg-primary" id="pronunciation-progress" | |
role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<div class="score-label"> | |
<span>Completeness Score</span> | |
<span id="completeness-score">0%</span> | |
</div> | |
<div class="progress"> | |
<div class="progress-bar progress-bar-inner bg-warning" id="completeness-progress" | |
role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<div class="score-label"> | |
<span>Accuracy Score</span> | |
<span id="accuracy-score">0%</span> | |
</div> | |
<div class="progress"> | |
<div class="progress-bar progress-bar-inner bg-danger" id="accuracy-progress" role="progressbar" | |
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<div class="score-label"> | |
<span>Grammar Score</span> | |
<span id="grammar-score">0%</span> | |
</div> | |
<div class="progress"> | |
<div class="progress-bar progress-bar-inner bg-info" id="grammar-progress" role="progressbar" | |
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<div class="score-label"> | |
<span>Comprehension Score</span> | |
<span id="comprehension-score">0%</span> | |
</div> | |
<div class="progress"> | |
<div class="progress-bar progress-bar-inner bg-dark" id="comprehension-progress" role="progressbar" | |
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<div class="score-label"> | |
<span>Intonation Score</span> | |
<span id="intonation-score">0%</span> | |
</div> | |
<div class="progress"> | |
<div class="progress-bar progress-bar-inner bg-secondary" id="intonation-progress" | |
role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> | |
</div> | |
</div> | |
</div> | |
<div class="feedback-section"> | |
<h4>Speech Analysis Feedback</h4> | |
<p><strong>Identified Text:</strong> <span id="identified-text"></span></p> | |
<div id="feedback-container"> | |
<!-- <p><strong>Pronunciation Feedback:</strong> <span id="pronunciation-feedback"></span></p> --> | |
<!-- <p><strong>Fluency Feedback:</strong> <span id="fluency-feedback"></span></p> --> | |
<!-- <p><strong>Accuracy Feedback:</strong> <span id="accuracy-feedback"></span></p> --> | |
<!-- <p><strong>Grammar Feedback:</strong> <span id="grammar-feedback"></span></p> --> | |
<!-- <p><strong>Intonation Feedback:</strong> <span id="intonation-feedback"></span></p> | |
<p><strong>Comprehension Feedback:</strong> <span id="comprehension-feedback"></span></p> --> | |
</div> | |
</div> | |
</div> | |
<!-- Bootstrap JS and Popper.js --> | |
<script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script> | |
<script> | |
function analyzeAudio() { | |
const audioFile = document.getElementById("audio-file").files[0]; | |
const language = document.getElementById("language-select").value; | |
if (!audioFile) { | |
alert("Please upload an audio file."); | |
return; | |
} | |
const formData = new FormData(); | |
formData.append("audio_file", audioFile); | |
formData.append("language", language) | |
fetch("/api/v1/analyze", { | |
method: "POST", | |
body: formData | |
}) | |
.then(response => response.json()) | |
.then(data => { | |
updateProgress('fluency', data.fluency_score); | |
updateProgress('pronunciation', data.pronunciation_score); | |
updateProgress('completeness', data.completeness_score); | |
updateProgress('accuracy', data.accuracy_score); | |
updateProgress('grammar', data.grammar_score); | |
updateProgress('comprehension', data.comprehension_score); | |
updateProgress('intonation', data.intonation_score); | |
const audioPlayer = document.getElementById("audio-player"); | |
const audioURL = URL.createObjectURL(audioFile); | |
audioPlayer.src = audioURL; | |
document.getElementById("audio-player-container").style.display = "block"; | |
// Example data to simulate the transcript and errors from the backend | |
// const grammar_errors = [{ 'word': 'dismissal', 'position_in_text': 2, 'error': 'Subject without a verb', 'suggestion': 'Ensure the subject is followed by a verb.' }, { 'word': 'college', 'position_in_text': 4, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'he', 'position_in_text': 10, 'error': 'Subject without a verb', 'suggestion': 'Ensure the subject is followed by a verb.' }, { 'word': 'reaction', 'position_in_text': 13, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'experiences', 'position_in_text': 24, 'error': 'Subject without a verb', 'suggestion': 'Ensure the subject is followed by a verb.' }, { 'word': 'experiences', 'position_in_text': 24, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'factory', 'position_in_text': 32, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'success', 'position_in_text': 38, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'leader', 'position_in_text': 42, 'error': 'Subject without a verb', 'suggestion': 'Ensure the subject is followed by a verb.' }, { 'word': 'environment', 'position_in_text': 52, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'clashes', 'position_in_text': 61, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'Illusion', 'position_in_text': 64, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'incense', 'position_in_text': 73, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'violence', 'position_in_text': 75, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'write', 'position_in_text': 77, 'error': 'Missing article', 'suggestion': "Add an article ('a', 'an', 'the') before this noun." }, { 'word': 'which', 'position_in_text': 82, 'error': 'Subject without a verb', 'suggestion': 'Ensure the subject is followed by a verb.' }] | |
// Function to highlight mispronounced words and grammar errors | |
function highlightErrors(text, mispronouncedWords, grammarErrors) { | |
const textArray = text.split(" "); | |
const highlightedTextArray = textArray.map((word, index) => { | |
// Check for mispronounced words | |
const mispronounced = mispronouncedWords.find(mw => mw.word === word && mw.position_in_text === index); | |
if (mispronounced) { | |
return `<span class="highlight-mispronounced">${word}</span>`; | |
} | |
// Check for grammar errors | |
const grammarError = grammarErrors.find(ge => ge.word === word && ge.position_in_text === index); | |
console.log("GRAMMAR ERROR: ", grammarError) | |
if (grammarError) { | |
return `<span class="highlight-grammar">${word}</span>`; | |
} | |
return word; // Return unmodified if no errors | |
}); | |
return highlightedTextArray.join(" "); | |
} | |
// Apply the highlighting function to the DisplayText | |
const highlightedText = highlightErrors(data.display_text, data.mispronunced_words, data.grammar_errors); | |
// Inject the highlighted text into an HTML element | |
document.getElementById("identified-text").innerHTML = highlightedText; | |
// Update feedback | |
document.getElementById("pronunciation-feedback").textContent = data.pronunciation_feedback; | |
document.getElementById("fluency-feedback").textContent = data.fluency_feedback; | |
document.getElementById("accuracy-feedback").textContent = data.accuracy_feedback; | |
document.getElementById("grammar-feedback").textContent = data.grammar_feedback; | |
document.getElementById("intonation-feedback").textContent = data.intonation_feedback; | |
document.getElementById("comprehension-feedback").textContent = data.comprehension_feedback; | |
}) | |
.catch(error => console.error('Error:', error)); | |
} | |
function updateProgress(scoreType, score) { | |
const progressBar = document.getElementById(`${scoreType}-progress`); | |
const scoreLabel = document.getElementById(`${scoreType}-score`); | |
progressBar.style.width = `${score}%`; | |
progressBar.setAttribute('aria-valuenow', score); | |
scoreLabel.textContent = `${score}%`; | |
} | |
</script> | |
</body> | |
</html> | |