File size: 2,906 Bytes
2407511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Environment-gated local demo sample manifest and safe file lookup."""

from __future__ import annotations

import os
import re
from pathlib import Path
from typing import Optional

from .models import DemoManifest, DemoSampleFile, DemoWorkflow, InputMode, Modality


DEMO_DIR = (Path(__file__).resolve().parent / "demo_samples").resolve()
_SAFE_NAME = re.compile(r"[a-z0-9][a-z0-9_-]*\.(png|tif|tiff|jpg|jpeg)")


def demo_enabled() -> bool:
    return os.getenv("SATQUERY_DEMO_MODE", "false").strip().lower() in {"1", "true", "yes", "on"}


def _file(role: str, name: str, mime: str) -> DemoSampleFile:
    return DemoSampleFile(
        role=role,
        filename=name,
        url=f"/api/agent/demo/files/{name}",
        mime_type=mime,
    )


def demo_manifest() -> DemoManifest:
    if not demo_enabled():
        return DemoManifest(enabled=False, workflows=[])
    workflows = [
        DemoWorkflow(
            id="single_vqa",
            title="Single-image understanding",
            description="Approved local optical sample with visible water-, vegetation-, and structure-support patterns.",
            input_mode=InputMode.SINGLE,
            primary_modality=Modality.OPTICAL,
            query="Is a water body visible?",
            files=[_file("primary", "single-optical.png", "image/png")],
        ),
        DemoWorkflow(
            id="change_vqa",
            title="Bi-temporal change analysis",
            description="Approved local before/after pair containing one measurable changed region.",
            input_mode=InputMode.BI_TEMPORAL,
            primary_modality=Modality.OPTICAL,
            secondary_modality=Modality.OPTICAL,
            query="How much of the image changed?",
            primary_date="2025-01-01",
            secondary_date="2025-02-01",
            files=[
                _file("primary", "change-before.png", "image/png"),
                _file("secondary", "change-after.png", "image/png"),
            ],
        ),
        DemoWorkflow(
            id="cross_modal",
            title="Optical–SAR joint analysis",
            description="Approved local exactly aligned GeoTIFF pair with real deterministic fusion evidence.",
            input_mode=InputMode.CROSS_MODAL,
            primary_modality=Modality.OPTICAL,
            secondary_modality=Modality.SAR,
            query="Where do both modalities agree?",
            files=[
                _file("primary", "cross-optical.tif", "image/tiff"),
                _file("secondary", "cross-sar.tif", "image/tiff"),
            ],
        ),
    ]
    return DemoManifest(enabled=True, workflows=workflows)


def demo_sample_path(name: str) -> Optional[Path]:
    if not demo_enabled() or not _SAFE_NAME.fullmatch(name):
        return None
    path = (DEMO_DIR / name).resolve()
    if path.parent != DEMO_DIR or not path.is_file():
        return None
    return path