Files
horror/backend/tests/test_ki.py
2026-09-17 19:10:10 +02:00

116 lines
4.2 KiB
Python

"""KI-Suche: Antwort des Modells lesen, Titel bei TMDB bestätigen."""
from app import ki, main
def test_parsen_zieht_json_aus_geschwaetz():
text = (
"<think>Der Nutzer mag ruhige Filme.</think>\n"
"Hier meine Vorschläge:\n"
'{"filme": [{"titel": "The Witch", "jahr": 2015, "grund": "Langsam, düster."},'
' {"titel": "", "jahr": 1, "grund": "leer"},'
' {"titel": "Lamb", "jahr": "2021"}]}\nViel Spaß!'
)
assert ki.parsen(text) == [
{"titel": "The Witch", "jahr": 2015, "grund": "Langsam, düster."},
{"titel": "Lamb", "jahr": 2021, "grund": ""},
]
def test_parsen_bei_muell_leer():
assert ki.parsen("Keine Ahnung.") == []
assert ki.parsen('{"filme": "nix"}') == []
assert ki.parsen("{kaputt") == []
def test_prompt_nennt_sammlung_und_gesehenes():
text = ki.prompt("blutig", ["Alien (1979)"], ["Nobody (2021)"])
assert "Gesucht: blutig" in text
assert "- Alien (1979)" in text
assert "- Nobody (2021)" in text
# Ohne Beschreibung soll die Sammlung den Ton angeben
assert "zu dieser Sammlung passt" in ki.prompt("", ["Alien (1979)"], [])
def test_vorgaben_aus_der_leiste():
zeilen = ki.vorgaben(
{"include": ["Horror", "Thriller"], "exclude": ["Komödie"],
"jahr_min": 2010, "note_min": 6.5, "dauer_max": 120, "stimmen_min": None}
)
assert zeilen == [
"Genre: Horror, Thriller",
"Auf keinen Fall: Komödie",
"Ab 2010",
"Mindestens 6.5 von 10 auf TMDB",
"Höchstens 120 Minuten",
]
assert ki.vorgaben({"jahr_min": 1980, "jahr_max": 1989}) == ["Zwischen 1980 und 1989"]
assert ki.vorgaben({}) == []
assert "unbedingt einhalten" in ki.prompt("x", [], [], {"include": ["Horror"]})
def test_route_fragt_und_loest_auf(client, film, monkeypatch):
aufrufe = {}
async def fragen(beschreibung, sammlung, gesehen, filter_):
aufrufe.update(
beschreibung=beschreibung, sammlung=sammlung, gesehen=gesehen, filter=filter_
)
return [{"titel": "The Witch", "jahr": 2015, "grund": "Passt."}]
async def aufloesen(vorschlaege, filter_, ausser=()):
aufrufe["ausser"] = set(ausser)
return [{"id": 310131, "title": "The Witch", "grund": v["grund"]} for v in vorschlaege]
monkeypatch.setattr(main.ki, "fragen", fragen)
monkeypatch.setattr(main.ki, "aufloesen", aufloesen)
# Ein Film in der Sammlung, einer gesehen
client.post("/api/wishlist", json={"movie_id": film(1, "Alien")})
client.post("/api/watched", json={"movie_id": film(2)})
antwort = client.post(
"/api/ki-suche",
json={"beschreibung": " Folk-Horror ", "mit_sammlung": True,
"include": "Horror,Mystery", "jahr_min": 2010},
)
assert antwort.status_code == 200, antwort.text
assert antwort.json()[0]["grund"] == "Passt."
assert aufrufe["beschreibung"] == "Folk-Horror"
assert aufrufe["sammlung"] == ["Alien"]
assert len(aufrufe["gesehen"]) == 1
assert aufrufe["ausser"] == {film(2)}
assert aufrufe["filter"]["include"] == ["Horror", "Mystery"]
assert aufrufe["filter"]["jahr_min"] == 2010
assert aufrufe["filter"]["note_max"] is None
# Gesehene dürfen auch drinbleiben — dann zeigt die Karte es an
client.post("/api/ki-suche", json={"beschreibung": "x", "ohne_gesehene": False})
assert aufrufe["ausser"] == set()
def test_nur_filter_reichen_als_frage(client, monkeypatch):
async def fragen(beschreibung, sammlung, gesehen, filter_):
return []
async def aufloesen(vorschlaege, filter_, ausser=()):
return []
monkeypatch.setattr(main.ki, "fragen", fragen)
monkeypatch.setattr(main.ki, "aufloesen", aufloesen)
assert client.post("/api/ki-suche", json={"include": "Horror"}).status_code == 200
def test_route_ohne_beschreibung_und_sammlung(client):
assert client.post("/api/ki-suche", json={"beschreibung": " "}).status_code == 400
def test_route_wenn_die_ki_schweigt(client, monkeypatch):
import httpx
async def fragen(*_):
raise httpx.ConnectError("weg")
monkeypatch.setattr(main.ki, "fragen", fragen)
assert client.post("/api/ki-suche", json={"beschreibung": "x"}).status_code == 502