File size: 6,695 Bytes
778278c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
from __future__ import annotations

from hydradeck.core.types import ExtractedFact, Source
from hydradeck.render import (
    build_slide_frames_from_sections,
    build_slide_frames_from_report,
    enforce_slide_density,
    render_beamer_frames,
    render_paper,
    render_report_structured,
)


def test_render_paper_converts_markdown_like_body() -> None:
    sources = [Source(url="https://example.com", title="Example", snippet="snippet")]
    facts = [
        ExtractedFact(
            claim="Claim A",
            evidence="Evidence A",
            url="https://example.com",
            title="Example",
        )
    ]
    body = """## Heading
- bullet 1
- bullet 2
`inline`
```python
print('x')
```
"""

    tex = render_paper(
        topic="demo",
        outline=["背景", "创新"],
        body=body,
        facts=facts,
        sources=sources,
    )

    assert "```" not in tex
    assert "## Heading" not in tex
    assert "Heading" in tex
    assert "\\begin{itemize}" in tex
    assert "bullet 1" in tex
    assert "\\section*{1. Introduction and Background}" in tex


def test_render_templates_use_facts_not_generic_filler() -> None:
    sources = [Source(url="https://example.com", title="Example", snippet="snippet")]
    facts = [
        ExtractedFact(
            claim="RynnBrain released checkpoints on 2026-02-09",
            evidence="project timeline from official repo",
            url="https://example.com",
            title="Example",
        ),
        ExtractedFact(
            claim="Model introduces interleaved reasoning with spatial grounding",
            evidence="technical report description",
            url="https://example.com",
            title="Example",
        ),
    ]
    paper = render_paper(
        topic="demo",
        outline=["背景", "创新", "架构"],
        body="结论段落 [1]",
        facts=facts,
        sources=sources,
    )
    section_blocks = [
        {"name": "背景", "latex": facts[0].claim},
        {"name": "创新", "latex": facts[1].claim},
    ]
    frames = build_slide_frames_from_sections(section_blocks, language="en")
    slides = render_beamer_frames("demo", frames, language="en")

    assert "released checkpoints" in paper
    assert "interleaved reasoning" in paper
    assert "released checkpoints" in slides
    assert "interleaved reasoning" in slides
    section_one = paper.split("\\section*{1. Introduction and Background}", 1)[1]
    section_one = section_one.split("\\section*{2. Logical Outline}", 1)[0]
    assert "\\begin{itemize}" not in section_one


def test_render_beamer_from_report_derives_outline() -> None:
    paper = (
        "\\documentclass{article}\n"
        "\\begin{document}\n"
        "\\section*{Executive Summary}\nAlpha beta gamma.\n\n"
        "\\section*{Methodology}\nMethod details.\n\n"
        "\\section*{Results}\nResult details.\n"
        "\\end{document}\n"
    )
    frames = build_slide_frames_from_report(paper, language="en")
    slides = render_beamer_frames("demo", frames, language="en")
    assert "\\begin{frame}{Agenda}" in slides
    assert "Executive Summary" in slides
    assert "Methodology" in slides


def test_render_beamer_frames_limits_density() -> None:
    report = (
        "\\documentclass{article}\\begin{document}"
        "\\section*{Overview} A long sentence about architecture and implementation details repeated."
        " Another long sentence about evaluation metrics and reproducibility details."
        "\\section*{Results} Multiple findings with evidence and quantitative metrics."
        "\\end{document}"
    )
    frames = build_slide_frames_from_report(report, language="en")
    assert len(frames) >= 2
    tex = render_beamer_frames("demo", frames, language="en")
    assert "\\begin{frame}{Agenda}" in tex
    assert "\\begin{itemize}" in tex


def test_render_report_structured_zh_uses_ctex() -> None:
    section_blocks = [
        {"name": "方法", "latex": "本节给出方法细节与参数说明。"},
        {"name": "结果", "latex": "本节给出结果与证据。"},
    ]
    tex = render_report_structured("中文研究报告", section_blocks, language="zh")
    assert "\\documentclass[11pt]{ctexart}" in tex
    assert "本研究报告聚焦可追溯证据" not in tex
    assert "建议定期刷新证据并进行复跑验证" not in tex
    assert "\\section*{方法}" in tex


def test_render_beamer_frames_zh_uses_ctexbeamer() -> None:
    frames = [
        build_slide_frames_from_report(
            "\\documentclass{ctexart}\\begin{document}\\section*{结果}关键结果一。关键结果二。\\end{document}",
            language="zh",
        )[0]
    ]
    tex = render_beamer_frames("中文主题", frames, language="zh")
    assert "\\documentclass[aspectratio=169]{ctexbeamer}" in tex
    assert "\\begin{frame}{目录}" in tex


def test_build_slide_frames_from_sections_splits_long_section() -> None:
    section_blocks = [
        {
            "name": "Results",
            "latex": (
                "The first finding shows strong improvement in consistency and precision. "
                "The second finding shows stronger robustness under distribution shift. "
                "The third finding indicates cost-performance improvement. "
                "The fourth finding confirms stability across runs. "
                "The fifth finding highlights limitations and guardrails."
            ),
        }
    ]
    frames = build_slide_frames_from_sections(section_blocks, language="en")
    assert len(frames) >= 2


def test_render_report_structured_removes_bracket_refs() -> None:
    section_blocks = [
        {"name": "Evidence", "latex": "Claim [1] with support [2] and \\cite{src1}."}
    ]
    tex = render_report_structured("demo", section_blocks, language="en")
    assert "[1]" not in tex
    assert "[2]" not in tex
    assert "\\cite{" not in tex


def test_enforce_slide_density_splits_large_bullet_groups() -> None:
    frames = [
        {
            "title": "Results",
            "bullets": [
                "point one with enough words to be valid",
                "point two with enough words to be valid",
                "point three with enough words to be valid",
                "point four with enough words to be valid",
                "point five with enough words to be valid",
            ],
        }
    ]
    from hydradeck.render import SlideFrame

    fr = [SlideFrame(title=x["title"], bullets=x["bullets"]) for x in frames]
    out = enforce_slide_density(fr, language="en", max_bullets_per_frame=4)
    assert len(out) == 2
    assert out[0].title == "Results"
    assert "(cont.)" in out[1].title