From 3d270f60d3a987cf36336c98f9e61d7f5d96f83e Mon Sep 17 00:00:00 2001 From: Claude Dev Date: Tue, 24 Mar 2026 13:27:17 +0100 Subject: [PATCH] Globe-Ingest: Neuer Endpoint POST /api/public/globe-ingest Nimmt externe Ereignisse (EONET, USGS) als Artikel in eine Lage auf. Duplikat-Check per Headline. Locations direkt mit Koordinaten. --- src/routers/public_api.py | 67 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/routers/public_api.py b/src/routers/public_api.py index a30b2b6..917d93e 100644 --- a/src/routers/public_api.py +++ b/src/routers/public_api.py @@ -162,6 +162,73 @@ async def get_lagebild(db=Depends(db_dependency)): + + +@router.post("/globe-ingest", dependencies=[Depends(verify_api_key)]) +async def globe_ingest( + request: Request, + db=Depends(db_dependency), +): + """Nimmt externe Ereignisse (EONET, USGS) als Artikel in eine Lage auf.""" + import json as _json + body = await request.json() + incident_id = body.get("incident_id") + events = body.get("events", []) + + if not incident_id or not events: + raise HTTPException(status_code=400, detail="incident_id und events erforderlich") + + # Pruefen ob Lage existiert + cursor = await db.execute("SELECT id FROM incidents WHERE id = ?", (incident_id,)) + if not await cursor.fetchone(): + raise HTTPException(status_code=404, detail="Lage nicht gefunden") + + inserted = 0 + for evt in events[:50]: # Max 50 pro Call + headline = evt.get("title", "")[:500] + if not headline: + continue + + # Duplikat-Check per Headline + Lage + cursor = await db.execute( + "SELECT id FROM articles WHERE incident_id = ? AND headline = ? LIMIT 1", + (incident_id, headline), + ) + if await cursor.fetchone(): + continue + + source = evt.get("source", "Globe GEOINT") + source_url = evt.get("url", "") + content = evt.get("description", "") + lat = evt.get("lat") + lon = evt.get("lon") + category = evt.get("category", "primary") + + await db.execute( + """INSERT INTO articles (incident_id, headline, headline_de, source, source_url, + content_original, language, collected_at, verification_status) + VALUES (?, ?, ?, ?, ?, ?, 'de', datetime('now'), 'pending')""", + (incident_id, headline, headline, source, source_url, content), + ) + article_id = (await db.execute("SELECT last_insert_rowid()")).fetchone() + article_id = (await article_id)[0] if article_id else None + + # Location direkt einfuegen wenn Koordinaten vorhanden + if article_id and lat and lon: + await db.execute( + """INSERT INTO article_locations + (article_id, incident_id, location_name, location_name_normalized, + latitude, longitude, confidence, category) + VALUES (?, ?, ?, ?, ?, ?, 0.9, ?)""", + (article_id, incident_id, evt.get("location", headline[:50]), + evt.get("location", headline[:50]).lower(), lat, lon, category), + ) + + inserted += 1 + + await db.commit() + return {"ok": True, "inserted": inserted, "total_sent": len(events)} + @router.get("/globe-feed", dependencies=[Depends(verify_api_key)]) async def get_globe_feed( incident_id: int = None,