app/app.py aktualisiert
This commit is contained in:
parent
cca29425ea
commit
8f1aa4e77f
110
app/app.py
110
app/app.py
@ -7,7 +7,7 @@ from difflib import SequenceMatcher
|
|||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
# --- DB VERBINDUNG & RESET (Wie gehabt) ---
|
# --- DB VERBINDUNG & RESET ---
|
||||||
def get_db_connection():
|
def get_db_connection():
|
||||||
max_retries = 10
|
max_retries = 10
|
||||||
for i in range(max_retries):
|
for i in range(max_retries):
|
||||||
@ -41,9 +41,30 @@ def reset_db_on_startup():
|
|||||||
reset_db_on_startup()
|
reset_db_on_startup()
|
||||||
|
|
||||||
# --- HILFSFUNKTIONEN ---
|
# --- HILFSFUNKTIONEN ---
|
||||||
|
|
||||||
def clean_text(text):
|
def clean_text(text):
|
||||||
|
"""Basis-Reinigung für Verben-Input"""
|
||||||
return text.lower().strip()
|
return text.lower().strip()
|
||||||
|
|
||||||
|
def clean_vocab_input(text):
|
||||||
|
"""
|
||||||
|
Spezielle Reinigung für Vokabeln:
|
||||||
|
1. Kleinbuchstaben & Leerzeichen weg.
|
||||||
|
2. Führendes 'to ' entfernen (damit 'go' == 'to go').
|
||||||
|
3. Klammern entfernen (z.B. '(to)' -> weg).
|
||||||
|
"""
|
||||||
|
t = text.lower().strip()
|
||||||
|
|
||||||
|
# Klammern entfernen
|
||||||
|
t = t.replace('(', '').replace(')', '').replace('[', '').replace(']', '')
|
||||||
|
t = t.strip()
|
||||||
|
|
||||||
|
# Führendes "to " entfernen (nur wenn es ein ganzes Wort ist)
|
||||||
|
if t.startswith('to '):
|
||||||
|
t = t[3:].strip()
|
||||||
|
|
||||||
|
return t
|
||||||
|
|
||||||
def check_part(user_in, correct_str):
|
def check_part(user_in, correct_str):
|
||||||
variants = [x.strip().lower() for x in correct_str.split('/')]
|
variants = [x.strip().lower() for x in correct_str.split('/')]
|
||||||
return user_in in variants
|
return user_in in variants
|
||||||
@ -56,9 +77,7 @@ def index():
|
|||||||
|
|
||||||
@app.route('/api/pages')
|
@app.route('/api/pages')
|
||||||
def get_pages():
|
def get_pages():
|
||||||
# Wir filtern jetzt nach Typ!
|
mode_type = request.args.get('type', 'vocab')
|
||||||
mode_type = request.args.get('type', 'vocab') # 'vocab' oder 'irregular'
|
|
||||||
|
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
|
|
||||||
@ -77,15 +96,14 @@ def get_pages():
|
|||||||
@app.route('/api/question', methods=['POST'])
|
@app.route('/api/question', methods=['POST'])
|
||||||
def get_question():
|
def get_question():
|
||||||
data = request.json
|
data = request.json
|
||||||
main_mode = data.get('mainMode') # 'vocab' oder 'irregular'
|
main_mode = data.get('mainMode')
|
||||||
sub_mode = data.get('subMode') # 'de-en', 'start-german', etc.
|
sub_mode = data.get('subMode')
|
||||||
pages = data.get('pages', [])
|
pages = data.get('pages', [])
|
||||||
|
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
|
|
||||||
if main_mode == 'irregular':
|
if main_mode == 'irregular':
|
||||||
# Verben Logik
|
|
||||||
query = "SELECT infinitive, simple_past, past_participle, german, page FROM irregular_verbs WHERE page = ANY(%s) ORDER BY RANDOM() LIMIT 1"
|
query = "SELECT infinitive, simple_past, past_participle, german, page FROM irregular_verbs WHERE page = ANY(%s) ORDER BY RANDOM() LIMIT 1"
|
||||||
cur.execute(query, (pages,))
|
cur.execute(query, (pages,))
|
||||||
row = cur.fetchone()
|
row = cur.fetchone()
|
||||||
@ -94,22 +112,19 @@ def get_question():
|
|||||||
|
|
||||||
if not row: return jsonify({'error': 'Keine Verben gefunden.'})
|
if not row: return jsonify({'error': 'Keine Verben gefunden.'})
|
||||||
|
|
||||||
# Entscheiden basierend auf sub_mode
|
|
||||||
if sub_mode == 'start-german':
|
if sub_mode == 'start-german':
|
||||||
# Frage: Deutsch -> Antwort: Alle 3 Formen
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'type': 'irregular_full',
|
'type': 'irregular_full',
|
||||||
'question': row[3], # Deutsch
|
'question': row[3],
|
||||||
'answer_infinitive': row[0],
|
'answer_infinitive': row[0],
|
||||||
'answer_simple': row[1],
|
'answer_simple': row[1],
|
||||||
'answer_participle': row[2],
|
'answer_participle': row[2],
|
||||||
'page': row[4]
|
'page': row[4]
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
# Frage: Infinitiv -> Antwort: Past & Participle (Standard)
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'type': 'irregular_standard',
|
'type': 'irregular_standard',
|
||||||
'question': row[0], # Infinitive
|
'question': row[0],
|
||||||
'german_hint': row[3],
|
'german_hint': row[3],
|
||||||
'answer_simple': row[1],
|
'answer_simple': row[1],
|
||||||
'answer_participle': row[2],
|
'answer_participle': row[2],
|
||||||
@ -117,7 +132,6 @@ def get_question():
|
|||||||
})
|
})
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Vokabel Logik
|
|
||||||
query = "SELECT english, german, page FROM vocabulary WHERE page = ANY(%s) ORDER BY RANDOM() LIMIT 1"
|
query = "SELECT english, german, page FROM vocabulary WHERE page = ANY(%s) ORDER BY RANDOM() LIMIT 1"
|
||||||
cur.execute(query, (pages,))
|
cur.execute(query, (pages,))
|
||||||
row = cur.fetchone()
|
row = cur.fetchone()
|
||||||
@ -131,7 +145,7 @@ def get_question():
|
|||||||
q_text, a_text = row[1], row[0]
|
q_text, a_text = row[1], row[0]
|
||||||
elif sub_mode == 'en-de':
|
elif sub_mode == 'en-de':
|
||||||
q_text, a_text = row[0], row[1]
|
q_text, a_text = row[0], row[1]
|
||||||
else: # random
|
else:
|
||||||
if random.random() > 0.5: q_text, a_text = row[1], row[0]
|
if random.random() > 0.5: q_text, a_text = row[1], row[0]
|
||||||
else: q_text, a_text = row[0], row[1]
|
else: q_text, a_text = row[0], row[1]
|
||||||
|
|
||||||
@ -147,7 +161,11 @@ def check_answer():
|
|||||||
data = request.json
|
data = request.json
|
||||||
q_type = data.get('type')
|
q_type = data.get('type')
|
||||||
|
|
||||||
# 1. Verben: Alles abfragen (Start: Deutsch)
|
# --- 1. & 2. VERBEN (Keine Typos, strikt) ---
|
||||||
|
if q_type.startswith('irregular'):
|
||||||
|
is_correct = False
|
||||||
|
msg = ""
|
||||||
|
|
||||||
if q_type == 'irregular_full':
|
if q_type == 'irregular_full':
|
||||||
u_inf = clean_text(data.get('infinitive', ''))
|
u_inf = clean_text(data.get('infinitive', ''))
|
||||||
u_simp = clean_text(data.get('simple', ''))
|
u_simp = clean_text(data.get('simple', ''))
|
||||||
@ -157,13 +175,8 @@ def check_answer():
|
|||||||
ok_simp = check_part(u_simp, data.get('correct_simple', ''))
|
ok_simp = check_part(u_simp, data.get('correct_simple', ''))
|
||||||
ok_part = check_part(u_part, data.get('correct_participle', ''))
|
ok_part = check_part(u_part, data.get('correct_participle', ''))
|
||||||
|
|
||||||
if ok_inf and ok_simp and ok_part:
|
if ok_inf and ok_simp and ok_part: is_correct = True
|
||||||
return jsonify({'status': 'correct', 'msg': 'Perfekt! Alles richtig.'})
|
|
||||||
else:
|
|
||||||
sol = f"{data['correct_infinitive']} -> {data['correct_simple']} -> {data['correct_participle']}"
|
|
||||||
return jsonify({'status': 'wrong', 'msg': f'Leider falsch. Lösung: {sol}'})
|
|
||||||
|
|
||||||
# 2. Verben: Standard (Start: Infinitiv)
|
|
||||||
elif q_type == 'irregular_standard':
|
elif q_type == 'irregular_standard':
|
||||||
u_simp = clean_text(data.get('simple', ''))
|
u_simp = clean_text(data.get('simple', ''))
|
||||||
u_part = clean_text(data.get('participle', ''))
|
u_part = clean_text(data.get('participle', ''))
|
||||||
@ -171,36 +184,57 @@ def check_answer():
|
|||||||
ok_simp = check_part(u_simp, data.get('correct_simple', ''))
|
ok_simp = check_part(u_simp, data.get('correct_simple', ''))
|
||||||
ok_part = check_part(u_part, data.get('correct_participle', ''))
|
ok_part = check_part(u_part, data.get('correct_participle', ''))
|
||||||
|
|
||||||
if ok_simp and ok_part:
|
if ok_simp and ok_part: is_correct = True
|
||||||
|
|
||||||
|
if is_correct:
|
||||||
return jsonify({'status': 'correct', 'msg': 'Richtig!'})
|
return jsonify({'status': 'correct', 'msg': 'Richtig!'})
|
||||||
else:
|
else:
|
||||||
sol = f"{data['correct_simple']} -> {data['correct_participle']}"
|
# Bei Verben schicken wir KEINE Lösung im msg Feld, das macht das Frontend erst am Ende
|
||||||
return jsonify({'status': 'wrong', 'msg': f'Lösung: {sol}'})
|
return jsonify({'status': 'wrong', 'msg': 'Leider nicht ganz richtig.'})
|
||||||
|
|
||||||
# 3. Vokabeln
|
# --- 3. VOKABELN (Mit "to"-Logik und Typos) ---
|
||||||
else:
|
else:
|
||||||
u_input = clean_text(data.get('input', ''))
|
u_input_raw = data.get('input', '')
|
||||||
correct_raw = data.get('correct', '')
|
correct_raw = data.get('correct', '')
|
||||||
|
|
||||||
# Split variants (e.g. "car; auto")
|
# Bereinigter Vergleich (ohne "to ", ohne Klammern)
|
||||||
valid_answers = [clean_text(x) for x in correct_raw.split(';')]
|
u_clean = clean_vocab_input(u_input_raw)
|
||||||
# Add version without brackets "(to) go" -> "go"
|
|
||||||
for v in list(valid_answers):
|
|
||||||
if '(' in v: valid_answers.append(v.replace('(','').replace(')','').strip())
|
|
||||||
|
|
||||||
if u_input in valid_answers:
|
# Antwortmöglichkeiten vorbereiten (Splitten bei ';')
|
||||||
|
valid_answers = []
|
||||||
|
raw_parts = correct_raw.split(';')
|
||||||
|
for p in raw_parts:
|
||||||
|
# Original rein
|
||||||
|
valid_answers.append(clean_vocab_input(p))
|
||||||
|
# Falls "(to) go" drin stand -> das wird durch clean_vocab_input schon zu "go"
|
||||||
|
# Aber falls "to go" drin stand -> wird zu "go"
|
||||||
|
|
||||||
|
# 1. Direkter Treffer
|
||||||
|
if u_clean in valid_answers:
|
||||||
return jsonify({'status': 'correct', 'msg': 'Richtig!'})
|
return jsonify({'status': 'correct', 'msg': 'Richtig!'})
|
||||||
|
|
||||||
# Fuzzy Check
|
# 2. Fuzzy Match (Rechtschreibprüfung)
|
||||||
best_ratio = 0
|
best_ratio = 0
|
||||||
|
best_match = ""
|
||||||
for v in valid_answers:
|
for v in valid_answers:
|
||||||
ratio = SequenceMatcher(None, u_input, v).ratio()
|
ratio = SequenceMatcher(None, u_clean, v).ratio()
|
||||||
if ratio > best_ratio: best_ratio = ratio
|
if ratio > best_ratio:
|
||||||
|
best_ratio = ratio
|
||||||
|
best_match = v # Das bereinigte Wort als Vorschlag
|
||||||
|
|
||||||
if best_ratio >= 0.8:
|
# Toleranz: 85% Übereinstimmung, bei kurzen Wörtern (<5 Zeichen) strenger (90%)
|
||||||
return jsonify({'status': 'typo', 'msg': f'Fast richtig! Lösung: {correct_raw}'})
|
threshold = 0.85
|
||||||
|
if len(best_match) < 5:
|
||||||
|
threshold = 0.9
|
||||||
|
|
||||||
return jsonify({'status': 'wrong', 'msg': f'Falsch. Lösung: {correct_raw}'})
|
if best_ratio >= threshold:
|
||||||
|
return jsonify({
|
||||||
|
'status': 'typo',
|
||||||
|
'msg': f'Fast richtig! Meintest du: "{best_match}"? (Achte auf die Schreibweise)'
|
||||||
|
})
|
||||||
|
|
||||||
|
# 3. Falsch
|
||||||
|
return jsonify({'status': 'wrong', 'msg': 'Leider falsch.'})
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
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