mirror of
https://github.com/Jeuners/astra-vision.git
synced 2026-09-09 15:02:35 +02:00
Neues Werkzeug read_news, gleiche Trennung wie ComfyUI: - astra/feeds.py: kuratierte deutsche Feed-Liste nach Thema (tech, nachrichten, wirtschaft) — 11 Feeds, alle live gegen die echten Endpunkte verifiziert (heise, Golem, t3n, netzpolitik.org, tagesschau.de, Zeit Online, Spiegel, SZ, Handelsblatt, WiWo, manager magazin). - astra/rss.py: async Feed-Client (feedparser), holt Feeds eines Themas parallel ab, überspringt einzelne nicht erreichbare Feeds statt komplett zu scheitern. - astra/tools.py: read_news als natives Ollama-Tool, gleiches tool_start/tool_result/tool_error-UI-Muster wie generate_image. Mit zwei Tools gleichzeitig verfügbar sank die Zuverlässigkeit des lokalen 9.7B-Modells spürbar (0/8 Tool-Aufrufe mit dem ursprünglichen, langen System-Prompt) — reproduzierbar isoliert über direkte Ollama-Requests. Ursache: Instruction-Dilution bei mehreren Tool-Regeln in einem langen Prompt. Behoben durch gestrafften, Tool-Regeln-zuerst-Prompt und Temperatur 0.6→0.4: Bildgenerierung bleibt ~100% zuverlässig, Nachrichten-Tool bei ~60–75% je nach Formulierung. Per echtem Browser-Test mit synthetisierter Sprache verifiziert: echte aktuelle Schlagzeilen erscheinen im Transkript. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVgSHNHdRx3UNTBodFmhRA
91 lines
2.8 KiB
Python
91 lines
2.8 KiB
Python
import httpx
|
|
import pytest
|
|
|
|
import astra.rss as rss_module
|
|
from astra.rss import RSSError, read_topic
|
|
|
|
SAMPLE_RSS = b"""<?xml version="1.0"?>
|
|
<rss version="2.0"><channel>
|
|
<title>Test Feed</title>
|
|
<item><title>Erste Meldung</title><description><p>Kurzer Text</p></description><link>https://example.com/1</link></item>
|
|
<item><title>Zweite Meldung</title><description>Noch mehr Text</description><link>https://example.com/2</link></item>
|
|
</channel></rss>"""
|
|
|
|
|
|
def _patched_client(monkeypatch, handler):
|
|
real_async_client = httpx.AsyncClient
|
|
|
|
def factory(*args, **kwargs):
|
|
kwargs["transport"] = httpx.MockTransport(handler)
|
|
return real_async_client(**kwargs)
|
|
|
|
monkeypatch.setattr(httpx, "AsyncClient", factory)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_topic_combines_entries_from_all_feeds(monkeypatch):
|
|
monkeypatch.setitem(
|
|
rss_module.FEEDS,
|
|
"testtopic",
|
|
(
|
|
{"name": "Feed A", "url": "https://feed-a.example/rss"},
|
|
{"name": "Feed B", "url": "https://feed-b.example/rss"},
|
|
),
|
|
)
|
|
|
|
def handler(request: httpx.Request) -> httpx.Response:
|
|
return httpx.Response(200, content=SAMPLE_RSS)
|
|
|
|
_patched_client(monkeypatch, handler)
|
|
entries = await read_topic("testtopic")
|
|
|
|
assert len(entries) == 4
|
|
assert entries[0].title == "Erste Meldung"
|
|
assert entries[0].summary == "Kurzer Text"
|
|
assert entries[0].link == "https://example.com/1"
|
|
assert entries[0].source in ("Feed A", "Feed B")
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_topic_skips_unreachable_feeds(monkeypatch):
|
|
monkeypatch.setitem(
|
|
rss_module.FEEDS,
|
|
"testtopic",
|
|
(
|
|
{"name": "Down", "url": "https://down.example/rss"},
|
|
{"name": "Up", "url": "https://up.example/rss"},
|
|
),
|
|
)
|
|
|
|
def handler(request: httpx.Request) -> httpx.Response:
|
|
if "down" in str(request.url):
|
|
raise httpx.ConnectError("refused", request=request)
|
|
return httpx.Response(200, content=SAMPLE_RSS)
|
|
|
|
_patched_client(monkeypatch, handler)
|
|
entries = await read_topic("testtopic")
|
|
|
|
assert len(entries) == 2
|
|
assert all(entry.source == "Up" for entry in entries)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_topic_raises_for_unknown_topic():
|
|
with pytest.raises(RSSError):
|
|
await read_topic("does-not-exist")
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_topic_raises_when_every_feed_fails(monkeypatch):
|
|
monkeypatch.setitem(
|
|
rss_module.FEEDS,
|
|
"testtopic",
|
|
({"name": "Down", "url": "https://down.example/rss"},),
|
|
)
|
|
|
|
def handler(request: httpx.Request) -> httpx.Response:
|
|
raise httpx.ConnectError("refused", request=request)
|
|
|
|
_patched_client(monkeypatch, handler)
|
|
with pytest.raises(RSSError):
|
|
await read_topic("testtopic")
|