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/bootstrap@5.3.0-alpha1/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/core@2.11.7/dist/umd/popper.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/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> | |