app/app.py aktualisiert
This commit is contained in:
parent
8ce68eddd2
commit
d4e3dd4a92
91
app/app.py
91
app/app.py
@ -34,10 +34,9 @@ def init_db():
|
|||||||
cur.close()
|
cur.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
# Start-Initialisierung
|
|
||||||
init_db()
|
init_db()
|
||||||
|
|
||||||
# --- HELPER FUNKTIONEN ---
|
# --- HELPER ---
|
||||||
|
|
||||||
def is_middle_relevant(text):
|
def is_middle_relevant(text):
|
||||||
if not text: return False
|
if not text: return False
|
||||||
@ -50,13 +49,14 @@ def is_middle_relevant(text):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def clean_german_answers(text):
|
def clean_german_answers(text):
|
||||||
|
# Alles in Klammern entfernen und splitten
|
||||||
text = re.sub(r'\(.*?\)', '', text)
|
text = re.sub(r'\(.*?\)', '', text)
|
||||||
text = re.sub(r'\[.*?\]', '', text)
|
text = re.sub(r'\[.*?\]', '', text)
|
||||||
parts = re.split(r'[;,]', text)
|
parts = re.split(r'[;,]', text)
|
||||||
return [p.strip() for p in parts if p.strip()]
|
return [p.strip() for p in parts if p.strip()]
|
||||||
|
|
||||||
def check_middle_logic(user_in, correct):
|
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()
|
u = user_in.strip().lower()
|
||||||
c = correct.strip().lower()
|
c = correct.strip().lower()
|
||||||
|
|
||||||
@ -69,27 +69,34 @@ def check_middle_logic(user_in, correct):
|
|||||||
|
|
||||||
if not u_parts: return 'wrong'
|
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)
|
all_user_parts_correct = all(p in c_parts for p in u_parts)
|
||||||
|
|
||||||
if all_user_parts_correct:
|
if all_user_parts_correct:
|
||||||
|
# Wenn weniger Teile als nötig -> unvollständig
|
||||||
if len(u_parts) < len(c_parts):
|
if len(u_parts) < len(c_parts):
|
||||||
return 'incomplete'
|
return 'incomplete'
|
||||||
return 'correct'
|
return 'correct'
|
||||||
|
|
||||||
|
# Tippfehler-Check
|
||||||
ratio = SequenceMatcher(None, u, c).ratio()
|
ratio = SequenceMatcher(None, u, c).ratio()
|
||||||
if ratio > 0.85: return 'typo'
|
if ratio > 0.85: return 'typo'
|
||||||
|
|
||||||
return 'wrong'
|
return 'wrong'
|
||||||
|
|
||||||
def check_string_match(user_in, correct):
|
def check_string_match(user_in, correct):
|
||||||
|
"""Standard String Vergleich"""
|
||||||
u = user_in.strip().lower()
|
u = user_in.strip().lower()
|
||||||
c = correct.strip().lower()
|
c = correct.strip().lower()
|
||||||
|
if not u: return 'wrong'
|
||||||
|
|
||||||
if u == c: return 'correct'
|
if u == c: return 'correct'
|
||||||
|
|
||||||
ratio = SequenceMatcher(None, u, c).ratio()
|
ratio = SequenceMatcher(None, u, c).ratio()
|
||||||
if ratio > 0.85: return 'typo'
|
if ratio > 0.85: return 'typo'
|
||||||
return 'wrong'
|
return 'wrong'
|
||||||
|
|
||||||
# --- ROUTEN ---
|
# --- ROUTES ---
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
@ -103,15 +110,11 @@ def get_lessons():
|
|||||||
rows = cur.fetchall()
|
rows = cur.fetchall()
|
||||||
cur.close()
|
cur.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
lessons = [r[0] for r in rows]
|
lessons = [r[0] for r in rows]
|
||||||
|
|
||||||
# Sortierung: Erst Zahlen, dann Strings, "Original" ganz hinten
|
|
||||||
def sort_key(val):
|
def sort_key(val):
|
||||||
if val.isdigit(): return (0, int(val))
|
if val.isdigit(): return (0, int(val))
|
||||||
if val.startswith("Original"): return (2, val)
|
if val.startswith("Original"): return (2, val)
|
||||||
return (1, val)
|
return (1, val)
|
||||||
|
|
||||||
lessons.sort(key=sort_key)
|
lessons.sort(key=sort_key)
|
||||||
return jsonify(lessons)
|
return jsonify(lessons)
|
||||||
|
|
||||||
@ -158,34 +161,69 @@ def check():
|
|||||||
inputs = data.get('inputs', [])
|
inputs = data.get('inputs', [])
|
||||||
attempt_num = data.get('attempt', 1)
|
attempt_num = data.get('attempt', 1)
|
||||||
|
|
||||||
results = []
|
# Wir initialisieren die Ergebnis-Liste mit "falsch", damit wir sie später füllen können
|
||||||
total_items = len(inputs)
|
results = [None] * len(inputs)
|
||||||
|
|
||||||
correct_items = 0
|
correct_items = 0
|
||||||
|
total_items = len(inputs)
|
||||||
has_incomplete = False
|
has_incomplete = False
|
||||||
|
|
||||||
for inp in inputs:
|
# 1. GRAMMATIK (Mitte) direkt prüfen (feste Position)
|
||||||
user_val = inp.get('value', '')
|
for i, inp in enumerate(inputs):
|
||||||
correct_val = inp.get('correct', '')
|
if inp.get('type') == 'middle':
|
||||||
field_type = inp.get('type', 'german')
|
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
|
||||||
|
|
||||||
status = 'wrong'
|
results[i] = {'status': status, 'correct': inp.get('correct', ''), 'msg': msg}
|
||||||
|
if status in ['correct', 'typo']: correct_items += 1
|
||||||
|
|
||||||
if field_type == 'middle':
|
# 2. DEUTSCH (German) - Pool-Logik für Reihenfolge-Unabhängigkeit
|
||||||
status = check_middle_logic(user_val, correct_val)
|
|
||||||
else:
|
|
||||||
status = check_string_match(user_val, correct_val)
|
|
||||||
|
|
||||||
res_entry = {'status': status, 'correct': correct_val}
|
# 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 = []
|
||||||
|
|
||||||
if status == 'incomplete':
|
for i, inp in enumerate(inputs):
|
||||||
res_entry['msg'] = 'Unvollständig! Da fehlt noch etwas.'
|
if inp.get('type') == 'german' or inp.get('type') is None:
|
||||||
has_incomplete = True
|
german_user_inputs.append({'index': i, 'value': inp.get('value', '')})
|
||||||
|
german_correct_pool.append(inp.get('correct', ''))
|
||||||
|
|
||||||
results.append(res_entry)
|
# Welche Pool-Einträge wurden schon "verbraucht"?
|
||||||
|
used_pool_indices = set()
|
||||||
|
|
||||||
if status in ['correct', 'typo']:
|
# Jetzt prüfen wir jede User-Eingabe gegen den GANZEN Pool
|
||||||
correct_items += 1
|
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
|
score_fraction = 0
|
||||||
if total_items > 0:
|
if total_items > 0:
|
||||||
base_score = correct_items / total_items
|
base_score = correct_items / total_items
|
||||||
@ -203,4 +241,5 @@ def check():
|
|||||||
})
|
})
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
# Production settings
|
||||||
app.run(host='0.0.0.0', port=5000)
|
app.run(host='0.0.0.0', port=5000)
|
||||||
Loading…
x
Reference in New Issue
Block a user