From 29f3e7348077d8d13ff2ef04c234438a171b66ad Mon Sep 17 00:00:00 2001 From: claude-dev Date: Sun, 8 Mar 2026 19:05:46 +0100 Subject: [PATCH] Fix: Duplikat-Check + Stale-Check in Streaming-Endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Duplikat-Check in search-fix auf source_id+type umgestellt - Stale-Check im Streaming-Endpoint überspringt web_sources Co-Authored-By: Claude Opus 4.6 --- src/routers/sources.py | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/routers/sources.py b/src/routers/sources.py index efff0de..262f09e 100644 --- a/src/routers/sources.py +++ b/src/routers/sources.py @@ -1,9 +1,9 @@ import os -"""Grundquellen-Verwaltung und Kundenquellen-Übersicht.""" +"""Grundquellen-Verwaltung und Kundenquellen-Übersicht.""" import sys import logging -# Monitor-Source-Rules verfügbar machen +# Monitor-Source-Rules verfügbar machen sys.path.insert(0, "/home/claude-dev/AegisSight-Monitor/src") from fastapi import APIRouter, Depends, HTTPException, status @@ -298,7 +298,7 @@ async def add_discovered_sources( existing_urls.add(feed["url"]) added += 1 - # Web-Source für die Domain anlegen wenn noch nicht vorhanden + # Web-Source für die Domain anlegen wenn noch nicht vorhanden if feeds and feeds[0].get("domain"): domain = feeds[0]["domain"] cursor = await db.execute( @@ -319,7 +319,7 @@ async def add_discovered_sources( -# --- Health-Check & Vorschläge --- +# --- Health-Check & Vorschläge --- @router.get("/health") async def get_health( @@ -327,7 +327,7 @@ async def get_health( db: aiosqlite.Connection = Depends(db_dependency), ): """Health-Check-Ergebnisse abrufen.""" - # Prüfen ob Tabelle existiert + # Prüfen ob Tabelle existiert cursor = await db.execute( "SELECT name FROM sqlite_master WHERE type='table' AND name='source_health_checks'" ) @@ -369,7 +369,7 @@ async def get_suggestions( admin: dict = Depends(get_current_admin), db: aiosqlite.Connection = Depends(db_dependency), ): - """Alle Vorschläge abrufen (pending zuerst, dann letzte 20 bearbeitete).""" + """Alle Vorschläge abrufen (pending zuerst, dann letzte 20 bearbeitete).""" cursor = await db.execute( "SELECT name FROM sqlite_master WHERE type='table' AND name='source_suggestions'" ) @@ -432,7 +432,7 @@ async def update_suggestion( "SELECT id FROM sources WHERE url = ? AND tenant_id IS NULL", (url,) ) if await cursor.fetchone(): - result_action = "übersprungen (URL bereits vorhanden)" + result_action = "übersprungen (URL bereits vorhanden)" new_status = "rejected" else: await db.execute( @@ -442,7 +442,7 @@ async def update_suggestion( ) result_action = f"Quelle '{name}' angelegt" else: - result_action = "übersprungen (keine URL)" + result_action = "übersprungen (keine URL)" new_status = "rejected" elif stype == "deactivate_source": @@ -455,7 +455,7 @@ async def update_suggestion( source_id = suggestion["source_id"] if source_id: await db.execute("DELETE FROM sources WHERE id = ?", (source_id,)) - result_action = "Quelle gelöscht" + result_action = "Quelle gelöscht" elif stype == "fix_url": source_id = suggestion["source_id"] @@ -465,7 +465,7 @@ async def update_suggestion( result_action = f"URL aktualisiert" # Auto-Reject: Wenn fix_url oder add_source akzeptiert wird, - # zugehörige deactivate_source-Vorschläge automatisch ablehnen + # zugehörige deactivate_source-Vorschläge automatisch ablehnen if stype in ("fix_url", "add_source") and suggestion.get("source_id"): await db.execute( "UPDATE source_suggestions SET status = 'rejected', reviewed_at = CURRENT_TIMESTAMP " @@ -640,7 +640,7 @@ async def run_health_check_stream( # Stale + Duplikate (schnell, kein Fortschritt noetig) for source in sources: - if source["source_type"] == "excluded": + if source["source_type"] in ("excluded", "web_source"): continue article_count = source.get("article_count") or 0 if article_count == 0: @@ -697,7 +697,7 @@ async def search_fix_for_source( admin: dict = Depends(get_current_admin), db: aiosqlite.Connection = Depends(db_dependency), ): - """Sonnet mit WebSearch nach Lösung für eine kaputte Quelle suchen lassen.""" + """Sonnet mit WebSearch nach Lösung für eine kaputte Quelle suchen lassen.""" import json as _json cursor = await db.execute( @@ -710,7 +710,7 @@ async def search_fix_for_source( source = dict(source) - # Health-Check-Probleme für diese Quelle laden + # Health-Check-Probleme für diese Quelle laden cursor = await db.execute( "SELECT check_type, status, message FROM source_health_checks WHERE source_id = ?", (source_id,), @@ -729,14 +729,14 @@ Kategorie: {source['category']} Probleme: {issues_text} -Aufgabe: Suche im Internet nach funktionierenden Alternativen für diese Quelle. -- Finde konkrete RSS-Feed-URLs die tatsächlich funktionieren -- Prüfe ob es alternative Zugangswege gibt (andere Subdomains, Feed-Aggregatoren, alternative URLs) -- Gibt es eine Lösung oder ist die Quelle nur noch per WebSearch erreichbar? +Aufgabe: Suche im Internet nach funktionierenden Alternativen für diese Quelle. +- Finde konkrete RSS-Feed-URLs die tatsächlich funktionieren +- Prüfe ob es alternative Zugangswege gibt (andere Subdomains, Feed-Aggregatoren, alternative URLs) +- Gibt es eine Lösung oder ist die Quelle nur noch per WebSearch erreichbar? Regeln: -- Maximal 3 Lösungen vorschlagen (die besten) -- Verwende echte deutsche Umlaute (ü, ä, ö, ß), keine Umschreibungen (ue, ae, oe, ss) +- Maximal 3 Lösungen vorschlagen (die besten) +- Verwende echte deutsche Umlaute (ü, ä, ö, ß), keine Umschreibungen (ue, ae, oe, ss) Antworte NUR mit einem JSON-Objekt: {{ @@ -746,10 +746,10 @@ Antworte NUR mit einem JSON-Objekt: "type": "replace_url|add_feed|deactivate", "name": "Anzeigename", "url": "https://...", - "description": "Kurze Begründung" + "description": "Kurze Begründung" }} ], - "summary": "Zusammenfassung in 1-2 Sätzen" + "summary": "Zusammenfassung in 1-2 Sätzen" }} Nur das JSON, kein anderer Text.""" @@ -767,7 +767,7 @@ Nur das JSON, kein anderer Text.""" else: result = {"fixable": False, "solutions": [], "summary": response[:500]} - # Lösungen als Vorschläge speichern + # Lösungen als Vorschläge speichern await db.executescript(""" CREATE TABLE IF NOT EXISTS source_suggestions ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -793,10 +793,10 @@ Nur das JSON, kein anderer Text.""" title = f"{source['name']}: {sol.get('description', sol_type)[:120]}" - # Duplikat-Check + # Duplikat-Check: gleicher Typ + gleiche Quelle bereits pending? cursor = await db.execute( - "SELECT id FROM source_suggestions WHERE title = ? AND status = 'pending'", - (title,), + "SELECT id FROM source_suggestions WHERE suggestion_type = ? AND source_id = ? AND status = 'pending'", + (suggestion_type, source_id), ) if await cursor.fetchone(): continue