fix(rewrite): make image upload non-fatal and add rewrite tracing logs

- wordpress.py: catch image download/upload failures and skip image
  instead of aborting the entire WP draft update
- pipeline.py: add INFO logs at each step of _do_rewrite_and_draft
  to trace OpenAI call, tag generation, and WP API call
- telegram_bot.py: add INFO logs around rewrite execution + exc_info
  on error for full traceback in logs
- repositories.py: include scheduled_publish_at in get_article_by_id

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OliverGiertz 2026-03-26 07:45:55 +00:00
parent 12932bca90
commit 1963e32ab4
5 changed files with 42 additions and 9 deletions

View file

@ -110,7 +110,9 @@ def _do_rewrite_and_draft(article: dict[str, Any]) -> tuple[int, str | None]:
article_id = int(article["id"]) article_id = int(article["id"])
# Rewrite # Rewrite
logger.info("_do_rewrite_and_draft #%d: starte OpenAI-Rewrite", article_id)
rewritten = rewrite_article_text(article) rewritten = rewrite_article_text(article)
logger.info("_do_rewrite_and_draft #%d: Rewrite fertig (%d Wörter), generiere Tags", article_id, len(rewritten.split()))
tags: list[str] = [] tags: list[str] = []
try: try:
tags = generate_article_tags(article, rewritten_text=rewritten) tags = generate_article_tags(article, rewritten_text=rewritten)
@ -157,7 +159,9 @@ def _do_rewrite_and_draft(article: dict[str, Any]) -> tuple[int, str | None]:
raise RuntimeError(f"Artikel #{article_id} nach Rewrite nicht gefunden") raise RuntimeError(f"Artikel #{article_id} nach Rewrite nicht gefunden")
# Create WP draft # Create WP draft
logger.info("_do_rewrite_and_draft #%d: erstelle/aktualisiere WP Draft (wp_post_id=%s)", article_id, fresh.get("wp_post_id"))
wp_post_id, wp_post_url = publish_article_draft(fresh) wp_post_id, wp_post_url = publish_article_draft(fresh)
logger.info("_do_rewrite_and_draft #%d: WP Draft fertig (post_id=%s)", article_id, wp_post_id)
# Update WP info in DB # Update WP info in DB
from .repositories import mark_article_publish_result from .repositories import mark_article_publish_result

View file

@ -321,7 +321,8 @@ def get_article_by_id(article_id: int) -> dict[str, Any] | None:
a.source_name_snapshot, a.source_terms_url_snapshot, a.source_license_name_snapshot, a.source_name_snapshot, a.source_terms_url_snapshot, a.source_license_name_snapshot,
a.legal_checked, a.legal_checked_at, a.legal_note, a.legal_checked, a.legal_checked_at, a.legal_note,
a.wp_post_id, a.wp_post_url, a.publish_attempts, a.publish_last_error, a.published_to_wp_at, a.wp_post_id, a.wp_post_url, a.publish_attempts, a.publish_last_error, a.published_to_wp_at,
a.word_count, a.status, a.meta_json, a.created_at, a.updated_at a.word_count, a.status, a.meta_json, a.created_at, a.updated_at,
a.scheduled_publish_at
FROM articles a FROM articles a
WHERE a.id = ? WHERE a.id = ?
""", """,

View file

@ -435,14 +435,16 @@ def _handle_callback(callback_query: dict[str, Any]) -> None:
if action == "rewrite": if action == "rewrite":
try: try:
logger.info("Rewrite #%d: starte rewrite_and_update_draft", article_id)
_pipeline.rewrite_and_update_draft(article_id) _pipeline.rewrite_and_update_draft(article_id)
logger.info("Rewrite #%d: abgeschlossen, sende Benachrichtigung", article_id)
updated = get_article_by_id(article_id) updated = get_article_by_id(article_id)
if updated: if updated:
from .scheduler import suggest_publish_slot from .scheduler import suggest_publish_slot
slot = suggest_publish_slot() slot = suggest_publish_slot()
notify_new_draft(updated, score=_get_relevance_score(updated), suggested_publish_at=slot) notify_new_draft(updated, score=_get_relevance_score(updated), suggested_publish_at=slot)
except Exception as exc: except Exception as exc:
logger.error("Rewrite #%d fehlgeschlagen: %s", article_id, exc) logger.error("Rewrite #%d fehlgeschlagen: %s", article_id, exc, exc_info=True)
notify_error(f"Rewrite #{article_id} fehlgeschlagen: {exc}") notify_error(f"Rewrite #{article_id} fehlgeschlagen: {exc}")
elif action == "discard": elif action == "discard":

View file

@ -318,13 +318,19 @@ def publish_article_draft(article: dict[str, Any]) -> tuple[int, str | None]:
featured_media_id = None featured_media_id = None
selected_image_url = _selected_image_url_from_meta(article.get("meta_json")) selected_image_url = _selected_image_url_from_meta(article.get("meta_json"))
if selected_image_url: if selected_image_url:
featured_media_id = _upload_featured_media( try:
base_url=settings.wordpress_base_url, featured_media_id = _upload_featured_media(
auth_header=auth, base_url=settings.wordpress_base_url,
image_url=selected_image_url, auth_header=auth,
article_title=title, image_url=selected_image_url,
source_url=source_url, article_title=title,
) source_url=source_url,
)
except Exception as img_exc:
import logging
logging.getLogger(__name__).warning(
"Bild-Upload fehlgeschlagen (wird übersprungen): %s%s", selected_image_url, img_exc
)
payload = { payload = {
"title": title, "title": title,

View file

@ -18,6 +18,26 @@
3. Payload-Validation/Tag-Fehler? 3. Payload-Validation/Tag-Fehler?
4. Artikel in `pending` statt `failed` markieren, wenn unklar 4. Artikel in `pending` statt `failed` markieren, wenn unklar
## Incident: Telegram-Buttons reagieren nicht / Befehle ignoriert
**Ursache:** N8N "App Release - Telegram Bot"-Workflow hat den Webhook überschrieben.
**Prüfen:**
```bash
curl -s "https://api.telegram.org/bot8403822424:AAGp8gZoNIGZv3IIan45q7P9HfM868qzXi4/getWebhookInfo" | python3 -m json.tool
```
`url` muss auf `https://news.vanityontour.de/telegram/webhook` zeigen
`allowed_updates` muss `["message", "callback_query"]` enthalten
**Webhook zurücksetzen:**
```bash
curl -s -X POST "https://api.telegram.org/bot8403822424:AAGp8gZoNIGZv3IIan45q7P9HfM868qzXi4/setWebhook" \
-H "Content-Type: application/json" \
-d '{"url":"https://news.vanityontour.de/telegram/webhook","allowed_updates":["message","callback_query"],"secret_token":"RWWAaBwfCUX9Y573JVkB9zAeloHsZZoruXOBBgUtsvU"}'
```
Vollständige Dokumentation: `projects/webhook/telegram-webhook-reset.md`
## Backups ## Backups
- SQLite-Dump taeglich - SQLite-Dump taeglich
- Konfiguration und `.env` sicher sichern - Konfiguration und `.env` sicher sichern