diff --git a/app.py b/app.py index 5abdd0e..f3cf7a9 100644 --- a/app.py +++ b/app.py @@ -615,6 +615,24 @@ def _transcribe_video_bg(db_path: str, submission_id: int, video_path: str): auto_process_bg(db_path, submission_id) +def mark_ausverkauft_in_neuheiten(db, spiel_titel): + """Cross-reference ausverkauft submission with neuheiten table. + Sets bit 0 of neuheiten.flags to mark the game as sold out. + Returns number of matched neuheiten rows.""" + if not spiel_titel: + return 0 + try: + # Use LIKE for fuzzy matching (handles minor spelling variations) + result = db.execute( + "UPDATE neuheiten SET flags = flags | 1 WHERE LOWER(titel) LIKE ?", + (f"%{spiel_titel.lower().strip()}%",), + ) + db.commit() + return result.rowcount + except Exception: + return 0 + + # ── Routes ────────────────────────────────────────────────────────── @app.route("/whatsapp/webhook", methods=["GET", "POST"]) def whatsapp_webhook(): @@ -753,6 +771,9 @@ def whatsapp_webhook(): "UPDATE submissions SET category=?, spiel_titel=? WHERE id=?", ("ausverkauft", out_title, recent["id"]), ) + # Auto-mark matching neuheiten as sold out + if out_title: + mark_ausverkauft_in_neuheiten(db, out_title) # Merge media paths (keep all, separated by ||) if media_path: merged_media = media_path @@ -772,6 +793,9 @@ def whatsapp_webhook(): VALUES (?, ?, ?, ?, ?, ?, 'new', ?, ?, ?)""", ("whatsapp", sender_id, sender_name, msg_type, content, media_path, halle, cat, spiel_titel), ) + # Auto-mark matching neuheiten as sold out + if cat == "ausverkauft" and spiel_titel: + mark_ausverkauft_in_neuheiten(db, spiel_titel) # Auto-reply: only on NEW threads, not appends if not thread_found and META_TOKEN: @@ -789,7 +813,6 @@ def whatsapp_webhook(): ) send_whatsapp_message(sender_id, reply) # Thorsten voice: same text but without emojis - import re tts_text = re.sub(r'[^\x00-\x7F\u00C0-\u00FF\u0100-\u017F\u0180-\u024F\u1E00-\u1EFF\u2018-\u201F\u2013\u2014\u2026\u00A0\u00AB\u00BB\u20AC]', '', reply) tts_text = re.sub(r' +', ' ', tts_text).strip() audio_path = generate_thorsten_tts(tts_text) @@ -3213,7 +3236,7 @@ def api_chat(): params_n.extend(params_n[:]) # duplicate for WHERE clause score_expr_n = ' + '.join(score_parts_n) sql_n = ( - f"SELECT titel, untertitel, halle, stand, info_text, themen, web, ({score_expr_n}) AS relevance " + f"SELECT titel, untertitel, halle, stand, info_text, themen, web, flags, ({score_expr_n}) AS relevance " "FROM neuheiten " f"WHERE {' OR '.join(like_clauses_n)} " "ORDER BY relevance DESC LIMIT 30" @@ -3235,12 +3258,43 @@ def api_chat(): halle_stand = f"{n['halle'] or ''} {n['stand'] or ''}".strip() verlag = n['untertitel'] or '' themen = (n['themen'] or '').strip() + ausverkauft = 'AUSVERKAUFT' if (n['flags'] or 0) & 1 else '' context_parts.append( f"[Neuheit] {n['titel']}" + (f" | Verlag: {verlag}" if verlag else '') + (f" | {halle_stand}" if halle_stand else '') + + (f" | 🔴 {ausverkauft}" if ausverkauft else '') + (f" | {themen}" if themen else '') ) + + # Also search published submissions for ausverkauft stories with matching spiel_titel + if meaningful_terms: + ausverkauft_subs = [] + try: + for t in meaningful_terms: + rows = db.execute( + "SELECT spiel_titel, content, halle, published_at FROM submissions " + "WHERE status='published' AND deleted_at IS NULL " + "AND category='ausverkauft' AND spiel_titel IS NOT NULL " + "AND LOWER(spiel_titel) LIKE ? LIMIT 5", + (f"%{t}%",), + ).fetchall() + ausverkauft_subs.extend(rows) + except Exception: + pass + # Deduplicate by spiel_titel + seen_titles = set() + for r in ausverkauft_subs[:10]: + title = (r['spiel_titel'] or '').strip() + if title and title.lower() not in seen_titles: + seen_titles.add(title.lower()) + halle = r['halle'] or '' + snippet = (r['content'] or '').strip()[:120] + context_parts.append( + f"[Ausverkauft-Meldung] {title}" + + (f" | {halle}" if halle else '') + + (f" | {snippet}" if snippet else '') + ) context = '\n'.join(context_parts) # System prompt @@ -3256,6 +3310,9 @@ def api_chat(): "- Bei Standortfragen nenne immer die Hallen-Nummer.\n" "- [Aussteller]-Einträge enthalten Verlage/Shops mit Halle, Stand und Land.\n" "- [Neuheit]-Einträge enthalten Brettspiel-Neuheiten mit Verlag, Halle, Stand und Kategorien.\n" + "- [Neuheit] mit 'AUSVERKAUFT' = am Stand vergriffen — erwähne das aktiv.\n" + "- [Ausverkauft-Meldung]-Einträge = Community-Berichte über vergriffene Spiele.\n" + "- Bei Fragen wie 'ist X noch da?' prüfe Ausverkauft-Status und warne.\n" "- Wenn du einen Beitrag erwähnst, verlinke ihn IMMER mit der Beitrags-ID aus dem Kontext.\n" " Format: [Kurzbeschreibung](/beitrag/ID)\n" " Beispiel: 'Schau dir [diesen Erfahrungsbericht](/beitrag/53) an!'\n"