feat: Implementiere echte Zeitmessung für präzise Tippstatistiken

Co-authored-by: aider (deepseek/deepseek-reasoner) <aider@aider.chat>
This commit is contained in:
jamulix 2025-10-21 20:22:24 +02:00
commit 862626bba1
2 changed files with 76 additions and 15 deletions

33
app.py
View file

@ -318,11 +318,12 @@ def recreate_lessons():
@app.route('/update_progress', methods=['POST'])
def update_progress():
"""Aktualisiert den Tippfortschritt"""
"""Aktualisiert den Tippfortschritt mit echter Zeitmessung"""
try:
data = request.get_json()
user_input = data.get('user_input', '')
current_text = data.get('current_text', '')
elapsed_time = data.get('elapsed_time', 0) # in Sekunden
# Hole den aktuellen Fortschritt
progress = Progress.query.first()
@ -335,8 +336,8 @@ def update_progress():
# Speichere in der Datenbank
db.session.commit()
# Berechne Statistiken
stats = calculate_statistics(user_input, current_text)
# Berechne Statistiken mit echter Zeit
stats = calculate_statistics(user_input, current_text, elapsed_time)
return jsonify(stats)
else:
@ -346,24 +347,34 @@ def update_progress():
print(f"Fehler in update_progress: {e}")
return jsonify({'error': 'Interner Serverfehler'}), 500
def calculate_statistics(user_input, current_text):
"""Berechnet Tippstatistiken"""
def calculate_statistics(user_input, current_text, elapsed_time):
"""Berechnet Tippstatistiken mit echter Zeitmessung"""
correct_chars = 0
incorrect_chars = 0
total_chars = len(user_input)
# Zähle korrekte und falsche Zeichen
for i, char in enumerate(user_input):
if i < len(current_text) and char == current_text[i]:
correct_chars += 1
else:
incorrect_chars += 1
# Berechne verschiedene Metriken
# Berechne Metriken basierend auf echter Zeit
if total_chars > 0 and elapsed_time > 0:
# Zeichen pro Sekunde
chars_per_second = total_chars / elapsed_time
# Wörter pro Minute (Annahme: 1 Wort = 5 Zeichen)
words_per_minute = (total_chars / 5) / (elapsed_time / 60)
# Durchschnittliche Zeit pro Zeichen
duration_per_char = elapsed_time / total_chars
else:
chars_per_second = 0
words_per_minute = 0
duration_per_char = 0
# Fehlerrate und Genauigkeit
error_rate = (incorrect_chars / total_chars * 100) if total_chars > 0 else 0
time_taken = total_chars * 0.05 # Simulierte Zeit
typing_speed = (total_chars / time_taken * 60) if time_taken > 0 else 0
duration_per_char = (time_taken / total_chars) if total_chars > 0 and time_taken > 0 else 0
words_per_minute = ((total_chars / 5) / (time_taken / 60)) if total_chars > 0 and time_taken > 0 else 0
accuracy = (correct_chars / total_chars * 100) if total_chars > 0 else 0
return {
@ -371,7 +382,7 @@ def calculate_statistics(user_input, current_text):
'incorrect_chars': incorrect_chars,
'total_chars': total_chars,
'error_rate': round(error_rate, 1),
'typing_speed': round(typing_speed, 2),
'typing_speed': round(chars_per_second, 2),
'duration_per_char': round(duration_per_char, 3),
'words_per_minute': round(words_per_minute, 2),
'accuracy': round(accuracy, 2)

View file

@ -15,10 +15,22 @@ document.addEventListener('DOMContentLoaded', function() {
// Aktuelle Textdaten
let currentText = window.initialText;
let startTime = null;
let timerInterval = null;
// Fokus auf das Eingabefeld setzen
userInput.focus();
// Starte die Zeitmessung beim ersten Tastendruck
userInput.addEventListener('keydown', function(event) {
if (!startTime && event.key.length === 1) { // Nur Buchstaben, Zahlen, etc.
startTime = new Date();
// Starte Timer für Echtzeit-Update
if (timerInterval) clearInterval(timerInterval);
timerInterval = setInterval(updateTimer, 100);
}
});
// Aktualisiere die Statistik bei Eingabe
userInput.addEventListener('input', function() {
const userValue = this.value;
@ -26,6 +38,10 @@ document.addEventListener('DOMContentLoaded', function() {
// Wenn der Text vollständig getippt wurde, automatisch zur nächsten Zeile
if (userValue === currentText) {
if (timerInterval) {
clearInterval(timerInterval);
timerInterval = null;
}
setTimeout(function() {
fetch('/next_text', {
method: 'POST',
@ -42,16 +58,33 @@ document.addEventListener('DOMContentLoaded', function() {
userInput.value = '';
userInput.focus(); // Fokus zurück auf Eingabefeld
updateStatistics('', currentText);
// Zurücksetzen der Zeitmessung
startTime = null;
})
.catch(error => console.error('Fehler:', error));
}, 100); // Kurze Verzögerung für bessere Benutzererfahrung
}
});
// Timer für Echtzeit-Update der Statistik
function updateTimer() {
if (startTime) {
const userValue = userInput.value;
updateStatistics(userValue, currentText);
}
}
// Event-Listener für Lektions-Buttons
document.querySelectorAll('.lesson-btn').forEach(button => {
button.addEventListener('click', function() {
const lessonIndex = parseInt(this.getAttribute('data-lesson-index'));
// Stoppe Timer und setze Zeit zurück
if (timerInterval) {
clearInterval(timerInterval);
timerInterval = null;
}
startTime = null;
fetch('/set_lesson', {
method: 'POST',
headers: {
@ -78,8 +111,15 @@ document.addEventListener('DOMContentLoaded', function() {
});
});
// Nächste Zeile Button
// Nächster Text Button
nextBtn.addEventListener('click', function() {
// Stoppe Timer und setze Zeit zurück
if (timerInterval) {
clearInterval(timerInterval);
timerInterval = null;
}
startTime = null;
fetch('/next_text', {
method: 'POST',
headers: {
@ -117,6 +157,13 @@ document.addEventListener('DOMContentLoaded', function() {
// Statistik aktualisieren
function updateStatistics(userInput, currentText) {
// Berechne verstrichene Zeit
let elapsedTime = 0;
if (startTime) {
const now = new Date();
elapsedTime = (now - startTime) / 1000; // in Sekunden
}
// Sende Daten an den Server
fetch('/update_progress', {
method: 'POST',
@ -125,19 +172,22 @@ document.addEventListener('DOMContentLoaded', function() {
},
body: JSON.stringify({
user_input: userInput,
current_text: currentText
current_text: currentText,
elapsed_time: elapsedTime
})
})
.then(response => response.json())
.then(data => {
// Aktualisiere die Anzeige
speedElement.textContent = data.typing_speed;
durationElement.textContent = data.duration_per_char + 's';
durationElement.textContent = data.duration_per_char.toFixed(3) + 's';
errorRateElement.textContent = data.error_rate + '%';
correctElement.textContent = data.correct_chars;
incorrectElement.textContent = data.incorrect_chars;
totalElement.textContent = data.total_chars;
wpmElement.textContent = data.words_per_minute;
wpmElement.textContent = data.words_per_minute.toFixed(2);
// Aktualisiere die Genauigkeit
document.getElementById('accuracy').textContent = data.accuracy.toFixed(1) + '%';
// Aktualisiere die Textfarben
updateTextHighlighting(userInput, currentText);