Spaces:
Sleeping
Sleeping
| from app.schemas.graph import HTML5VisualPayload | |
| from app.services.visualization_service import VisualizationService | |
| class _CalledOrRaise: | |
| """Fake engine base: records calls, or raises if it must never be called.""" | |
| def __init__(self, marker: str, should_raise: bool = False): | |
| self.marker = marker | |
| self.should_raise = should_raise | |
| self.calls = [] | |
| def _payload(self, animation_type="2d_text"): | |
| return HTML5VisualPayload( | |
| html_code="<html></html>", | |
| animation_type=animation_type, | |
| explanation=self.marker, | |
| ) | |
| class FakeRouter: | |
| def __init__(self, decision=None): | |
| self.decision = decision | |
| self.calls = [] | |
| def classify(self, selection_text, card_markdown, chunks, familiarity): | |
| self.calls.append((selection_text, card_markdown, chunks, familiarity)) | |
| return self.decision | |
| class FakeFormula(_CalledOrRaise): | |
| def __init__(self): | |
| super().__init__("FAKE_FORMULA") | |
| def generate(self, concept, chunks, familiarity): | |
| self.calls.append((concept, chunks, familiarity)) | |
| if self.should_raise: | |
| raise AssertionError("formula engine should not have been called") | |
| return self._payload("formula") | |
| class FakeTextRef(_CalledOrRaise): | |
| def __init__(self): | |
| super().__init__("FAKE_TEXT_REF") | |
| def generate(self, concept, chunks, familiarity, web_results=None): | |
| self.calls.append((concept, chunks, familiarity, web_results)) | |
| if self.should_raise: | |
| raise AssertionError("text_ref engine should not have been called") | |
| return self._payload("2d_text") | |
| class FakeD3(_CalledOrRaise): | |
| def __init__(self): | |
| super().__init__("FAKE_D3") | |
| def generate(self, concept, chunks, familiarity): | |
| self.calls.append((concept, chunks, familiarity)) | |
| if self.should_raise: | |
| raise AssertionError("d3 engine should not have been called") | |
| return self._payload("graph") | |
| class FakeShell(_CalledOrRaise): | |
| def __init__(self): | |
| super().__init__("FAKE_SHELL") | |
| def generate(self, concept, kind, chunks, familiarity): | |
| self.calls.append((concept, kind, chunks, familiarity)) | |
| if self.should_raise: | |
| raise AssertionError("shell engine should not have been called") | |
| return self._payload(kind) | |
| def _make_service(router=None): | |
| return VisualizationService( | |
| router=router or FakeRouter(), | |
| formula=FakeFormula(), | |
| text_ref=FakeTextRef(), | |
| d3=FakeD3(), | |
| shell=FakeShell(), | |
| ) | |
| _CHUNKS = [{"source": "s", "text": "some grounded text"}] | |
| def test_generate_formula_routes_to_formula_engine(): | |
| service = _make_service() | |
| out = service.generate("E=mc^2", "formula", "graduate", chunks=_CHUNKS) | |
| assert out.explanation == "FAKE_FORMULA" | |
| assert service.formula.calls == [("E=mc^2", _CHUNKS, "graduate")] | |
| assert service.text_ref.calls == [] | |
| assert service.d3.calls == [] | |
| assert service.shell.calls == [] | |
| def test_generate_2d_text_routes_to_text_ref_engine_with_web_results(): | |
| service = _make_service() | |
| web_results = [{"title": "t", "url": "u"}] | |
| out = service.generate( | |
| "some concept", "2d_text", "graduate", chunks=_CHUNKS, web_results=web_results | |
| ) | |
| assert out.explanation == "FAKE_TEXT_REF" | |
| assert service.text_ref.calls == [("some concept", _CHUNKS, "graduate", web_results)] | |
| assert service.formula.calls == [] | |
| assert service.d3.calls == [] | |
| assert service.shell.calls == [] | |
| def test_generate_graph_routes_to_d3_engine(): | |
| service = _make_service() | |
| out = service.generate("GDP over time", "graph", "graduate", chunks=_CHUNKS) | |
| assert out.explanation == "FAKE_D3" | |
| assert service.d3.calls == [("GDP over time", _CHUNKS, "graduate")] | |
| assert service.formula.calls == [] | |
| assert service.text_ref.calls == [] | |
| assert service.shell.calls == [] | |
| def test_generate_3d_routes_to_shell_engine_with_kind_3d(): | |
| service = _make_service() | |
| out = service.generate("a molecule", "3d", "graduate", chunks=_CHUNKS) | |
| assert out.explanation == "FAKE_SHELL" | |
| assert service.shell.calls == [("a molecule", "3d", _CHUNKS, "graduate")] | |
| assert service.formula.calls == [] | |
| assert service.text_ref.calls == [] | |
| assert service.d3.calls == [] | |
| def test_generate_2d_anim_routes_to_shell_engine_with_kind_2d_anim(): | |
| service = _make_service() | |
| out = service.generate("a mechanism", "2d_anim", "graduate", chunks=_CHUNKS) | |
| assert out.explanation == "FAKE_SHELL" | |
| assert service.shell.calls == [("a mechanism", "2d_anim", _CHUNKS, "graduate")] | |
| assert service.formula.calls == [] | |
| assert service.text_ref.calls == [] | |
| assert service.d3.calls == [] | |
| def test_generate_decline_returns_decline_card_without_calling_any_engine(): | |
| service = VisualizationService( | |
| router=FakeRouter(), | |
| formula=FakeFormula(), | |
| text_ref=FakeTextRef(), | |
| d3=FakeD3(), | |
| shell=FakeShell(), | |
| ) | |
| for engine in (service.formula, service.text_ref, service.d3, service.shell): | |
| engine.should_raise = True | |
| out = service.generate("pure philosophy", "decline", "graduate", chunks=_CHUNKS) | |
| assert out.animation_type == "2d_text" | |
| assert "better discussed in chat" in out.html_code | |
| assert service.formula.calls == [] | |
| assert service.text_ref.calls == [] | |
| assert service.d3.calls == [] | |
| assert service.shell.calls == [] | |
| def test_generate_no_chunks_declines_regardless_of_modality(): | |
| for engine in (FakeFormula(), FakeTextRef(), FakeD3(), FakeShell()): | |
| engine.should_raise = True | |
| for modality in ("formula", "2d_text", "graph", "3d", "2d_anim", "decline"): | |
| service = VisualizationService( | |
| router=FakeRouter(), | |
| formula=FakeFormula(), | |
| text_ref=FakeTextRef(), | |
| d3=FakeD3(), | |
| shell=FakeShell(), | |
| ) | |
| for engine in (service.formula, service.text_ref, service.d3, service.shell): | |
| engine.should_raise = True | |
| out = service.generate("no source concept", modality, "graduate", chunks=[]) | |
| assert out.animation_type == "2d_text" | |
| assert "source grounding" in out.explanation or "better discussed in chat" in out.html_code | |
| assert service.formula.calls == [] | |
| assert service.text_ref.calls == [] | |
| assert service.d3.calls == [] | |
| assert service.shell.calls == [] | |
| # Also confirm chunks=None short-circuits the same way. | |
| service = _make_service() | |
| for engine in (service.formula, service.text_ref, service.d3, service.shell): | |
| engine.should_raise = True | |
| out = service.generate("no source concept", "formula", "graduate", chunks=None) | |
| assert out.animation_type == "2d_text" | |
| assert service.formula.calls == [] | |
| def test_classify_delegates_to_router(): | |
| from app.agents.modality_router import ModalityDecision | |
| decision = ModalityDecision(modality="formula", reasoning="has an equation") | |
| router = FakeRouter(decision=decision) | |
| service = _make_service(router=router) | |
| out = service.classify("selected text", "# card markdown", _CHUNKS, "graduate") | |
| assert out is decision | |
| assert router.calls == [("selected text", "# card markdown", _CHUNKS, "graduate")] | |