Geoparsing-Centroid + Eigennamen in GNews-Query #35
@@ -31,6 +31,28 @@ def _get_geonamescache():
|
|||||||
return _gc
|
return _gc
|
||||||
|
|
||||||
|
|
||||||
|
# Geografische Zentren (Centroids) der Laender, keyed nach ISO-2-Code.
|
||||||
|
# Wird genutzt, wenn ein Artikel ein LAND nennt (kein konkreter Ort). Vorher
|
||||||
|
# wurde dem Land die Hauptstadt zugewiesen — das stapelte z.B. alle "Japan"-
|
||||||
|
# Marker exakt auf Tokyo und suggerierte faelschlich ein Ereignis in der
|
||||||
|
# Hauptstadt. Das Centroid liegt in der Landesmitte und ist neutral.
|
||||||
|
# Laender, die hier fehlen, fallen auf die Hauptstadt zurueck (alte Logik).
|
||||||
|
_COUNTRY_CENTROIDS = {
|
||||||
|
"AF": (33.94, 67.71), "AT": (47.52, 14.55), "AZ": (40.14, 47.58),
|
||||||
|
"CH": (46.82, 8.23), "CN": (35.86, 104.20), "CY": (35.13, 33.43),
|
||||||
|
"DE": (51.17, 10.45), "EG": (26.82, 30.80), "ES": (40.46, -3.75),
|
||||||
|
"FR": (46.23, 2.21), "GB": (54.70, -3.28), "GR": (39.07, 21.82),
|
||||||
|
"IL": (31.05, 34.85), "IN": (20.59, 78.96), "IQ": (33.22, 43.68),
|
||||||
|
"IR": (32.43, 53.69), "IT": (41.87, 12.57), "JO": (30.59, 36.24),
|
||||||
|
"JP": (36.20, 138.25), "KP": (40.34, 127.51), "KR": (35.91, 127.77),
|
||||||
|
"KW": (29.31, 47.48), "LB": (33.85, 35.86), "NL": (52.13, 5.29),
|
||||||
|
"OM": (21.47, 55.98), "PK": (30.38, 69.35), "PS": (31.95, 35.23),
|
||||||
|
"QA": (25.32, 51.18), "RU": (61.52, 105.32), "SA": (23.89, 45.08),
|
||||||
|
"SY": (34.80, 38.997), "TR": (38.96, 35.24), "UA": (48.38, 31.17),
|
||||||
|
"US": (39.83, -98.58), "YE": (15.55, 48.52), "TW": (23.80, 121.00),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Bekannte Laendernamen (deutsch/englisch/alternativ -> ISO-2 Code + Hauptstadt-Koordinaten)
|
# Bekannte Laendernamen (deutsch/englisch/alternativ -> ISO-2 Code + Hauptstadt-Koordinaten)
|
||||||
_COUNTRY_ALIASES = {
|
_COUNTRY_ALIASES = {
|
||||||
"libanon": {"code": "LB", "name": "Lebanon", "lat": 33.8938, "lon": 35.5018},
|
"libanon": {"code": "LB", "name": "Lebanon", "lat": 33.8938, "lon": 35.5018},
|
||||||
@@ -106,9 +128,12 @@ def _geocode_offline(name: str, country_code: str = "") -> Optional[dict]:
|
|||||||
# 1. Bekannte Laender-Aliase (schnellster + sicherster Pfad)
|
# 1. Bekannte Laender-Aliase (schnellster + sicherster Pfad)
|
||||||
alias = _COUNTRY_ALIASES.get(name_lower)
|
alias = _COUNTRY_ALIASES.get(name_lower)
|
||||||
if alias:
|
if alias:
|
||||||
|
# Land -> geografisches Zentrum (Centroid) statt Hauptstadt, wo bekannt.
|
||||||
|
centroid = _COUNTRY_CENTROIDS.get(alias["code"])
|
||||||
|
lat, lon = centroid if centroid else (alias["lat"], alias["lon"])
|
||||||
return {
|
return {
|
||||||
"lat": alias["lat"],
|
"lat": lat,
|
||||||
"lon": alias["lon"],
|
"lon": lon,
|
||||||
"country_code": alias["code"],
|
"country_code": alias["code"],
|
||||||
"normalized_name": alias["name"],
|
"normalized_name": alias["name"],
|
||||||
"confidence": 0.95,
|
"confidence": 0.95,
|
||||||
@@ -118,9 +143,20 @@ def _geocode_offline(name: str, country_code: str = "") -> Optional[dict]:
|
|||||||
countries = gc.get_countries()
|
countries = gc.get_countries()
|
||||||
for code, country in countries.items():
|
for code, country in countries.items():
|
||||||
if country.get("name", "").lower() == name_lower:
|
if country.get("name", "").lower() == name_lower:
|
||||||
|
# Land -> Centroid (Landesmitte), wo bekannt. Das verhindert, dass
|
||||||
|
# alle "Japan"-Marker exakt auf Tokyo gestapelt werden.
|
||||||
|
centroid = _COUNTRY_CENTROIDS.get(code)
|
||||||
|
if centroid:
|
||||||
|
return {
|
||||||
|
"lat": centroid[0],
|
||||||
|
"lon": centroid[1],
|
||||||
|
"country_code": code,
|
||||||
|
"normalized_name": country["name"],
|
||||||
|
"confidence": 0.9,
|
||||||
|
}
|
||||||
|
# Kein Centroid hinterlegt -> Fallback auf die Hauptstadt.
|
||||||
capital = country.get("capital", "")
|
capital = country.get("capital", "")
|
||||||
if capital:
|
if capital:
|
||||||
# Hauptstadt geocoden, aber als Land benennen
|
|
||||||
cap_alias = _COUNTRY_ALIASES.get(capital.lower())
|
cap_alias = _COUNTRY_ALIASES.get(capital.lower())
|
||||||
if cap_alias:
|
if cap_alias:
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -58,15 +58,36 @@ def build_news_search_feeds(
|
|||||||
locale = _GNEWS_LOCALE.get(lang_key)
|
locale = _GNEWS_LOCALE.get(lang_key)
|
||||||
if not locale:
|
if not locale:
|
||||||
continue
|
continue
|
||||||
kws = keywords_by_lang.get(lang_key) or []
|
lang_kws = [str(k).strip() for k in (keywords_by_lang.get(lang_key) or []) if str(k).strip()]
|
||||||
# Fallback: wenn fuer die Sprache keine Keywords da sind, "en" nehmen
|
en_kws = [str(k).strip() for k in (keywords_by_lang.get("en") or []) if str(k).strip()]
|
||||||
# (lateinische Eigennamen matchen auch in fremdsprachigen News-Indizes).
|
|
||||||
if not kws and lang_key != "en":
|
if lang_key == "en":
|
||||||
kws = keywords_by_lang.get("en") or []
|
query_terms = en_kws[:max_keywords]
|
||||||
kws = [str(k).strip() for k in kws if str(k).strip()]
|
else:
|
||||||
if not kws:
|
# Fuer nicht-englische Sprachen: die ersten 2 englischen Keywords
|
||||||
|
# voranstellen. Haiku ordnet Eigennamen/Akronyme (z.B. "Qilin",
|
||||||
|
# "Asahi") nach vorne — und die kommen auch in fremdsprachigen
|
||||||
|
# Artikeln lateinisch vor. Ohne das fehlt beim ersten Refresh (noch
|
||||||
|
# keine Headlines-Historie) der entscheidende Eigenname in der Query.
|
||||||
|
# Danach 3 sprach-spezifische Keywords.
|
||||||
|
query_terms = en_kws[:2] + lang_kws[:3]
|
||||||
|
# Wenn fuer die Sprache gar keine Keywords da sind: ganz auf en.
|
||||||
|
if not lang_kws:
|
||||||
|
query_terms = en_kws[:max_keywords]
|
||||||
|
|
||||||
|
# Dedup, Reihenfolge erhalten
|
||||||
|
seen_terms: set[str] = set()
|
||||||
|
deduped: list[str] = []
|
||||||
|
for t in query_terms:
|
||||||
|
tl = t.lower()
|
||||||
|
if tl in seen_terms:
|
||||||
continue
|
continue
|
||||||
query = " ".join(kws[:max_keywords])
|
seen_terms.add(tl)
|
||||||
|
deduped.append(t)
|
||||||
|
|
||||||
|
if not deduped:
|
||||||
|
continue
|
||||||
|
query = " ".join(deduped)
|
||||||
if not query or query in seen_queries:
|
if not query or query in seen_queries:
|
||||||
continue
|
continue
|
||||||
seen_queries.add(query)
|
seen_queries.add(query)
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren