Mehrwörtige Wort-Einträge verhindern + orange highlighten
- Backend: _sanitize_word() splittet Komma-Listen und filtert Mehrwörter raus - Frontend: Chips mit Leerzeichen/Komma werden orange markiert (Tooltip) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
22
app.py
22
app.py
@@ -1044,12 +1044,26 @@ def generate_questions(obj_id: str):
|
|||||||
"questions_linked": 0,
|
"questions_linked": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _sanitize_word(raw: str) -> list[str]:
|
||||||
|
"""Zerlegt kommagetrennte Einträge und gibt nur echte Einzelwörter zurück."""
|
||||||
|
tokens = []
|
||||||
|
for part in raw.replace(";", ",").split(","):
|
||||||
|
part = part.strip().strip("\"'")
|
||||||
|
if not part:
|
||||||
|
continue
|
||||||
|
words_in_part = part.split()
|
||||||
|
if len(words_in_part) == 1:
|
||||||
|
tokens.append(words_in_part[0])
|
||||||
|
# Mehrwortige Einträge → überspringen (KI-Fehler)
|
||||||
|
return tokens
|
||||||
|
|
||||||
# Alle eindeutigen Wörter aus allen Leveln vorab sammeln und einmalig laden
|
# Alle eindeutigen Wörter aus allen Leveln vorab sammeln und einmalig laden
|
||||||
all_words_by_level: dict[str, int] = {} # title_de → first level seen
|
all_words_by_level: dict[str, int] = {} # title_de → first level seen
|
||||||
for lvl in levels:
|
for lvl in levels:
|
||||||
level = int(lvl.get("level") or 1)
|
level = int(lvl.get("level") or 1)
|
||||||
for w in lvl.get("words", []) + lvl.get("distractor_words", []) + [lvl.get("short_answer", "")]:
|
raw_words = lvl.get("words", []) + lvl.get("distractor_words", []) + [lvl.get("short_answer", "")]
|
||||||
w = str(w).strip()
|
for raw in raw_words:
|
||||||
|
for w in _sanitize_word(str(raw)):
|
||||||
if w and w not in all_words_by_level:
|
if w and w not in all_words_by_level:
|
||||||
all_words_by_level[w] = level
|
all_words_by_level[w] = level
|
||||||
|
|
||||||
@@ -1074,8 +1088,8 @@ def generate_questions(obj_id: str):
|
|||||||
q_de = (lvl.get("question") or "").strip()
|
q_de = (lvl.get("question") or "").strip()
|
||||||
a_de = (lvl.get("answer") or "").strip()
|
a_de = (lvl.get("answer") or "").strip()
|
||||||
short_text = (lvl.get("short_answer") or "").strip()
|
short_text = (lvl.get("short_answer") or "").strip()
|
||||||
words_list = [str(w).strip() for w in lvl.get("words", []) if str(w).strip()]
|
words_list = [t for raw in lvl.get("words", []) for t in _sanitize_word(str(raw))]
|
||||||
distractor_list = [str(w).strip() for w in lvl.get("distractor_words", []) if str(w).strip()]
|
distractor_list = [t for raw in lvl.get("distractor_words", []) for t in _sanitize_word(str(raw))]
|
||||||
|
|
||||||
if not q_de:
|
if not q_de:
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -443,8 +443,10 @@ export default function GenerateIt() {
|
|||||||
<div className="empty-state">–</div>
|
<div className="empty-state">–</div>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ overflowY: 'auto', flex: 1, padding: '4px 8px', display: 'flex', flexWrap: 'wrap', gap: 4, alignContent: 'flex-start' }}>
|
<div style={{ overflowY: 'auto', flex: 1, padding: '4px 8px', display: 'flex', flexWrap: 'wrap', gap: 4, alignContent: 'flex-start' }}>
|
||||||
{objWords.map(w => (
|
{objWords.map(w => {
|
||||||
<span key={w.id} className="word-chip" style={{ display: 'inline-flex', alignItems: 'center', gap: 3 }}>
|
const isInvalid = /[\s,;]/.test(w.title_de)
|
||||||
|
return (
|
||||||
|
<span key={w.id} className="word-chip" style={{ display: 'inline-flex', alignItems: 'center', gap: 3, ...(isInvalid ? { background: 'var(--warning-bg, #fff3cd)', border: '1px solid var(--warning, #f0a500)', color: 'var(--warning-fg, #7a4f00)' } : {}) }} title={isInvalid ? 'Mehrwortiger Eintrag – bitte löschen' : undefined}>
|
||||||
{w.title_de}
|
{w.title_de}
|
||||||
<button
|
<button
|
||||||
onClick={() => handleDeleteWord(w.id)}
|
onClick={() => handleDeleteWord(w.id)}
|
||||||
@@ -452,7 +454,8 @@ export default function GenerateIt() {
|
|||||||
title="Löschen"
|
title="Löschen"
|
||||||
>✕</button>
|
>✕</button>
|
||||||
</span>
|
</span>
|
||||||
))}
|
)
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user