from typing import List, Optional, Dict, Any from pydantic import BaseModel, Field from datetime import datetime, timezone def current_utc_time(): return datetime.now(timezone.utc) class AlternativeDiagnosis(BaseModel): disease_id: str disease_name: str crop: str confidence: float = Field(..., ge=0.0, le=1.0) class TreatmentPlan(BaseModel): immediate_action: List[str] organic_control: List[str] chemical_control: List[str] class DiseaseDetail(BaseModel): id: str name: str scientific_name: Optional[str] = None crop: str severity: str = Field(..., description="Healthy | Low | Moderate | Severe | Critical | Invalid") is_healthy: bool = False symptoms: List[str] treatment: TreatmentPlan prevention: List[str] expert_consultation_recommended: bool = False class DiagnosisResponse(BaseModel): success: bool = True is_valid_leaf: bool = Field(default=True, description="False if image is a car, object, or non-plant") timestamp: datetime = Field(default_factory=current_utc_time) image_id: str crop: str disease: str disease_id: str scientific_name: Optional[str] = None is_healthy: bool severity: str confidence: float = Field(..., ge=0.0, le=1.0) confidence_percentage: str symptoms: List[str] management: TreatmentPlan prevention: List[str] alternatives: List[AlternativeDiagnosis] = [] similar_crops: List[str] = [] expert_escalation: dict = Field( default_factory=lambda: { "recommended": False, "helpline_number": "+918817814859", "whatsapp_expert": "+918817814859", "reason": None } ) class CropInfo(BaseModel): crop_name: str supported_diseases_count: int diseases: List[str] class SupportedCropsResponse(BaseModel): total_crops: int total_classes: int crops: List[CropInfo] class ExpertTicketRequest(BaseModel): farmer_name: str phone_number: str location: Optional[str] = None crop: str disease_suspected: Optional[str] = None confidence_score: Optional[float] = None notes: Optional[str] = None image_url_or_id: Optional[str] = None class ExpertTicketResponse(BaseModel): ticket_id: str status: str = "PENDING_REVIEW" created_at: datetime = Field(default_factory=current_utc_time) message: str assigned_expert: str = "Dr. S. Sharma (Senior Agronomist, Plant Pathology)" estimated_callback_minutes: int = 30 class DosageCalculationRequest(BaseModel): crop: str disease_id: str farm_area_acres: float = Field(..., gt=0.0, description="Farm area in acres") knapsack_tank_liters: float = Field(default=16.0, gt=0.0, description="Knapsack sprayer tank capacity in liters") treatment_type: str = Field(default="chemical", description="chemical | organic") class DosageCalculationResponse(BaseModel): crop: str disease: str farm_area_acres: float recommended_chemical_or_bio: str total_water_liters: float total_dosage_amount: str dosage_per_tank: str total_knapsack_tanks: int spray_instructions: List[str] safety_precautions: List[str] class SporeCastPoint(BaseModel): district: str latitude: float longitude: float disease: str risk_level: str # Low, Moderate, High, Severe Epidemic wind_vector: str forecast_48h: str affected_farms_reported: int class SporeCastAlertResponse(BaseModel): active_epidemics: int highest_risk_region: str spore_dispersion_speed_kmh: float regional_heatmap: List[SporeCastPoint] kvk_advisory: str class GreenCreditRequest(BaseModel): farmer_id: Optional[str] = "FARMER-001" crop: str farm_area_acres: float adopted_practice: str = Field(..., description="bio_fungicide | neem_extract | trichoderma | balanced_ipm") class GreenCreditResponse(BaseModel): green_credits_earned: int chemical_pesticide_saved_kg: float carbon_offset_kg_co2e: float soil_microbiome_health_score: str reward_redemption_eligible: bool certificate_id: str class SpectroscopyAnalysisResponse(BaseModel): is_leaf: bool = True is_valid_leaf: bool = True rejection_code: Optional[str] = None error_message: Optional[str] = None chlorophyll_retention_percentage: float = 0.0 green_leaf_index_gli: float = 0.0 vari_index: float = 0.0 ngrdi_index: float = 0.0 health_status: str asymptomatic_stress_detected: bool = False risk_classification: str spectral_diagnosis: str early_action_protocol: List[str] = [] foliage_coverage_percentage: Optional[float] = None diagnostics: Optional[dict] = None class FarmMemorySaveRequest(BaseModel): crop: str disease: str disease_id: str severity: str confidence: float temperature_c: float humidity_pct: float weather_condition: str location_name: Optional[str] = "Ambikapur, Surguja" gps_lat: Optional[float] = 23.1188 gps_lng: Optional[float] = 83.1979 farmer_notes: Optional[str] = "" diagnosis_date: Optional[str] = None class SeasonalAlertItem(BaseModel): alert_id: str crop: str disease: str disease_id: str historical_outbreak_date: str threat_level: str recurrence_risk_score: float window_description: str alert_title: str alert_message: str prophylactic_plan: dict class SeasonalAlertsResponse(BaseModel): status: str = "success" active_alerts_count: int alerts: List[SeasonalAlertItem] class BioAcousticAnalysisResponse(BaseModel): pest_detected: bool pest_identified: str threat_level: str confidence_score: float dominant_frequency_hz: float pest_acoustic_energy_ratio: float diagnosis_summary: str recommended_actions: List[str] engine_type: Optional[str] = "Mel_CNN_BioAcoustic" class_probabilities: Optional[Dict[str, float]] = None mastication_rhythm_index: Optional[float] = None class BioTwinForecastResponse(BaseModel): crop: str target_pathogen: str spore_germination_index_pct: float risk_classification: str calculated_dew_point_c: float effective_leaf_wetness_hours: float critical_infection_window_hours: int physics_forecast_summary: str preventive_canopy_actions: List[str] class DroneVRAMissionRequest(BaseModel): field_id: str = "FIELD-01" center_lat: float = 23.1188 center_lng: float = 83.1979 field_area_acres: float = Field(..., gt=0.0) infected_clusters: List[dict] = Field(default_factory=list) spray_altitude_meters: float = Field(default=2.5, gt=0.5, le=10.0) class DroneVRAMissionResponse(BaseModel): mission_id: str field_area_acres: float flight_altitude_meters: float swath_width_meters: float total_waypoints: int estimated_flight_duration_minutes: float vra_spot_spray_liters: float traditional_blanket_spray_liters: float chemical_savings_percentage: str waypoints: List[dict] geojson_flight_plan: dict qgroundcontrol_format_compatible: bool class ProofOfFarmingRequest(BaseModel): farmer_id: str = "FARMER-101" farmer_name: str khasra_survey_number: str district: str = "Surguja" state: str = "Chhattisgarh" crop: str = "Paddy (Rice)" disease_identified: str severity_percentage: float = Field(..., ge=0.0, le=100.0) affected_area_acres: float = Field(..., gt=0.0) gps_latitude: float gps_longitude: float image_hash: Optional[str] = None class ProofOfFarmingResponse(BaseModel): certificate_id: str digital_signature_sha256: str created_at_utc: str claim_status: str fast_track_claim_payload: dict blockchain_smart_contract_ready: bool verification_qr_payload: str class GovernmentSchemeItem(BaseModel): id: str title_hi: str title_en: str category: str category_hi: str benefit_amount: str summary_hi: str summary_en: str eligibility_hi: str required_documents_hi: List[str] official_portal: str direct_apply_url: Optional[str] = None status_check_url: Optional[str] = None guidelines_pdf_url: Optional[str] = None source_portal_authority: Optional[str] = "Government of India" helpline: str icon: str badge_color: str last_synced_utc: Optional[str] = None class GovernmentSchemesResponse(BaseModel): total_schemes: int myscheme_portal_url: str = "https://www.myscheme.gov.in/search/category/Agriculture,Rural%20&%20Environment" live_sync_status: str = "SYNCED_WITH_GOVT_PORTALS" categories: List[str] schemes: List[GovernmentSchemeItem] class KisanPollOptionItem(BaseModel): id: str title_hi: str title_en: str description_hi: str icon: str votes_count: int vote_percentage: float recommended_govt_action_hi: str class KisanPollVoteRequest(BaseModel): problem_id: str district: Optional[str] = "Surguja" state: Optional[str] = "Chhattisgarh" crop_affected: Optional[str] = "Paddy (Rice)" farmer_comment: Optional[str] = "" class KisanPollResultsResponse(BaseModel): target_district: str total_farmer_responses: int highest_priority_issue: str highest_priority_vote_share: str recommended_immediate_intervention: str issues_breakdown: List[KisanPollOptionItem] last_updated: str # ========================================================================= # Next-Gen Innovation Schemas (Voice, Traps, Satellite, Soil, GNN) # ========================================================================= class VoiceAdvisoryRequest(BaseModel): user_query: str dialect: Optional[str] = "ch-IN" crop: Optional[str] = None class VoiceAdvisoryResponse(BaseModel): status: str = "success" dialect: str dialect_name: str user_query: str normalized_context: dict spoken_title: str advisory_text: str tank_prescription: dict tts_playback_metadata: dict class SoilHealthCardRequest(BaseModel): crop: Optional[str] = "Rice" area_acres: Optional[float] = 1.0 ph: Optional[float] = 6.8 organic_carbon_pct: Optional[float] = 0.52 available_n_kg_ha: Optional[float] = 220.0 available_p_kg_ha: Optional[float] = 14.5 available_k_kg_ha: Optional[float] = 180.0 zinc_ppm: Optional[float] = 0.55 has_active_blast: Optional[bool] = False class SoilHealthCardResponse(BaseModel): status: str = "success" soil_test_readings: dict target_crop: str area_acres: float total_commercial_fertilizer: dict split_schedule: List[dict] safety_alert: Optional[str] = None # ========================================================================= # Extreme Weather Shock & IoT Telemetry Schemas # ========================================================================= class WeatherShockForecastRequest(BaseModel): crop: Optional[str] = "Potato" ambient_temp_c: Optional[float] = 4.0 min_predicted_temp_c: Optional[float] = 1.5 max_predicted_temp_c: Optional[float] = 24.0 relative_humidity: Optional[float] = 55.0 wind_speed_kmh: Optional[float] = 3.0 cloud_cover_pct: Optional[float] = 5.0 growth_stage: Optional[str] = None class WeatherShockForecastResponse(BaseModel): status: str = "success" crop: str vulnerable_stage: str primary_threat: str microclimate_snapshot: dict frost_assessment: dict heatwave_assessment: dict class IoTTelemetryPacket(BaseModel): device_id: str = "NODE-SURGUJA-01" battery_voltage_v: float = 3.92 solar_charging: bool = True rssi_dbm: int = -88 snr_db: float = 8.5 soil_moisture_vwc_15cm: float = 24.5 soil_moisture_vwc_30cm: float = 28.2 canopy_temp_c: float = 26.4 canopy_rh_pct: float = 82.0 leaf_wetness_pct: float = 45.0 class IoTTelemetryResponse(BaseModel): status: str = "success" device_id: str packet_timestamp_utc: str soil_moisture_assessment: dict microclimate: dict hardware_telemetry: dict active_alarms: List[dict] # ========================================================================= # Kisan Jan-Mat Community Poll & Government Scheme Schemas # ========================================================================= class KisanPollVoteRequest(BaseModel): problem_id: str district: Optional[str] = "Surguja" state: Optional[str] = "Chhattisgarh" crop_affected: Optional[str] = "Paddy (Rice)" farmer_comment: Optional[str] = "" device_id: Optional[str] = "" class KisanPollVoteResponse(BaseModel): status: str message_hi: str message_en: str ballot_id: str total_community_votes: int updated_results: List[dict] class KisanPollQuestionsResponse(BaseModel): status: str = "success" total_options: int options: List[dict] class KisanPollResultsResponse(BaseModel): status: str = "success" target_district: str total_farmer_responses: int highest_priority_issue: str highest_priority_vote_share: str recommended_immediate_intervention: str issues_breakdown: List[dict] recent_grassroot_ballots: Optional[List[dict]] = [] last_updated: str