Die Pipeline liess GPT Artikel umschreiben und legte sie direkt als geplanten WordPress-Beitrag an - ohne dass ein Mensch sie gesehen hat. Der KI-Hinweis auf dem Blog sagt aber redaktionelle Pruefung zu, und genau daran haengt die Ausnahme in Art. 50 Abs. 4 KI-VO. Neuer Status `pending_review` zwischen Rewrite und Publish: Die Pipeline endet beim Rewrite, ohne WordPress-Beitrag und ohne Publish-Slot. Erst die Freigabe im Portal stempelt Pruefer und Systemzeit, reserviert den Slot und legt den Beitrag an. - Migration: editorial_review_at/_by/_note, Status-CHECK erweitert - Spalten-Migration laeuft nach den Tabellen-Neubauten erneut, sonst verwirft der aeltere no_image-Rebuild die frisch angelegten Spalten - Jeder Weg nach `approved` stempelt (Button, Statuswechsel, API) - Jeder maschinelle Rewrite loescht einen alten Stempel - Telegram: Info mit Portal-Link statt Draft-Meldung, kein Freigabe-Button - Altbestand bleibt unberuehrt und veroeffentlicht weiter - EDITORIAL_REVIEW_REQUIRED=false stellt den alten Ablauf wieder her - 14 neue Tests, docs/KI-VO.md Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
82 lines
3.7 KiB
Python
82 lines
3.7 KiB
Python
from functools import lru_cache
|
|
from pathlib import Path
|
|
|
|
from dotenv import load_dotenv
|
|
from pydantic import AliasChoices, Field
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
# Prefer backend-specific env file to avoid collisions with legacy root .env
|
|
model_config = SettingsConfigDict(
|
|
env_file=("backend/.env", ".env"),
|
|
env_file_encoding="utf-8",
|
|
extra="ignore",
|
|
)
|
|
|
|
app_env: str = "development"
|
|
app_name: str = "rss-news-backend"
|
|
app_secret_key: str = "replace-with-a-long-random-secret"
|
|
|
|
app_admin_username: str = "admin"
|
|
app_admin_password: str = "change-me"
|
|
|
|
session_cookie_name: str = "rss_news_session"
|
|
session_max_age_seconds: int = 28800
|
|
|
|
app_db_path: str = "backend/data/rss_news.db"
|
|
|
|
wordpress_base_url: str | None = Field(default=None, validation_alias=AliasChoices("WORDPRESS_BASE_URL", "WP_BASE_URL"))
|
|
wordpress_username: str | None = Field(default=None, validation_alias=AliasChoices("WORDPRESS_USERNAME", "WP_USERNAME"))
|
|
wordpress_app_password: str | None = Field(default=None, validation_alias=AliasChoices("WORDPRESS_APP_PASSWORD", "WP_PASSWORD"))
|
|
wordpress_default_status: str = "draft"
|
|
# Tag hygiene: the rewriter proposes far more tags than a post needs, and
|
|
# every unknown one used to be created on the spot - that is how 955 posts
|
|
# accumulated 3.055 tags, 1.683 of them used exactly once.
|
|
wordpress_max_tags_per_post: int = 5
|
|
wordpress_new_tag_min_proposals: int = 3
|
|
openai_api_key: str | None = Field(default=None, validation_alias=AliasChoices("OPENAI_API_KEY"))
|
|
openai_model: str = "gpt-4o-mini"
|
|
|
|
# Telegram Bot
|
|
telegram_bot_token: str | None = Field(default=None, validation_alias=AliasChoices("TELEGRAM_BOT_TOKEN"))
|
|
telegram_chat_id: str | None = Field(default=None, validation_alias=AliasChoices("TELEGRAM_CHAT_ID"))
|
|
telegram_webhook_secret: str | None = Field(default=None, validation_alias=AliasChoices("TELEGRAM_WEBHOOK_SECRET"))
|
|
|
|
# N8N API authentication
|
|
n8n_api_key: str | None = Field(default=None, validation_alias=AliasChoices("N8N_API_KEY"))
|
|
|
|
# Pipeline behaviour
|
|
pipeline_relevance_auto: int = 80 # >= this: auto-process
|
|
pipeline_relevance_warn: int = 60 # >= this: Telegram warning, else reject
|
|
pipeline_max_drafts_per_day: int = 4
|
|
pipeline_publish_hours: str = "9,12,15,18" # comma-separated preferred publish hours (CET)
|
|
pipeline_publish_start_hour: int = 9
|
|
pipeline_publish_end_hour: int = 19
|
|
pipeline_publish_min_gap_hours: int = 3
|
|
pipeline_min_words_raw: int = 120 # minimum words in raw content before rewrite (else reject)
|
|
pipeline_min_words_rewritten: int = 150 # minimum words in rewritten content (else reject)
|
|
pipeline_max_article_age_days: int = 7 # skip articles older than N days during ingestion (0 = no limit)
|
|
|
|
# Redaktionelle Freigabe (Art. 50 Abs. 4 KI-VO)
|
|
# Ist das Gate aktiv, endet die Pipeline beim Rewrite: der Artikel wartet im
|
|
# Portal auf die Freigabe durch einen Menschen. Erst danach entsteht der
|
|
# WordPress-Beitrag und der Publish-Slot. Auf False laeuft der alte,
|
|
# vollautomatische Ablauf.
|
|
editorial_review_required: bool = True
|
|
# Basis-URL des Portals fuer die Deep-Links in den Telegram-Meldungen.
|
|
portal_base_url: str = "https://news.vanityontour.de"
|
|
|
|
|
|
@lru_cache(maxsize=1)
|
|
def get_settings() -> Settings:
|
|
# Prefer shared legacy env from the original rss-news workspace if present.
|
|
env_candidates = (
|
|
Path("/Users/oliver/Documents/rss-news/.env"),
|
|
Path("backend/.env"),
|
|
Path(".env"),
|
|
)
|
|
for env_path in env_candidates:
|
|
if env_path.exists():
|
|
load_dotenv(env_path, override=False)
|
|
return Settings()
|