File size: 4,570 Bytes
186f4a4
4079a6f
 
13a101b
 
 
4079a6f
 
186f4a4
4079a6f
 
 
 
 
 
 
 
 
 
 
13a101b
 
 
 
 
 
cd0ff97
13a101b
 
 
 
 
 
 
 
 
 
 
cd0ff97
 
13a101b
 
 
 
 
cd0ff97
 
13a101b
 
cd0ff97
13a101b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cd0ff97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186f4a4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import asyncio
import importlib
import sys
from types import SimpleNamespace

import pytest

import gradio as gr
from fastapi.responses import FileResponse


def test_start_render_api_registers_one_streamed_output() -> None:
    sys.modules.pop("app", None)
    module = importlib.import_module("app")

    with gr.Blocks() as demo:
        dependency = gr.api(module.start_render_api, api_name="start_render")

    assert dependency.get("outputs")
    assert len(dependency["outputs"]) == 1


def test_start_render_api_adds_public_audio_url_to_completed_chapters(monkeypatch) -> None:
    sys.modules.pop("app", None)
    module = importlib.import_module("app")

    class FakeSynthesisService:
        def get_job(self, session_id):
            return SimpleNamespace(status="idle")

        def render(self, **kwargs):
            yield {
                "type": "chapter_done",
                "session_id": kwargs["session_id"],
                "chapter_id": "c1",
                "duration_seconds": 12,
                "overall_progress": 0.5,
                "output_path": "/tmp/scriptorium/session-a/renders/001-c1.wav",
                "backend": "modal",
                "model": "magpie",
            }
            yield {
                "type": "completed",
                "session_id": kwargs["session_id"],
                "outputs": ["/tmp/scriptorium/session-a/renders/001-c1.wav"],
                "backend": "modal",
                "model": "magpie",
            }

    monkeypatch.setattr(module, "synthesis_service", FakeSynthesisService())
    monkeypatch.setattr(module, "_selected_book", lambda session_id, selected_ids: {"chapters": [{"id": "c1", "included": True}]})
    monkeypatch.setattr(module, "_voice_config_for_backend", lambda voice_config, session_id: voice_config)
    monkeypatch.setattr(module.store, "save_json", lambda *args, **kwargs: None)

    events = list(
        module.start_render_api(
            session_id="session-a",
            selected_chapter_ids=["c1"],
            voice_config={"mode": "auto"},
            diffusion_steps=32,
            speed=1.0,
        )
    )

    chapter_done = events[0]
    assert chapter_done["type"] == "chapter_done"
    assert chapter_done["url"] == "/files/session-a/renders/001-c1.wav"
    assert chapter_done["backend"] == "modal"
    assert chapter_done["model"] == "magpie"


def test_generate_preview_api_exposes_model_and_backend(monkeypatch) -> None:
    sys.modules.pop("app", None)
    module = importlib.import_module("app")

    class FakeSynthesisService:
        def generate_preview(self, **kwargs):
            output_path = kwargs["output_path"]
            output_path.parent.mkdir(parents=True, exist_ok=True)
            output_path.write_bytes(b"RIFFpreview")
            return {
                "duration_seconds": 6,
                "sample_rate": 24000,
                "backend": "modal",
                "model": "magpie",
            }

    monkeypatch.setattr(module, "synthesis_service", FakeSynthesisService())
    monkeypatch.setattr(
        module,
        "_book_payload",
        lambda _session_id: {"chapters": [{"id": "c1", "text": "hello world", "title": "One"}]},
    )
    monkeypatch.setattr(module, "_voice_config_for_backend", lambda voice_config, session_id: voice_config)

    payload = module.generate_preview_api(
        session_id="session-a",
        chapter_id="c1",
        voice_config={"model": "magpie", "backend": "modal", "speaker": "Sofia", "language": "en"},
        diffusion_steps=32,
        speed=1.0,
    )

    assert payload["url"] == "/files/session-a/previews/c1.wav"
    assert payload["backend"] == "modal"
    assert payload["model"] == "magpie"


def test_serve_generated_file_supports_attachment_downloads(tmp_path, monkeypatch) -> None:
    sys.modules.pop("app", None)
    module = importlib.import_module("app")

    session_root = tmp_path / "session-a"
    export_path = session_root / "exports" / "reading-room.m4a"
    export_path.parent.mkdir(parents=True, exist_ok=True)
    export_path.write_bytes(b"m4a")

    monkeypatch.setattr(module, "_session_root", lambda _session_id: session_root)

    response = asyncio.run(
        module.serve_generated_file(
            session_id="session-a",
            kind="exports",
            filename="reading-room.m4a",
            download=True,
        )
    )

    assert isinstance(response, FileResponse)
    assert "attachment" in response.headers["content-disposition"]
    assert "reading-room.m4a" in response.headers["content-disposition"]