deploy: model-native language mirror + Shopify shop policies in the brain + cart-link fix + PDF ephemeral-disk persistence + /c hosted no-code page (migration 0025)
47a6953 verified | from __future__ import annotations | |
| from app import demo_gap | |
| from app.models import Tenant | |
| class _Chunk: | |
| pass | |
| async def test_gap_report_labels_hit_and_miss(db_session, monkeypatch): | |
| t = Tenant(slug="demo-x", name="X", brand_name="Tienda X", is_demo=True) | |
| db_session.add(t) | |
| await db_session.flush() | |
| # Deterministic retrieval: only the shipping questions are "answered" by the | |
| # store's pages (score above threshold); everything else is a gap. | |
| async def fake_search(db, q, k=3, tenant_id=None): | |
| score = 0.55 if "env" in q.lower() else 0.10 | |
| return [(_Chunk(), score)] | |
| monkeypatch.setattr(demo_gap.rag_index, "search", fake_search) | |
| rep = await demo_gap.generate_gap_report(db_session, t, lang="es") | |
| assert rep["brand"] == "Tienda X" | |
| assert rep["total"] == len(demo_gap.GAP_QUESTIONS["es"]) | |
| hits = [r for r in rep["questions"] if r["status"] == "hit"] | |
| assert hits and all("env" in r["q"].lower() for r in hits) # only shipping = HIT | |
| assert rep["answered"] == len(hits) | |
| assert rep["gap_count"] == rep["total"] - len(hits) | |
| assert all(g not in [h["q"] for h in hits] for g in rep["gaps"]) | |
| async def test_gap_report_all_miss_when_nothing_indexed(db_session, monkeypatch): | |
| t = Tenant(slug="demo-empty", is_demo=True) | |
| db_session.add(t) | |
| await db_session.flush() | |
| async def empty_search(db, q, k=3, tenant_id=None): | |
| return [] # store crawled nothing useful -> every buyer question is a gap | |
| monkeypatch.setattr(demo_gap.rag_index, "search", empty_search) | |
| rep = await demo_gap.generate_gap_report(db_session, t, lang="en") | |
| assert rep["gap_count"] == rep["total"] and rep["answered"] == 0 | |