Bump version to v1.5.3

This commit is contained in:
Oliver 2025-07-11 09:44:31 +02:00
parent c49864c4aa
commit 4eaef89be8
No known key found for this signature in database
10 changed files with 3098 additions and 19 deletions

View file

@ -1,3 +1,36 @@
## [v1.5.3] - 2025-07-11
### ✨ Neue Funktionen
- Automatischer Volltextabruf bei zu kurzen Artikeln (< 50 Wörter)
- Inhalte werden direkt von der Originalseite geladen (ähnlich wie bei der Bildextraktion)
- Promobil, Camping-News und andere gängige WordPress-Seiten werden unterstützt
- Neue Verwaltungsseite `Feed-Verwaltung` unter `pages/01_feed_manager.py`
- RSS-Feeds können nun über eine dedizierte Oberfläche hinzugefügt, bearbeitet und gelöscht werden
- Anzahl verknüpfter Artikel pro Feed wird angezeigt
- Änderungen werden protokolliert und per `st.rerun()` sofort sichtbar
### 🔧 Verbesserungen
- Feed-Filter in der Artikelübersicht zeigt jetzt die **korrekten Feed-Namen mit Artikelanzahl**
- Beispiel: „Promobil News (12)“ statt nur „Alle (20)“
- Basierend auf `source`-Feld im Artikelobjekt
- Verbesserte Logging-Ausgaben bei Feed-Aktionen (hinzufügen, ändern, löschen)
### 📁 Neue Dateien
- `utils/article_extractor.py` Logik zum Abrufen vollständiger Artikeltexte von Originalseiten
- `pages/01_feed_manager.py` Eigenständige Verwaltungsseite für RSS-Feeds
### 🛠 Interne Änderungen
- `main.py` erweitert: Automatischer Fallback auf `extract_full_article()` bei zu kurzem Text
- Logging konsolidiert und mit Feed-Aktionen ergänzt
## [v1.5.2] - 2025-07-09
- Fehlerbehandlung bei `CHANGELOG.md`-Doppelungen hinzugefügt

View file

@ -1 +1 @@
VERSION = "1.5.2"
VERSION = "1.5.3"

30
app.py
View file

@ -1,3 +1,5 @@
# app.py (aktualisiert mit Feed-Dropdown)
import streamlit as st
from datetime import datetime
from main import (
@ -10,6 +12,7 @@ from main import (
)
from utils.dalle_generator import generate_dalle_image
import os
from collections import Counter
st.set_page_config(page_title="📰 RSS Artikel Manager", layout="wide")
st.title("📰 RSS Artikel Manager")
@ -20,7 +23,7 @@ feeds = load_feeds()
new_feed = st.sidebar.text_input("Neuen RSS Feed hinzufügen")
if st.sidebar.button("Feed hinzufügen"):
if new_feed and new_feed not in [f.get("url", f) for f in feeds]:
feeds.append({"url": new_feed})
feeds.append({"url": new_feed, "name": "Neuer Feed"})
save_feeds(feeds)
st.sidebar.success("Feed hinzugefügt")
@ -39,8 +42,28 @@ status_filter = st.selectbox("Status filtern", ["Alle", "New", "Rewrite", "Proce
all_articles = load_articles()
articles = all_articles
if status_filter != "Alle":
articles = [a for a in all_articles if a.get("status") == status_filter]
articles = [a for a in articles if a.get("status") == status_filter]
# === Feed-Filter ===
source_to_name = {f.get("url"): f.get("name", "unidentified") for f in feeds}
source_counter = Counter([a.get("source", "unidentified") for a in articles])
feed_options = ["Alle ({})".format(len(articles))]
feed_map = {}
for source, count in source_counter.items():
name = source_to_name.get(source, "unidentified")
label = f"{name} ({count})"
feed_options.append(label)
feed_map[label] = source
selected_feed_label = st.selectbox("Feed-Auswahl", feed_options)
if selected_feed_label != feed_options[0]: # nicht „Alle“
selected_source = feed_map[selected_feed_label]
articles = [a for a in articles if a.get("source", "unidentified") == selected_source]
# === Artikel-Tabelle ===
if articles:
@ -80,7 +103,6 @@ if articles:
new_status = st.selectbox("", status_options, index=status_options.index(current_status), key=f"status_{article['id']}")
if new_status != current_status:
article["status"] = new_status
# Speichern in vollständiger Artikelliste
for idx, art in enumerate(all_articles):
if art["id"] == article["id"]:
all_articles[idx] = article
@ -107,7 +129,6 @@ if articles:
img["caption"] = caption or "Kein Bildtitel vorhanden"
img["copyright"] = copyright or "Unbekannt"
img["copyright_url"] = copyright_url or "#"
# Speichern in vollständiger Artikelliste
for idx, art in enumerate(all_articles):
if art["id"] == article["id"]:
all_articles[idx] = article
@ -138,6 +159,5 @@ if articles:
st.error("Fehler beim Erzeugen des Bildes.")
else:
st.info("Ein KI-generiertes Bild ist bereits vorhanden.")
else:
st.info("Keine Artikel für den gewählten Status gefunden.")

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,14 @@
[
"https://www.camping-news.de/rss/"
{
"url": "https://www.camping-news.de/rss/",
"name": "Camping News"
},
{
"url": "https://www.promobil.de/rss/news",
"name": "Promobil News"
},
{
"url": "https://www.promobil.de/rss/ratgeber",
"name": "Promobil Ratgeber"
}
]

View file

@ -140,3 +140,81 @@
2025-07-08 10:38:57,857 - INFO - 🧠 Generiere DALL·E-Bild für Prompt: Das weltweit größte Caravaning-Erlebnis
2025-07-08 10:39:16,622 - INFO - HTTP Request: POST https://api.openai.com/v1/images/generations "HTTP/1.1 200 OK"
2025-07-08 10:39:16,627 - INFO - ✅ Bild generiert: https://oaidalleapiprodscus.blob.core.windows.net/private/org-YimPc01cYtOXjUpCATUqDABw/user-eA31w0vmy3fOrb3G64Ygndsr/img-6d1irbwhkDKGNvLJG50pYaZK.png?st=2025-07-08T07%3A39%3A16Z&se=2025-07-08T09%3A39%3A16Z&sp=r&sv=2024-08-04&sr=b&rscd=inline&rsct=image/png&skoid=cc612491-d948-4d2e-9821-2683df3719f5&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-07-07T20%3A35%3A26Z&ske=2025-07-08T20%3A35%3A26Z&sks=b&skv=2024-08-04&sig=DVMzSGr162NqN8830eX0tAH5Wtm5NAnTPxk2C7NQgTs%3D
2025-07-11 08:22:15,359 - INFO - Lade Feed: https://www.camping-news.de/rss/
2025-07-11 08:22:15,648 - INFO - 0 neue Artikel gefunden in https://www.camping-news.de/rss/
2025-07-11 08:22:15,649 - INFO - Keine neuen Artikel gefunden.
2025-07-11 08:29:26,863 - INFO - Lade Feed: https://www.camping-news.de/rss/
2025-07-11 08:29:27,225 - INFO - 0 neue Artikel gefunden in https://www.camping-news.de/rss/
2025-07-11 08:29:27,225 - INFO - Lade Feed: https://www.promobil.de/rss/news
2025-07-11 08:29:27,464 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/termine-veranstaltungen-juni-juli/
2025-07-11 08:29:27,618 - INFO - 13 Bilder gefunden bei https://www.promobil.de/termine-veranstaltungen-juni-juli/
2025-07-11 08:29:27,618 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/sicherheitszubehoer-wohnmobil-schutz-einbruch-diebstahl-gase/
2025-07-11 08:29:27,782 - INFO - 22 Bilder gefunden bei https://www.promobil.de/sicherheitszubehoer-wohnmobil-schutz-einbruch-diebstahl-gase/
2025-07-11 08:29:27,783 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/corigon-neue-hymer-marke-sommer-2025/
2025-07-11 08:29:27,984 - INFO - 23 Bilder gefunden bei https://www.promobil.de/corigon-neue-hymer-marke-sommer-2025/
2025-07-11 08:29:27,985 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/sieger-frosch-campfire-der-ideen-2025/
2025-07-11 08:29:28,132 - INFO - 21 Bilder gefunden bei https://www.promobil.de/sieger-frosch-campfire-der-ideen-2025/
2025-07-11 08:29:28,132 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/fiat-ducato-9-gang-automatik-softwareupdate/
2025-07-11 08:29:28,279 - INFO - 13 Bilder gefunden bei https://www.promobil.de/fiat-ducato-9-gang-automatik-softwareupdate/
2025-07-11 08:29:28,280 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/caravaning-jahrgangs-archiv-als-pdf-download/
2025-07-11 08:29:28,422 - INFO - 14 Bilder gefunden bei https://www.promobil.de/caravaning-jahrgangs-archiv-als-pdf-download/
2025-07-11 08:29:28,422 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/top-10-clever-campen-videos-2024/
2025-07-11 08:29:28,572 - INFO - 14 Bilder gefunden bei https://www.promobil.de/top-10-clever-campen-videos-2024/
2025-07-11 08:29:28,572 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/retro-wohnmobile-2004-nuller-jahre-rueckblick-promobil/
2025-07-11 08:29:28,761 - INFO - 25 Bilder gefunden bei https://www.promobil.de/retro-wohnmobile-2004-nuller-jahre-rueckblick-promobil/
2025-07-11 08:29:28,761 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/gaswarner-wohnmobil-schutz-gas/
2025-07-11 08:29:28,945 - INFO - 33 Bilder gefunden bei https://www.promobil.de/gaswarner-wohnmobil-schutz-gas/
2025-07-11 08:29:28,946 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/versicherungen-werden-2025-teuerer-tipps-und-tricks-um-die-kosten-zu-senken/
2025-07-11 08:29:29,104 - INFO - 13 Bilder gefunden bei https://www.promobil.de/versicherungen-werden-2025-teuerer-tipps-und-tricks-um-die-kosten-zu-senken/
2025-07-11 08:29:29,105 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/dailycamper-trekking-mini-camper-fiat-doblo/
2025-07-11 08:29:29,257 - INFO - 15 Bilder gefunden bei https://www.promobil.de/dailycamper-trekking-mini-camper-fiat-doblo/
2025-07-11 08:29:29,257 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/rocket-ryzon-campingbus-von-extrem-sportler-jonas-deichmann/
2025-07-11 08:29:29,436 - INFO - 24 Bilder gefunden bei https://www.promobil.de/rocket-ryzon-campingbus-von-extrem-sportler-jonas-deichmann/
2025-07-11 08:29:29,436 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/e-trailer-system-kontrollboard-wohnwagen-camper/
2025-07-11 08:29:29,593 - INFO - 16 Bilder gefunden bei https://www.promobil.de/e-trailer-system-kontrollboard-wohnwagen-camper/
2025-07-11 08:29:29,593 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/spielorte-em-2024-red-bull-arena-leipzig/
2025-07-11 08:29:29,786 - INFO - 19 Bilder gefunden bei https://www.promobil.de/spielorte-em-2024-red-bull-arena-leipzig/
2025-07-11 08:29:29,786 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/can-kasim-dogan-interview-westfalia/
2025-07-11 08:29:29,934 - INFO - 13 Bilder gefunden bei https://www.promobil.de/can-kasim-dogan-interview-westfalia/
2025-07-11 08:29:29,934 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/promobil-leser-meinung-mobilitaet-fortbewegungsmittel-fahrrad/
2025-07-11 08:29:30,103 - INFO - 22 Bilder gefunden bei https://www.promobil.de/promobil-leser-meinung-mobilitaet-fortbewegungsmittel-fahrrad/
2025-07-11 08:29:30,103 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/spielorte-em-2024-frankfurt/
2025-07-11 08:29:30,276 - INFO - 18 Bilder gefunden bei https://www.promobil.de/spielorte-em-2024-frankfurt/
2025-07-11 08:29:30,276 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/stuttgart-em-2024-fussball-stellplaetze-wohnmobil-camping/
2025-07-11 08:29:30,450 - INFO - 18 Bilder gefunden bei https://www.promobil.de/stuttgart-em-2024-fussball-stellplaetze-wohnmobil-camping/
2025-07-11 08:29:30,451 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/camper-radio-radiosender-caravan-fm/
2025-07-11 08:29:30,600 - INFO - 13 Bilder gefunden bei https://www.promobil.de/camper-radio-radiosender-caravan-fm/
2025-07-11 08:29:30,600 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/tourismus-management-armin-brysch-interview-virtuelle-reisen/
2025-07-11 08:29:30,750 - INFO - 13 Bilder gefunden bei https://www.promobil.de/tourismus-management-armin-brysch-interview-virtuelle-reisen/
2025-07-11 08:29:30,750 - INFO - 20 neue Artikel gefunden in https://www.promobil.de/rss/news
2025-07-11 08:29:30,759 - INFO - 20 neue Artikel gespeichert.
2025-07-11 08:34:46,453 - INFO - ✍️ Umschreiben von: Schutz vor Einbruch und Diebstahl fürs Wohnmobil: Wie schütze ich mein Wohnmobil vor Diebstahl?
2025-07-11 08:34:50,280 - INFO - HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
2025-07-11 08:34:51,815 - INFO - HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
2025-07-11 08:34:51,819 - INFO - ✅ Artikel umgeschrieben: Schutz vor Einbruch und Diebstahl fürs Wohnmobil: Wie schütze ich mein Wohnmobil vor Diebstahl?
2025-07-11 08:34:51,819 - INFO - ✍️ Umschreiben von: Gaswarner im Wohnmobil: So schütze Sie sich vor unsichtbaren Gasen
2025-07-11 08:34:57,346 - INFO - HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
2025-07-11 08:34:59,085 - INFO - HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
2025-07-11 08:34:59,087 - INFO - ✅ Artikel umgeschrieben: Gaswarner im Wohnmobil: So schütze Sie sich vor unsichtbaren Gasen
2025-07-11 08:34:59,087 - INFO - ✍️ Umschreiben von: Camper-Radio Caravan.fm : Radiosender speziell für Camping-Fans
2025-07-11 08:35:05,071 - INFO - HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
2025-07-11 08:35:07,789 - INFO - HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
2025-07-11 08:35:07,792 - INFO - ✅ Artikel umgeschrieben: Camper-Radio Caravan.fm : Radiosender speziell für Camping-Fans
2025-07-11 08:35:07,803 - INFO - Alle Artikel mit Status 'Rewrite' wurden verarbeitet.
2025-07-11 08:54:52,549 - INFO - Lade Feed: https://www.camping-news.de/rss/
2025-07-11 08:54:53,036 - INFO - 0 neue Artikel gefunden in https://www.camping-news.de/rss/
2025-07-11 08:54:53,036 - INFO - Lade Feed: https://www.promobil.de/rss/news
2025-07-11 08:54:53,402 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/termine-veranstaltungen-juni-juli/
2025-07-11 08:54:53,558 - INFO - 13 Bilder gefunden bei https://www.promobil.de/termine-veranstaltungen-juni-juli/
2025-07-11 08:54:53,731 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/sicherheitszubehoer-wohnmobil-schutz-einbruch-diebstahl-gase/
2025-07-11 08:54:53,908 - INFO - 22 Bilder gefunden bei https://www.promobil.de/sicherheitszubehoer-wohnmobil-schutz-einbruch-diebstahl-gase/
2025-07-11 08:54:54,076 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/fiat-ducato-9-gang-automatik-softwareupdate/
2025-07-11 08:54:54,217 - INFO - 13 Bilder gefunden bei https://www.promobil.de/fiat-ducato-9-gang-automatik-softwareupdate/
2025-07-11 08:54:54,376 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/versicherungen-werden-2025-teuerer-tipps-und-tricks-um-die-kosten-zu-senken/
2025-07-11 08:54:54,537 - INFO - 13 Bilder gefunden bei https://www.promobil.de/versicherungen-werden-2025-teuerer-tipps-und-tricks-um-die-kosten-zu-senken/
2025-07-11 08:54:54,682 - INFO - 📷 Extrahiere Bilder von https://www.promobil.de/camper-radio-radiosender-caravan-fm/
2025-07-11 08:54:54,826 - INFO - 13 Bilder gefunden bei https://www.promobil.de/camper-radio-radiosender-caravan-fm/
2025-07-11 08:54:54,826 - INFO - 5 neue Artikel gefunden in https://www.promobil.de/rss/news
2025-07-11 08:54:54,834 - INFO - 5 neue Artikel gespeichert.
2025-07-11 09:34:42,951 - INFO - ❌ Feed gelöscht: Promobil Ratgeber (https://www.promobil.de/rss/ratgeber)
2025-07-11 09:35:05,863 - INFO - 🔗 Neuer Feed hinzugefügt: Promobil Ratgeber (https://www.promobil.de/rss/ratgeber)

12
main.py
View file

@ -7,8 +7,9 @@ from bs4 import BeautifulSoup
from datetime import datetime
from dotenv import load_dotenv
import logging
from utils.image_extractor import extract_images_with_metadata
import openai
from utils.image_extractor import extract_images_with_metadata
from utils.article_extractor import extract_full_article
load_dotenv()
@ -75,6 +76,12 @@ def fetch_and_process_feed(feed_url, existing_ids):
soup = BeautifulSoup(content, "html.parser")
clean_text = soup.get_text(" ", strip=True)
# Automatischer Volltext-Fetch bei zu wenig Wörtern
if len(clean_text.split()) < 50 and entry.get("link"):
fetched_text = extract_full_article(entry["link"])
if len(fetched_text.split()) > len(clean_text.split()):
clean_text = fetched_text
images = extract_images_with_metadata(entry.link)
new_articles.append({
@ -86,7 +93,8 @@ def fetch_and_process_feed(feed_url, existing_ids):
"tags": [],
"status": "New",
"link": entry.get("link", ""),
"images": images
"images": images,
"source": feed_url
})
return new_articles

71
pages/01_feed_manager.py Normal file
View file

@ -0,0 +1,71 @@
# pages/01_feed_manager.py
import streamlit as st
from main import load_feeds, save_feeds, load_articles
import logging
# === Logging vorbereiten ===
log_dir = "logs"
log_file = f"{log_dir}/rss_tool.log"
logging.basicConfig(
filename=log_file,
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
st.set_page_config(page_title="📡 Feed-Verwaltung")
st.title("📡 RSS Feed-Verwaltung")
feeds = load_feeds()
articles = load_articles()
# === Neuen Feed hinzufügen ===
st.subheader(" Neuen Feed hinzufügen")
with st.form("add_feed_form"):
new_url = st.text_input("Feed URL", "")
new_name = st.text_input("Feed Name", "")
submitted = st.form_submit_button("Feed hinzufügen")
if submitted:
if new_url and new_name:
if not any(f.get("url") == new_url for f in feeds):
feeds.append({"url": new_url, "name": new_name})
save_feeds(feeds)
logging.info(f"🔗 Neuer Feed hinzugefügt: {new_name} ({new_url})")
st.success(f"Feed '{new_name}' hinzugefügt.")
st.rerun()
else:
st.warning("⚠️ Dieser Feed existiert bereits.")
else:
st.error("❌ Bitte gib sowohl URL als auch Name ein.")
# === Bestehende Feeds bearbeiten ===
st.subheader("🛠️ Vorhandene Feeds bearbeiten oder löschen")
for idx, feed in enumerate(feeds):
with st.expander(f"🔗 {feed.get('name')}"):
url = st.text_input(f"Feed-URL {idx}", value=feed.get("url"), key=f"url_{idx}")
name = st.text_input(f"Feed-Name {idx}", value=feed.get("name"), key=f"name_{idx}")
count = sum(1 for a in articles if a.get("source") == feed.get("url"))
col1, col2 = st.columns(2)
with col1:
if st.button("💾 Änderungen speichern", key=f"save_{idx}"):
old_url, old_name = feed.get("url"), feed.get("name")
feeds[idx]["url"] = url
feeds[idx]["name"] = name
save_feeds(feeds)
logging.info(f"✏️ Feed geändert: '{old_name}' ({old_url}) → '{name}' ({url})")
st.success("Änderungen gespeichert.")
st.rerun()
with col2:
if st.button("🗑️ Feed löschen", key=f"delete_{idx}"):
deleted_feed = feeds.pop(idx)
save_feeds(feeds)
logging.info(f"❌ Feed gelöscht: {deleted_feed.get('name')} ({deleted_feed.get('url')})")
st.warning("Feed gelöscht.")
st.rerun()
st.caption(f"📰 Verknüpfte Artikel: {count}")

View file

@ -0,0 +1,27 @@
# utils/article_extractor.py
import requests
from bs4 import BeautifulSoup
def extract_full_article(url: str) -> str:
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
# Promobil & WordPress & allgemeine Fallbacks
candidates = [
{"tag": "div", "class_": "article__text"}, # Promobil
{"tag": "div", "class_": "entry-content"}, # WordPress Standard
{"tag": "article", "class_": None}, # Generisch
]
for selector in candidates:
el = soup.find(selector["tag"], class_=selector["class_"])
if el and len(el.get_text(strip=True).split()) > 50:
return el.get_text(" ", strip=True)
# Fallback: ganzer Seiteninhalt
return soup.get_text(" ", strip=True)
except Exception:
return ""

23
utils/article_utils.py Normal file
View file

@ -0,0 +1,23 @@
# utils/article_utils.py
import hashlib
def clean_text(text: str) -> str:
return text.strip()
def generate_id(link: str) -> str:
return hashlib.md5(link.encode("utf-8")).hexdigest()
def categorize_article(text: str) -> str:
# Dummy-Kategorie
return "Allgemein"
def tag_article(text: str) -> list:
# Dummy-Tags
return ["tag1", "tag2"]
def summarize_text(text: str) -> str:
return text[:200] + "..."
def rewrite_text(text: str) -> str:
return text # Platzhalter, z.B. für GPT-Rewrite später