Dateien
AegisSight-Monitor/src/config.py
Claude Code 9c50439785 feat(x): X (Twitter) als Bezugsquelle pro Lage
X-Accounts werden analog zu Telegram als Quelle (source_type=x_account)
konfiguriert und pro Lage ueber include_x zugeschaltet. Der Scraper
(feeds/x_parser.py, twscrape) liest Account-Timelines, optional ueber
einen HTTP-Proxy mit Fallback auf direkten Abruf ueber die Server-IP.

- DB-Migration include_x, Pydantic-Modelle, incidents-Router
- Orchestrator-X-Pipeline plus Haiku-Account-Vorselektion
- sources-Router /x/validate, x_account-Typ in Stats und Frontend
- Lage-Einstellungen: X-Toggle neben international und Telegram
- twscrape als Abhaengigkeit

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 06:52:19 +00:00

119 Zeilen
5.7 KiB
Python

"""Konfiguration für den OSINT Lagemonitor."""
import os
from zoneinfo import ZoneInfo
# Zeitzone für alle Anwendungs-Timestamps (DB, Logs, UI)
TIMEZONE = ZoneInfo("Europe/Berlin")
# Pfade
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATA_DIR = os.path.join(BASE_DIR, "data")
LOG_DIR = os.path.join(BASE_DIR, "logs")
STATIC_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "static")
DB_PATH = os.environ.get("DB_PATH") or os.path.join(DATA_DIR, "osint.db")
# JWT
_JWT_SECRET = os.environ.get("JWT_SECRET", "")
def get_jwt_secret() -> str:
"""Gibt JWT_SECRET zurück. Wirft RuntimeError wenn nicht gesetzt."""
if not _JWT_SECRET:
raise RuntimeError("JWT_SECRET Umgebungsvariable muss gesetzt sein")
return _JWT_SECRET
# Rückwärtskompatibel für direkte Imports
JWT_SECRET = _JWT_SECRET
JWT_ALGORITHM = "HS256"
JWT_EXPIRE_HOURS = 24
# Claude CLI
CLAUDE_PATH = os.environ.get("CLAUDE_PATH", "/usr/bin/claude")
CLAUDE_TIMEOUT = 1800 # Sekunden (30 Min - Lage-Updates mit vielen Artikeln brauchen mehr Zeit)
# Claude Modelle
CLAUDE_MODEL_FAST = "claude-haiku-4-5-20251001" # Für einfache Aufgaben (Feed-Selektion)
CLAUDE_MODEL_MEDIUM = "claude-sonnet-4-6" # Für qualitätskritische Aufgaben (Netzwerkanalyse)
CLAUDE_MODEL_STANDARD = "claude-opus-4-7" # Standard-Opus für Recherche, Analyse, Faktencheck
# Ausgabesprache wird pro Organisation gesteuert -- siehe services/org_settings.py
# (organization_settings-Tabelle, Key 'output_language', Werte 'de' | 'en').
# Default-Fallback in den Agent-Methoden ist 'Deutsch', sodass Calls ohne
# explizite Org-Bindung weiterhin deutsch produzieren.
# Dev-Modus: ausfuehrliches Logging (DEBUG-Level, HTTP-Request-Log)
# In Kundenversion auf False setzen oder Env-Variable entfernen
DEV_MODE = os.environ.get("DEV_MODE", "true").lower() == "true"
# Feature-Flag: Translator-Agent (Haiku) komplett deaktivieren.
# False = keine Uebersetzungen mehr, fremdsprachige Artikel bleiben unuebersetzt.
TRANSLATOR_ENABLED = os.environ.get("TRANSLATOR_ENABLED", "true").lower() == "true"
# RSS-Feeds (Fallback, primär aus DB geladen)
RSS_FEEDS = {
"deutsch": [
{"name": "tagesschau", "url": "https://www.tagesschau.de/index~rss2.xml"},
{"name": "ZDF heute", "url": "https://www.zdf.de/rss/zdf/nachrichten"},
{"name": "Spiegel", "url": "https://www.spiegel.de/schlagzeilen/index.rss"},
{"name": "Zeit", "url": "https://newsfeed.zeit.de/index"},
{"name": "FAZ", "url": "https://www.faz.net/rss/aktuell/"},
{"name": "Süddeutsche", "url": "https://rss.sueddeutsche.de/rss/Topthemen"},
{"name": "NZZ", "url": "https://www.nzz.ch/recent.rss"},
{"name": "Deutsche Welle", "url": "https://rss.dw.com/rdf/rss-de-all"},
],
"international": [
{"name": "Reuters", "url": "https://www.reutersagency.com/feed/"},
{"name": "AP News", "url": "https://rsshub.app/apnews/topics/apf-topnews"},
{"name": "BBC World", "url": "https://feeds.bbci.co.uk/news/world/rss.xml"},
{"name": "Al Jazeera", "url": "https://www.aljazeera.com/xml/rss/all.xml"},
{"name": "France24", "url": "https://www.france24.com/en/rss"},
],
"behoerden": [
{"name": "BMI", "url": "https://www.bmi.bund.de/SiteGlobals/Functions/RSSFeed/BMI/RSSNewsfeed/RSSNewsfeed_Nachrichten.xml"},
{"name": "Europol", "url": "https://www.europol.europa.eu/rss.xml"},
],
}
# Ausgeschlossene Quellen (Fallback, primär aus DB geladen)
EXCLUDED_SOURCES = ["bild.de", "bild", "twitter", "x.com", "facebook", "instagram", "tiktok", "reddit"]
# SMTP (E-Mail-Versand für Magic Links und Einladungen)
SMTP_HOST = os.environ.get("SMTP_HOST", "")
SMTP_PORT = int(os.environ.get("SMTP_PORT", "587"))
SMTP_USER = os.environ.get("SMTP_USER", "")
SMTP_PASSWORD = os.environ.get("SMTP_PASSWORD", "")
SMTP_FROM_EMAIL = os.environ.get("SMTP_FROM_EMAIL", "noreply@aegis-sight.de")
SMTP_FROM_NAME = os.environ.get("SMTP_FROM_NAME", "AegisSight Monitor")
SMTP_USE_TLS = os.environ.get("SMTP_USE_TLS", "true").lower() == "true"
# Quellenvielfalt: Domain-Begrenzungen
MAX_FEEDS_PER_DOMAIN = 3 # Max. Feeds pro Domain bei Feed-Selektion
MAX_ARTICLES_PER_DOMAIN_RSS = 10 # Max. Artikel pro Domain nach RSS-Fetch
# Magic Link
MAGIC_LINK_EXPIRE_MINUTES = 10
MAGIC_LINK_BASE_URL = os.environ.get("MAGIC_LINK_BASE_URL", "https://monitor.aegis-sight.de")
# Telegram (Telethon)
TELEGRAM_API_ID = int(os.environ.get("TELEGRAM_API_ID", "0"))
TELEGRAM_API_HASH = os.environ.get("TELEGRAM_API_HASH", "")
TELEGRAM_SESSION_PATH = os.environ.get("TELEGRAM_SESSION_PATH", "/home/claude-dev/.telegram/telegram_session")
# X / Twitter (twscrape) -- siehe feeds/x_parser.py
# Scraper liest Account-Timelines konfigurierter X-Quellen (source_type='x_account').
X_SCRAPER_ENABLED = os.environ.get("X_SCRAPER_ENABLED", "true").lower() == "true"
# twscrape-Account-Store (SQLite). Liegt ausserhalb des Repos.
X_ACCOUNTS_DB_PATH = os.environ.get("X_ACCOUNTS_DB_PATH", "/home/claude-dev/.x-scraper/accounts.db")
# HTTP-Proxy fuer den X-Egress (tinyproxy am RUTX11 ueber WireGuard).
# Leer = direkter Abruf ueber die Server-IP. Bei gesetztem Wert prueft der
# Parser den Proxy vor jedem Lauf und faellt bei Ausfall auf direkt zurueck.
X_PROXY_URL = os.environ.get("X_PROXY_URL", "")
# Max. Posts pro Account-Timeline und Recency-Fenster in Tagen.
X_POST_CAP_PER_ACCOUNT = int(os.environ.get("X_POST_CAP_PER_ACCOUNT", "40"))
X_RECENCY_DAYS = int(os.environ.get("X_RECENCY_DAYS", "14"))
# Health-Check (genutzt von services/source_health.py)
HEALTH_CHECK_USER_AGENT = os.environ.get(
"HEALTH_CHECK_USER_AGENT",
"Mozilla/5.0 (compatible; AegisSight-HealthCheck/1.0)",
)
HEALTH_CHECK_TIMEOUT_S = float(os.environ.get("HEALTH_CHECK_TIMEOUT_S", "15.0"))