Spaces:
Running
Running
| from agent.models import EducationPptxInput, SlideOutline, SlideSpec | |
| from agent.preview import outline_to_html, render_slide_images | |
| from agent.prompts import fallback_outline, outline_looks_like_schema_echo, outline_max_tokens | |
| from agent.runner import AgentRunner | |
| from agent.tools.docx import create_docx, create_html_export | |
| from agent.tools.pptx import create_pptx | |
| def test_outline_max_tokens_scales_with_slide_count(): | |
| assert outline_max_tokens(5) == 750 | |
| assert outline_max_tokens(1) == 230 | |
| assert outline_max_tokens(20) == 1024 | |
| runner = AgentRunner() | |
| raw = ( | |
| '{"title": "AI Agents", "slides": [' | |
| '{"title": "Intro", "bullets": ["What is an agent?"]},' | |
| '{"title": "Uses", "bullets": ["Automation"]}' | |
| "]}" | |
| ) | |
| outline = runner._parse_outline(raw, expected_slides=5) | |
| assert len(outline.slides) == 5 | |
| assert outline.title == "AI Agents" | |
| def test_parse_outline_trims_when_model_returns_too_many(): | |
| runner = AgentRunner() | |
| raw = ( | |
| '{"title": "Topic", "slides": [' | |
| '{"title": "A", "bullets": ["a"]},' | |
| '{"title": "B", "bullets": ["b"]},' | |
| '{"title": "C", "bullets": ["c"]},' | |
| '{"title": "D", "bullets": ["d"]}' | |
| "]}" | |
| ) | |
| outline = runner._parse_outline(raw, expected_slides=3) | |
| assert len(outline.slides) == 3 | |
| def test_extract_json_from_fenced_block(): | |
| raw = '```json\n{"title": "T", "slides": [{"title": "S", "bullets": ["a"]}]}\n```' | |
| data = AgentRunner._extract_json(raw) | |
| assert data["title"] == "T" | |
| def test_extract_json_ignores_trailing_text(): | |
| raw = ( | |
| '{"title": "AI Agents", "slides": [{"title": "Intro", "bullets": ["a"]}]}\n' | |
| "Here is a short explanation of the lesson outline." | |
| ) | |
| data = AgentRunner._extract_json(raw) | |
| assert data["title"] == "AI Agents" | |
| def test_extract_json_ignores_duplicate_object(): | |
| first = '{"title": "First", "slides": [{"title": "A", "bullets": ["a"]}]}' | |
| second = '{"title": "Second", "slides": [{"title": "B", "bullets": ["b"]}]}' | |
| data = AgentRunner._extract_json(f"{first}\n{second}") | |
| assert data["title"] == "First" | |
| def test_extract_json_empty_raises(): | |
| import pytest | |
| with pytest.raises(ValueError, match="empty output"): | |
| AgentRunner._extract_json(" ") | |
| def test_extract_json_after_thinking_block(): | |
| raw = ( | |
| "planning the lesson\n" | |
| '{"title": "Agents", "slides": [{"title": "Intro", "bullets": ["What is an agent?"]}]}' | |
| ) | |
| from inference.response_clean import strip_thinking_blocks | |
| cleaned = strip_thinking_blocks(raw) | |
| data = AgentRunner._extract_json(cleaned) | |
| assert data["title"] == "Agents" | |
| def test_parse_outline_or_error_empty(): | |
| runner = AgentRunner() | |
| outline, err = runner._parse_outline_or_error("", 5, None) | |
| assert outline is None | |
| assert "empty" in err.lower() | |
| def test_parse_outline_rejects_schema_echo(): | |
| runner = AgentRunner() | |
| raw = ( | |
| '{"title": "string β presentation title", "slides": [' | |
| '{"title": "string β slide heading", "bullets": ["string", "..."], ' | |
| '"speaker_note": "string β one sentence for the teacher"}' | |
| "]}" | |
| ) | |
| import pytest | |
| with pytest.raises(ValueError, match="schema placeholders"): | |
| runner._parse_outline(raw, expected_slides=5) | |
| def test_outline_looks_like_schema_echo(): | |
| echo = SlideOutline( | |
| title="string β presentation title", | |
| slides=[SlideSpec(title="string β slide heading", bullets=["string", "..."])], | |
| ) | |
| assert outline_looks_like_schema_echo(echo) is True | |
| real = SlideOutline( | |
| title="Small model finetuning", | |
| slides=[SlideSpec(title="What is finetuning?", bullets=["Adapting a base model"])], | |
| ) | |
| assert outline_looks_like_schema_echo(real) is False | |
| def test_fallback_outline_slide_count(): | |
| req = EducationPptxInput(topic="ai agent", grade="6", slide_count=5) | |
| outline = fallback_outline(req) | |
| assert len(outline.slides) == 5 | |
| assert "ai agent" in outline.title.lower() | |
| def test_create_pptx_writes_file(tmp_path, monkeypatch): | |
| monkeypatch.setenv("AGENT_OUTPUTS_DIR", str(tmp_path)) | |
| outline = SlideOutline( | |
| title="Photosynthesis", | |
| slides=[ | |
| SlideSpec(title="What is it?", bullets=["Plants make food", "Uses sunlight"]), | |
| SlideSpec(title="Why it matters", bullets=["Oxygen", "Food chain"]), | |
| ], | |
| ) | |
| path = create_pptx(outline, run_id="test") | |
| assert path.exists() | |
| assert path.suffix == ".pptx" | |
| def test_create_docx_writes_file(tmp_path, monkeypatch): | |
| monkeypatch.setenv("AGENT_OUTPUTS_DIR", str(tmp_path)) | |
| outline = SlideOutline( | |
| title="Photosynthesis", | |
| slides=[SlideSpec(title="Intro", bullets=["Sunlight", "Chlorophyll"])], | |
| ) | |
| path = create_docx(outline, run_id="test") | |
| assert path.exists() | |
| assert path.suffix == ".docx" | |
| def test_outline_preview_and_images(tmp_path, monkeypatch): | |
| monkeypatch.setenv("AGENT_OUTPUTS_DIR", str(tmp_path)) | |
| outline = SlideOutline( | |
| title="Water Cycle", | |
| slides=[SlideSpec(title="Evaporation", bullets=["Heat", "Vapor"])], | |
| ) | |
| html = outline_to_html(outline) | |
| assert "Water Cycle" in html | |
| assert "Evaporation" in html | |
| images = render_slide_images(outline, run_id="prev") | |
| assert len(images) == 2 | |
| assert all(p.exists() for p in images) | |
| def test_create_html_export(tmp_path, monkeypatch): | |
| monkeypatch.setenv("AGENT_OUTPUTS_DIR", str(tmp_path)) | |
| outline = SlideOutline( | |
| title="Fractions", | |
| slides=[SlideSpec(title="Parts", bullets=["Half", "Quarter"])], | |
| ) | |
| path = create_html_export(outline, run_id="html") | |
| assert path.exists() | |
| assert "Fractions" in path.read_text() | |