SM737's picture
Upload folder using huggingface_hub (part 4)
a358495 verified
Raw History Blame Contribute Delete
12.5 kB
from __future__ import annotations
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field, computed_field
class TaskType(str, Enum):
BUILDING_COUNT = "building_count"
BUILDING_CHANGE = "building_change"
MULTI_INTENT = "multi_intent"
SINGLE_VQA = "single_vqa"
GROUNDING = "grounding"
BI_TEMPORAL_CHANGE = "bi_temporal_change"
OPTICAL_SAR = "optical_sar"
SCENE_DESCRIPTION = "scene_description"
SPECTRAL_INDEX = "spectral_index"
LAND_COVER = "land_cover"
OBJECT_IDENTIFICATION = "object_identification"
VEGETATION_ANALYSIS = "vegetation_analysis"
WATER_ANALYSIS = "water_analysis"
BUILT_UP_ANALYSIS = "built_up_analysis"
UNSUPPORTED = "unsupported"
UNCLEAR = "unclear"
class VerdictStatus(str, Enum):
SUPPORTED = "supported"
SUPPORTED_WITH_LIMITATIONS = "supported_with_limitations"
LOW_CONFIDENCE = "low_confidence"
INVALID_INPUT = "invalid_input"
UNSUPPORTED_TASK = "unsupported_task"
DISPUTED = "disputed"
INSUFFICIENT_EVIDENCE = "insufficient_evidence"
MODEL_UNAVAILABLE = "model_unavailable"
DEGRADED_ANALYSIS = "degraded_analysis"
class PlanNode(BaseModel):
node_id: str
tool: str
depends_on: list[str] = Field(default_factory=list)
parameters: dict[str, Any] = Field(default_factory=dict)
class TaskPlan(BaseModel):
task: TaskType
application: str = "single_image" # "single_image" | "bi_temporal" | "optical_sar" | "unsupported" | "unclear"
specific_task: str = "scene_description"
sub_tasks: list[str] = Field(default_factory=list)
multi_intent: bool = False
target: str | None = None
asks_direction: bool = False
tools: list[str]
reason: str
aoi_text: str | None = None
years: list[int] = Field(default_factory=list)
intents: list[str] = Field(default_factory=list)
nodes: list[PlanNode] = Field(default_factory=list)
requires_pair: bool = False
requires_temporal_relationship: bool = False
clarification: str | None = None
class RasterMetadata(BaseModel):
asset_id: str | None = None
file_hash: str | None = None
band_map: dict[str, Any] = Field(default_factory=dict)
band_mapping: dict[str, Any] = Field(default_factory=dict)
wavelengths: dict[str, float] = Field(default_factory=dict)
band_wavelengths: dict[str, float] = Field(default_factory=dict)
quality_metrics: dict[str, Any] = Field(default_factory=dict)
quality_score: float | None = None
valid_fraction: float = 1.0
filename: str
width: int
height: int
bands: int
band_count: int = 0
dtype: str
crs: str | None
bounds: list[float]
resolution: list[float]
nodata: float | None
nodata_percent: float
band_names: list[str]
available_indices: list[str] = Field(default_factory=list)
source_format: str = "raster"
transform: list[float] = Field(default_factory=list)
modality: str = "unknown"
acquisition_date: str | None = None
acquisition_time: str | None = None
sensor: str | None = None
platform: str | None = None
sun_azimuth: float | None = None
sun_elevation: float | None = None
cloud_information: dict[str, Any] = Field(default_factory=dict)
polarization: list[str] = Field(default_factory=list)
tags: dict[str, str] = Field(default_factory=dict)
wgs84_bounds: list[float] | None = None
def model_post_init(self, __context: Any) -> None:
if not self.band_count:
self.band_count = self.bands
if not self.band_mapping and self.band_map:
self.band_mapping = self.band_map
if not self.band_wavelengths and self.wavelengths:
self.band_wavelengths = self.wavelengths
if not self.platform and self.sensor:
self.platform = self.sensor
if not self.acquisition_time and self.acquisition_date:
self.acquisition_time = self.acquisition_date
RasterAsset = RasterMetadata
RasterProfile = RasterMetadata
class QualityReport(BaseModel):
score: float = Field(ge=0, le=1)
compatible: bool
blockers: list[str] = Field(default_factory=list)
warnings: list[str] = Field(default_factory=list)
checks: dict[str, Any] = Field(default_factory=dict)
class EvidenceItem(BaseModel):
evidence_id: str = ""
kind: str
producer: str
summary: str
confidence: float = Field(ge=0, le=1)
artifact_url: str | None = None
metrics: dict[str, Any] = Field(default_factory=dict)
supports_claim: bool | None = None
confidence_source: str = "producer_score"
asset_indices: list[int] = Field(default_factory=list)
timestamp: str | None = None
class TraceStep(BaseModel):
step: int
component: str
action: str
status: str
duration_ms: int
details: dict[str, Any] = Field(default_factory=dict)
class ArtifactRef(BaseModel):
artifact_id: str | None = None
name: str
url: str
mime_type: str
class ConfidenceBreakdown(BaseModel):
input_quality: float = Field(ge=0, le=1)
spatial_alignment: float = Field(ge=0, le=1)
evidence_strength: float = Field(ge=0, le=1)
ensemble_agreement: float = Field(ge=0, le=1)
model_probability: float | None = Field(default=None, ge=0, le=1)
warning_penalty: float = Field(ge=0, le=1)
final_score: float = Field(ge=0, le=1)
is_calibrated: bool = False
calibration_mode: str = "uncalibrated_evidence_strength_v1"
confidence_interval: list[float] = Field(default_factory=list)
expected_calibration_error: float | None = None
class PreprocessingReport(BaseModel):
filename: str
source_format: str
selected_variable: str | None = None
available_variables: list[str] = Field(default_factory=list)
tile_size: int
overlap: int
total_candidate_tiles: int
materialized_tiles: int
complete_coverage: bool
normalization: str
manifest_url: str
class GeoVerdict(BaseModel):
status: VerdictStatus
answer: str
confidence: float = Field(ge=0, le=1)
confidence_kind: str
contradictions: list[str] = Field(default_factory=list)
limitations: list[str] = Field(default_factory=list)
confidence_breakdown: ConfidenceBreakdown
class AnalysisResponse(BaseModel):
result_id: str
task_plan: TaskPlan
mode: str
assets: list[RasterMetadata]
quality: QualityReport
evidence: list[EvidenceItem]
verdict: GeoVerdict
trace: list[TraceStep]
artifacts: list[ArtifactRef]
query: str
generated_at: str
preprocessing: list[PreprocessingReport] = Field(default_factory=list)
input_configuration: str = "INVALID"
findings: list[dict[str, Any]] = Field(default_factory=list)
statistics: dict[str, Any] = Field(default_factory=dict)
models_used: list[str] = Field(default_factory=list)
timings: dict[str, float] = Field(default_factory=dict)
clarification: str | None = None
report_id: str | None = None
@computed_field
@property
def analysis_id(self) -> str:
return self.result_id
@computed_field
@property
def input_type(self) -> str:
return self.input_configuration
@computed_field
@property
def tasks(self) -> list[str]:
return self.task_plan.intents
@computed_field
@property
def buildings(self) -> dict[str, Any] | None:
return self.statistics.get("buildings_a")
@computed_field
@property
def water(self) -> dict[str, Any] | None:
return self.statistics.get("water_measure")
@computed_field
@property
def land_cover(self) -> dict[str, Any] | None:
return self.statistics.get("land_cover")
@computed_field
@property
def shadow(self) -> dict[str, Any] | None:
water = self.statistics.get("water_measure")
return water.get("shadow") if isinstance(water, dict) else None
@computed_field
@property
def uncertainty(self) -> dict[str, Any] | None:
water = self.statistics.get("water_measure")
if not isinstance(water, dict):
return None
return {
"water_shadow_conflict_score": water.get("water_shadow_conflict_score"),
"uncertainty_score": water.get("uncertainty_score"),
}
@computed_field
@property
def raster_profile(self) -> RasterMetadata | None:
return self.assets[0] if self.assets else None
@computed_field
@property
def plan(self) -> TaskPlan:
return self.task_plan
@computed_field
@property
def vegetation(self) -> dict[str, Any] | None:
return self.statistics.get("vegetation_measure") or self.statistics.get("spectral")
@computed_field
@property
def built_up(self) -> dict[str, Any] | None:
return self.statistics.get("built_up_measure") or self.statistics.get("buildings_a")
@computed_field
@property
def change(self) -> dict[str, Any] | None:
return self.statistics.get("change") or self.statistics.get("spectral_change") or self.statistics.get("building_match")
@computed_field
@property
def locations(self) -> list[dict[str, Any]]:
loc = self.statistics.get("user_location")
return [loc] if loc else []
@computed_field
@property
def confidence(self) -> float:
return self.verdict.confidence
@computed_field
@property
def warnings(self) -> list[str]:
return self.quality.warnings
# One canonical model, retaining the existing public API name for compatibility.
AnalysisResult = AnalysisResponse
class AssetRecord(BaseModel):
asset_id: str
original_filename: str
created_at: str
metadata: RasterMetadata
preprocessing: PreprocessingReport
preview_url: str
class QueryRequest(BaseModel):
query: str = Field(min_length=2, max_length=1000)
asset_ids: list[str] = Field(min_length=1, max_length=2)
pair_type: str = Field(default="auto", pattern="^(auto|single|bi_temporal|optical_sar)$")
class VRSBenchCategory(str, Enum):
OPTICAL_VQA = "optical_vqa"
MULTISPECTRAL_VQA = "multispectral_vqa"
VISUAL_GROUNDING = "visual_grounding"
LAND_COVER_VERIFICATION = "land_cover_verification"
class BenchmarkItemResult(BaseModel):
sample_id: str
category: VRSBenchCategory
question: str
target_model: str
expected_answer: str
predicted_answer: str
exact_match: bool
semantic_similarity: float
confidence: float
token_perplexity: float | None = None
predicted_boxes: list[list[float]] = Field(default_factory=list)
ground_truth_boxes: list[list[float]] = Field(default_factory=list)
iou: float | None = None
passed: bool
latency_ms: int
class BenchmarkSummaryMetrics(BaseModel):
total_samples: int
passed_samples: int
accuracy_percent: float
mean_semantic_similarity: float
mean_iou: float | None
mean_confidence: float
mean_latency_ms: float
optical_accuracy: float
multispectral_accuracy: float
grounding_mean_iou: float
model_variants_evaluated: list[str]
class BenchmarkRunRequest(BaseModel):
dataset_name: str = Field(default="vrsbench_sample_split", description="Dataset split to evaluate")
model_variant: str = Field(default="auto", description="'auto', 'earthdial-4b-rgb', 'earthdial-4b-ms' or 'mock'")
max_samples: int | None = Field(default=None, description="Limit evaluation to top N samples")
class BenchmarkRunResponse(BaseModel):
run_id: str
dataset_name: str
evaluated_at: str
summary: BenchmarkSummaryMetrics
results: list[BenchmarkItemResult]
class DatasetSummary(BaseModel):
name: str
description: str
total_samples: int
categories: list[str]
supported_models: list[str]
class SpatialGeometryRecord(BaseModel):
geometry_id: int | str
result_id: str
producer: str
evidence_kind: str
area_m2: float | None = None
crs: str | None = None
bounds: list[float] = Field(default_factory=list)
geometry: dict[str, Any]
properties: dict[str, Any] = Field(default_factory=dict)
class SpatialFeatureCollection(BaseModel):
type: str = "FeatureCollection"
features: list[dict[str, Any]]
total_count: int
properties: dict[str, Any] = Field(default_factory=dict)
class AnalysisRunRecord(BaseModel):
result_id: str
task_type: str
query_text: str
verdict_status: str
confidence: float
created_at: str
geometries_count: int