From d4e3dd4a92d7408f7d29d3cc3a81b44f5a854e30 Mon Sep 17 00:00:00 2001 From: sascha Date: Wed, 28 Jan 2026 21:39:21 +0000 Subject: [PATCH] app/app.py aktualisiert --- app/app.py | 103 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/app/app.py b/app/app.py index f0585b9..6235052 100644 --- a/app/app.py +++ b/app/app.py @@ -34,10 +34,9 @@ def init_db(): cur.close() conn.close() -# Start-Initialisierung init_db() -# --- HELPER FUNKTIONEN --- +# --- HELPER --- def is_middle_relevant(text): if not text: return False @@ -50,13 +49,14 @@ def is_middle_relevant(text): return True def clean_german_answers(text): + # Alles in Klammern entfernen und splitten text = re.sub(r'\(.*?\)', '', text) text = re.sub(r'\[.*?\]', '', text) parts = re.split(r'[;,]', text) return [p.strip() for p in parts if p.strip()] def check_middle_logic(user_in, correct): - """Prüft auf Unvollständigkeit (Komma-Trennung)""" + """Prüft Grammatik (erlaubt unvollständige Eingaben)""" u = user_in.strip().lower() c = correct.strip().lower() @@ -69,27 +69,34 @@ def check_middle_logic(user_in, correct): if not u_parts: return 'wrong' + # Sind alle eingegebenen Teile in der Lösung vorhanden? all_user_parts_correct = all(p in c_parts for p in u_parts) if all_user_parts_correct: + # Wenn weniger Teile als nötig -> unvollständig if len(u_parts) < len(c_parts): return 'incomplete' return 'correct' + # Tippfehler-Check ratio = SequenceMatcher(None, u, c).ratio() if ratio > 0.85: return 'typo' return 'wrong' def check_string_match(user_in, correct): + """Standard String Vergleich""" u = user_in.strip().lower() c = correct.strip().lower() + if not u: return 'wrong' + if u == c: return 'correct' + ratio = SequenceMatcher(None, u, c).ratio() if ratio > 0.85: return 'typo' return 'wrong' -# --- ROUTEN --- +# --- ROUTES --- @app.route('/') def index(): @@ -103,15 +110,11 @@ def get_lessons(): rows = cur.fetchall() cur.close() conn.close() - lessons = [r[0] for r in rows] - - # Sortierung: Erst Zahlen, dann Strings, "Original" ganz hinten def sort_key(val): if val.isdigit(): return (0, int(val)) if val.startswith("Original"): return (2, val) return (1, val) - lessons.sort(key=sort_key) return jsonify(lessons) @@ -155,37 +158,72 @@ def get_question(): @app.route('/api/check', methods=['POST']) def check(): data = request.json - inputs = data.get('inputs', []) + inputs = data.get('inputs', []) attempt_num = data.get('attempt', 1) - results = [] - total_items = len(inputs) + # Wir initialisieren die Ergebnis-Liste mit "falsch", damit wir sie später füllen können + results = [None] * len(inputs) + correct_items = 0 + total_items = len(inputs) has_incomplete = False - for inp in inputs: - user_val = inp.get('value', '') - correct_val = inp.get('correct', '') - field_type = inp.get('type', 'german') - - status = 'wrong' - - if field_type == 'middle': - status = check_middle_logic(user_val, correct_val) - else: - status = check_string_match(user_val, correct_val) + # 1. GRAMMATIK (Mitte) direkt prüfen (feste Position) + for i, inp in enumerate(inputs): + if inp.get('type') == 'middle': + status = check_middle_logic(inp.get('value', ''), inp.get('correct', '')) + msg = 'Unvollständig! Da fehlt noch etwas.' if status == 'incomplete' else '' + if status == 'incomplete': has_incomplete = True - res_entry = {'status': status, 'correct': correct_val} - - if status == 'incomplete': - res_entry['msg'] = 'Unvollständig! Da fehlt noch etwas.' - has_incomplete = True - - results.append(res_entry) - - if status in ['correct', 'typo']: - correct_items += 1 + results[i] = {'status': status, 'correct': inp.get('correct', ''), 'msg': msg} + if status in ['correct', 'typo']: correct_items += 1 + + # 2. DEUTSCH (German) - Pool-Logik für Reihenfolge-Unabhängigkeit + + # Sammle alle deutschen User-Eingaben und ihre Indizes + german_user_inputs = [] # Liste von {'index': 1, 'value': '...'} + # Sammle alle korrekten deutschen Lösungen (Pool) + german_correct_pool = [] + + for i, inp in enumerate(inputs): + if inp.get('type') == 'german' or inp.get('type') is None: + german_user_inputs.append({'index': i, 'value': inp.get('value', '')}) + german_correct_pool.append(inp.get('correct', '')) + # Welche Pool-Einträge wurden schon "verbraucht"? + used_pool_indices = set() + + # Jetzt prüfen wir jede User-Eingabe gegen den GANZEN Pool + for u_item in german_user_inputs: + idx = u_item['index'] + val = u_item['value'] + found_match = False + matched_correct_val = "" + + # Suche im Pool nach einem Match, der noch nicht benutzt wurde + for pool_i, pool_val in enumerate(german_correct_pool): + if pool_i in used_pool_indices: + continue + + # Standard Prüfung für Deutsch + status = check_string_match(val, pool_val) + + if status in ['correct', 'typo']: + # Treffer! + results[idx] = {'status': status, 'correct': pool_val} + used_pool_indices.add(pool_i) # Lösung als "benutzt" markieren + correct_items += 1 + found_match = True + break + + # Wenn KEIN Match im Pool gefunden wurde + if not found_match: + # Wir zeigen als Lösung einfach die an, die ursprünglich an dieser Position stand + # (auch wenn die Position eigentlich egal ist, irgendwas müssen wir anzeigen) + original_correct = inputs[idx].get('correct', '') + results[idx] = {'status': 'wrong', 'correct': original_correct} + + # Punkteberechnung score_fraction = 0 if total_items > 0: base_score = correct_items / total_items @@ -203,4 +241,5 @@ def check(): }) if __name__ == '__main__': + # Production settings app.run(host='0.0.0.0', port=5000) \ No newline at end of file