refactor(klassifikation): Klassifikation aus Monitor entfernt — Pflege jetzt in der Verwaltung

Endpoints unter /api/sources/classification/* weg, Service-Module (source_classifier, external_reputation) gelöscht. Quellen-Modal verliert Tab Klassifikations-Review, Klassifikations-Section in der Edit-Form, alle Bulk-Buttons (Sync, Klassifikation starten, Bulk-Approve). API-Methoden in api.js entfernt, alignment-Helper raus, saveSource entschlackt.

Read-Only bleibt: Filter-Dropdowns über der Quellenliste (Politik, Medientyp, Reliability, Externe Reputation, Alignment) und Inline-Badges (_renderClassificationBadges + Label-Maps in components.js). Kunde sieht nur freigegebene Werte.

GET /api/sources liefert weiter Klassifikations-Felder + alignments für die Anzeige; SourceCreate/SourceUpdate akzeptieren keine Klassifikations-Felder mehr.

Bulk-Klassifikations-Skripte entfernt — Pflege läuft über Verwaltungs-UI.
Dieser Commit ist enthalten in:
Claude Code
2026-05-09 22:01:20 +00:00
Ursprung 5f053a3eca
Commit b90e47ff3f
10 geänderte Dateien mit 6150 neuen und 7831 gelöschten Zeilen

Datei anzeigen

@@ -1,64 +0,0 @@
"""Einmalige LLM-Klassifikation aller noch unklassifizierten Quellen.
Verwendung:
python3 scripts/migrate_sources_classification.py --limit 50
python3 scripts/migrate_sources_classification.py --limit 500 # Alle
python3 scripts/migrate_sources_classification.py --recheck-pending # bereits Pending neu
Schreibt Vorschlaege in proposed_*-Spalten. Approval erfolgt anschliessend
ueber das Verwaltungs-UI / API (POST /api/sources/{id}/classification/approve).
"""
import argparse
import asyncio
import logging
import sys
from pathlib import Path
# src/ in PYTHONPATH aufnehmen, wenn Skript direkt aufgerufen wird
HERE = Path(__file__).resolve().parent
SRC = HERE.parent / "src"
if str(SRC) not in sys.path:
sys.path.insert(0, str(SRC))
from database import get_db # noqa: E402
from services.source_classifier import bulk_classify # noqa: E402
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
)
logger = logging.getLogger("migrate_sources")
async def main():
parser = argparse.ArgumentParser(description="LLM-Klassifikation aller Quellen.")
parser.add_argument("--limit", type=int, default=50, help="Max. Quellen pro Lauf")
parser.add_argument(
"--recheck-pending",
action="store_true",
help="Auch Quellen mit classification_source='llm_pending' neu klassifizieren",
)
args = parser.parse_args()
db = await get_db()
try:
result = await bulk_classify(
db,
limit=args.limit,
only_unclassified=not args.recheck_pending,
)
finally:
await db.close()
print(f"Verarbeitet: {result['processed']}")
print(f"Erfolgreich: {result['success']}")
print(f"Fehler: {len(result['errors'])}")
print(f"Kosten: ${result['total_cost_usd']:.4f}")
if result["errors"]:
print("\nFehler-Details:")
for e in result["errors"][:10]:
print(f" source_id={e['source_id']}: {e['error']}")
if __name__ == "__main__":
asyncio.run(main())