Files
horror/backend/tests/test_ki.py
2026-09-18 23:47:25 +02:00

147 lines
5.7 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_lange_begruendung_endet_am_komma():
kurz = "Wieder rätselt eine Familie um einen Mord, mit Witz."
assert ki.kuerzen(kurz) == kurz
lang = (
"Zwei chaotische Ermittler stolpern durch einen Fall voller Wendungen, "
"schräger Figuren und schlagfertiger Sprüche im Los Angeles der Siebziger."
)
gekuerzt = ki.kuerzen(lang)
assert gekuerzt == "Zwei chaotische Ermittler stolpern durch einen Fall voller Wendungen …"
assert len(gekuerzt) <= ki.MAX_GRUND + 2
# Ohne Komma bricht es am letzten Wort
ohne = "Wort " * 30
assert ki.kuerzen(ohne).endswith("Wort …") and len(ki.kuerzen(ohne)) <= ki.MAX_GRUND + 2
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"]})
assert "Nenne genau 30 Filme" in ki.system(30)
assert "38 Originaltitel" in ki.system(30)
assert '{"merkmale"' in ki.system(12)
def test_titel_muss_zum_treffer_passen():
assert ki._aehnlich("Clue", {"title": "Alle Mörder sind schon da", "original_title": "Clue"})
assert ki._aehnlich("The Hateful 8", {"title": "The Hateful 8", "original_title": "The Hateful Eight"})
assert ki._aehnlich("Murder by Death", {"title": "Eine Leiche zum Dessert", "original_title": "Murder by Death"})
assert not ki._aehnlich(
"The Afterparty",
{"title": "Fate: The Winx Saga - Die Afterparty", "original_title": "Fate: The Winx Saga - The Afterparty"},
)
def test_route_fragt_und_loest_auf(client, film, monkeypatch):
aufrufe = {}
async def fragen(beschreibung, sammlung, gesehen, filter_, anzahl):
aufrufe.update(
beschreibung=beschreibung, sammlung=sammlung, gesehen=gesehen, filter=filter_, anzahl=anzahl
)
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
assert aufrufe["anzahl"] == 12
client.post("/api/ki-suche", json={"beschreibung": "x", "limit": 40})
assert aufrufe["anzahl"] == 40
# 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_, anzahl):
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