diff --git a/app.py b/app.py index 30cc047..0c3cb52 100644 --- a/app.py +++ b/app.py @@ -1145,14 +1145,6 @@ def generate_questions(obj_id: str): if not levels: return jsonify({"error": "No levels in AI response"}), 500 - # Junction-Collections sicherstellen (einmalig) - for col, f1, f2 in [ - ("words_objects", "words_id", "objects_id"), - ("questions_objects", "questions_id", "objects_id"), - ("questions_distractor_words", "questions_id", "words_id"), - ]: - _ensure_junction(col, f1, f2, token) - stats = { "words_created": 0, "words_linked": 0, @@ -1173,6 +1165,21 @@ def generate_questions(obj_id: str): # Mehrwortige Einträge → überspringen (KI-Fehler) return tokens + # Bestehende Verlinkungen vorab laden (Dedup ohne N×GET) + ew_data, _ = _directus( + "GET", + f"/items/words_objects?filter[objects_id][_eq]={obj_id}&fields[]=words_id&limit=2000", + token, + ) + existing_word_ids: set[str] = {e["words_id"] for e in (ew_data.get("data") or [])} + + eq_data, _ = _directus( + "GET", + f"/items/questions_objects?filter[objects_id][_eq]={obj_id}&fields[]=questions_id&limit=200", + token, + ) + existing_question_ids: set[str] = {e["questions_id"] for e in (eq_data.get("data") or [])} + # Alle eindeutigen Wörter aus allen Leveln vorab sammeln und einmalig laden all_words_by_level: dict[str, int] = {} # title_de → first level seen for lvl in levels: @@ -1185,20 +1192,22 @@ def generate_questions(obj_id: str): # Wörter einmalig anlegen / finden (globaler Cache über alle Level) global_word_map: dict[str, str] = {} # title_de → id + new_word_links: list[dict] = [] for w, lvl_num in all_words_by_level.items(): try: wid, is_new = _find_or_create_word(w, lvl_num, token) global_word_map[w] = wid - _ensure_link( - "words_objects", - {"words_id": wid, "objects_id": obj_id}, - {"words_id": wid, "objects_id": obj_id}, - token, - ) + if wid not in existing_word_ids: + new_word_links.append({"words_id": wid, "objects_id": obj_id}) + existing_word_ids.add(wid) stats["words_created" if is_new else "words_linked"] += 1 except Exception as e: print(f"[generate_questions] word error '{w}': {e}") + # Alle neuen Wort-Verlinkungen in einem Batch speichern + if new_word_links: + _directus("POST", "/items/words_objects", token, new_word_links) + for lvl in levels: level = int(lvl.get("level") or 1) q_de = (lvl.get("question") or "").strip() @@ -1221,33 +1230,27 @@ def generate_questions(obj_id: str): stats["questions_created" if q_is_new else "questions_linked"] += 1 - # Frage ↔ Objekt - _ensure_link( - "questions_objects", - {"questions_id": q_id, "objects_id": obj_id}, - {"questions_id": q_id, "objects_id": obj_id}, - token, - ) + # Frage ↔ Objekt (nur wenn noch nicht verknüpft) + if q_id not in existing_question_ids: + _directus("POST", "/items/questions_objects", token, + {"questions_id": q_id, "objects_id": obj_id}) + existing_question_ids.add(q_id) - # related_words - for w in words_list: - if w in global_word_map: - _ensure_link( - "questions_words", - {"questions_id": q_id, "words_id": global_word_map[w]}, - {"questions_id": q_id, "words_id": global_word_map[w]}, - token, - ) + # related_words + distractor_words nur für neue Fragen (batch) + if q_is_new: + rw_links = [ + {"questions_id": q_id, "words_id": global_word_map[w]} + for w in words_list if w in global_word_map + ] + if rw_links: + _directus("POST", "/items/questions_words", token, rw_links) - # distractor_words - for w in distractor_list: - if w in global_word_map: - _ensure_link( - "questions_distractor_words", - {"questions_id": q_id, "words_id": global_word_map[w]}, - {"questions_id": q_id, "words_id": global_word_map[w]}, - token, - ) + dw_links = [ + {"questions_id": q_id, "words_id": global_word_map[w]} + for w in distractor_list if w in global_word_map + ] + if dw_links: + _directus("POST", "/items/questions_distractor_words", token, dw_links) print(f"[generate_questions] obj={obj_id} stats={stats}") return jsonify({"ok": True, "object_id": obj_id, "stats": stats})