File size: 4,049 Bytes
6ca3b92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f415181
9685699
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
from types import SimpleNamespace

from app.services import learn_lesson_builder


def test_mock_provider_builds_a_cached_reading_lesson_without_external_calls(
    monkeypatch, tmp_path
) -> None:
    monkeypatch.setattr(
        learn_lesson_builder,
        "get_settings",
        lambda: SimpleNamespace(ai_provider="mock"),
    )
    monkeypatch.setattr(learn_lesson_builder, "PUBLIC_ROOT", tmp_path)
    monkeypatch.setattr(
        learn_lesson_builder,
        "generate_lesson_script",
        lambda **_kwargs: (_ for _ in ()).throw(AssertionError("Groq should not run")),
    )
    monkeypatch.setattr(
        learn_lesson_builder,
        "synthesize_beats",
        lambda *_args, **_kwargs: (_ for _ in ()).throw(
            AssertionError("TTS should not run")
        ),
    )

    manifest = learn_lesson_builder.build_lesson(
        topic="Python programming",
        lesson_title="Python Programming",
        level="beginner",
    )

    assert manifest["deliveryMode"] == "reading"
    assert manifest["isFallback"] is True
    assert "Local preview" in manifest["deliveryNotice"]
    assert len(manifest["beats"]) >= 6
    assert all(beat["audio_src"] == "" for beat in manifest["beats"])
    assert "variables" in str(manifest).lower()
    assert (tmp_path / "unowned" / manifest["lessonHash"] / "lesson.json").exists()


def test_provider_timeout_returns_bounded_reading_lesson(monkeypatch, tmp_path) -> None:
    monkeypatch.setattr(
        learn_lesson_builder,
        "get_settings",
        lambda: SimpleNamespace(ai_provider="sarvam"),
    )
    monkeypatch.setattr(learn_lesson_builder, "PUBLIC_ROOT", tmp_path)
    monkeypatch.setattr(learn_lesson_builder, "_lesson_sync_tts_enabled", lambda: False)
    monkeypatch.setattr(learn_lesson_builder, "_lesson_generation_budget_seconds", lambda: 1.0)
    monkeypatch.setattr(
        learn_lesson_builder,
        "_script_llm_providers",
        lambda: [{"name": "test", "call": lambda _prompt: (_ for _ in ()).throw(TimeoutError())}],
    )
    monkeypatch.setattr(
        learn_lesson_builder,
        "synthesize_beats",
        lambda *_args, **_kwargs: (_ for _ in ()).throw(AssertionError("TTS must not run")),
    )

    manifest = learn_lesson_builder.build_lesson(
        topic="Basic Python for data analysis",
        lesson_title="Python foundations",
        level="beginner",
    )

    assert manifest["deliveryMode"] == "reading"
    assert manifest["isFallback"] is True
    assert "reading" in manifest["deliveryNotice"].lower()
    assert manifest["beats"]


def test_authored_lesson_can_return_reading_mode_without_audio(monkeypatch, tmp_path) -> None:
    monkeypatch.setattr(
        learn_lesson_builder,
        "get_settings",
        lambda: SimpleNamespace(ai_provider="sarvam"),
    )
    monkeypatch.setattr(learn_lesson_builder, "PUBLIC_ROOT", tmp_path)
    monkeypatch.setattr(learn_lesson_builder, "_lesson_sync_tts_enabled", lambda: False)
    monkeypatch.setattr(
        learn_lesson_builder,
        "generate_lesson_script",
        lambda **_kwargs: {
            "lesson_title": "Authored lesson",
            "summary": "A real authored reading class.",
            "objectives": ["Explain the idea"],
            "beats": [
                {
                    "kind": "explain",
                    "narration": "This is a complete authored explanation that a student can read and study without waiting for a voice asset.",
                    "board_heading": "Core idea",
                    "board_lines": ["Reason first"],
                }
            ],
            "notes": ["A useful note."],
            "flashcards": [{"front": "What matters?", "back": "The reason."}],
        },
    )

    manifest = learn_lesson_builder.build_lesson(
        topic="A real topic",
        lesson_title="Authored lesson",
        level="beginner",
    )

    assert manifest["deliveryMode"] == "reading"
    assert manifest["summary"] == "A real authored reading class."
    assert manifest["beats"][0]["audio_src"] == ""