"""KI-Suche: Antwort des Modells lesen, Titel bei TMDB bestätigen.""" from app import ki, main def test_parsen_zieht_json_aus_geschwaetz(): text = ( "Der Nutzer mag ruhige Filme.\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"]}) 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_): 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