| import { useQuery } from '@tanstack/react-query' |
|
|
| |
| |
| |
| import { |
| mandisResponse, |
| marketPricesResponse, |
| priceForecastsResponse, |
| sellRecommendationsResponse, |
| priceConflictsResponse, |
| modelInfoResponse, |
| deliveryLogsResponse, |
| pipelineRunsResponse, |
| pipelineStatsResponse, |
| } from './mockData' |
|
|
| const BASE_URL = import.meta.env.VITE_API_URL ?? '' |
|
|
| async function fetchJson<T>(path: string): Promise<T> { |
| const res = await fetch(`${BASE_URL}${path}`) |
| if (!res.ok) throw new Error(`API error: ${res.status} ${res.statusText}`) |
| return res.json() as Promise<T> |
| } |
|
|
| function mock<T>(value: T, delayMs = 260): Promise<T> { |
| return new Promise((resolve) => setTimeout(() => resolve(value), delayMs)) |
| } |
|
|
| |
|
|
| export interface Mandi { |
| mandi_id: string |
| name: string |
| district: string |
| latitude: number |
| longitude: number |
| market_type: string |
| enam_integrated: boolean |
| reporting_quality: string |
| commodities_traded: string[] |
| |
| state?: string |
| avg_daily_arrivals_tonnes?: number |
| |
| last_updated?: string |
| } |
|
|
| export interface MandisResponse { |
| mandis: Mandi[] |
| total: number |
| source?: string |
| } |
|
|
| export interface MarketPrice { |
| mandi_id: string |
| mandi_name: string |
| commodity_id: string |
| commodity_name: string |
| price_rs: number |
| agmarknet_price_rs: number | null |
| enam_price_rs: number | null |
| reconciled_price_rs: number |
| confidence: number |
| price_trend: string |
| date: string |
| |
| |
| category?: string |
| source_used?: string |
| reasoning?: string |
| } |
|
|
| export interface MarketPricesResponse { |
| market_prices: MarketPrice[] |
| total: number |
| source?: string |
| } |
|
|
| export interface PriceForecast { |
| mandi_id: string |
| mandi_name: string |
| commodity_id: string |
| commodity_name: string |
| |
| |
| current_price_rs: number | null |
| price_7d: number | null |
| price_14d: number | null |
| price_30d: number | null |
| ci_lower_7d: number | null |
| ci_upper_7d: number | null |
| |
| |
| |
| |
| ci_lower_14d?: number |
| ci_upper_14d?: number |
| ci_lower_30d?: number |
| ci_upper_30d?: number |
| direction: string |
| confidence: number |
| |
| seasonal_index?: number |
| } |
|
|
| export interface PriceForecastsResponse { |
| price_forecasts: PriceForecast[] |
| total: number |
| source?: string |
| } |
|
|
| export interface SellOption { |
| mandi_id: string |
| mandi_name: string |
| sell_timing: string |
| market_price_rs: number |
| transport_cost_rs: number |
| storage_loss_rs: number |
| mandi_fee_rs: number |
| net_price_rs: number |
| distance_km: number |
| |
| |
| |
| drive_time_min?: number |
| confidence?: number |
| price_source?: string |
| } |
|
|
| export interface CreditReadiness { |
| readiness: 'strong' | 'moderate' | 'not_yet' |
| expected_revenue_rs: number |
| min_revenue_rs: number |
| max_advisable_input_loan_rs: number |
| revenue_confidence: number |
| loan_to_revenue_pct: number |
| strengths: string[] |
| risks: string[] |
| advice_en: string |
| advice_ta: string |
| |
| kcc_limit_rs?: number | null |
| kcc_outstanding_rs?: number | null |
| kcc_headroom_rs?: number | null |
| kcc_repayment_status?: string | null |
| dpi_checked?: boolean |
| } |
|
|
| export interface SellRecommendation { |
| |
| |
| farmer_id?: string |
| farmer_name: string |
| commodity_id: string |
| commodity_name: string |
| |
| |
| quantity_quintals: number |
| farmer_lat: number |
| farmer_lon: number |
| best_option: SellOption |
| all_options: SellOption[] |
| potential_gain_rs: number |
| recommendation_text: string |
| |
| |
| |
| |
| |
| recommendation_local?: string |
| local_language_code?: string |
| |
| credit_readiness?: CreditReadiness | null |
| } |
|
|
| export interface SellRecommendationsResponse { |
| sell_recommendations: SellRecommendation[] |
| total: number |
| source?: string |
| } |
|
|
| export interface InvestigationStep { |
| tool: string |
| finding: string |
| } |
|
|
| export interface PriceConflict { |
| mandi_id: string |
| mandi_name: string |
| commodity_id: string |
| commodity_name: string |
| agmarknet_price: number |
| enam_price: number |
| delta_pct: number |
| resolution: string |
| reconciled_price: number |
| reasoning: string |
| |
| |
| confidence?: number |
| investigation_steps?: InvestigationStep[] | null |
| } |
|
|
| export interface PriceConflictsResponse { |
| price_conflicts: PriceConflict[] |
| total: number |
| source?: string |
| } |
|
|
| |
|
|
| export interface RawInputsResponse { |
| raw_inputs: Record<string, unknown> |
| sources: string[] |
| } |
|
|
| export interface ExtractedDataResponse { |
| extracted_data: Record<string, unknown> |
| total_mandis: number |
| } |
|
|
| export interface ReconciledDataResponse { |
| reconciled_data: Record<string, unknown> |
| total_mandis: number |
| total_conflicts: number |
| } |
|
|
| |
|
|
| export interface ModelInfoResponse { |
| model_metrics: { |
| model_type: string |
| |
| |
| |
| rmse?: number | null |
| mae?: number | null |
| r2?: number | null |
| directional_accuracy?: number | null |
| train_samples?: number | null |
| test_samples?: number | null |
| features?: string[] |
| feature_importances?: Record<string, number> |
| } |
| |
| |
| ml_stack?: { |
| primary_model: { type: string; features: number; metrics: Record<string, number> } |
| agents: Record<string, string> |
| [key: string]: unknown |
| } |
| source?: string |
| } |
|
|
| |
|
|
| export interface DeliveryLog { |
| farmer_id: string |
| farmer_name: string |
| phone: string |
| channel: string |
| sms_text: string |
| sms_text_local: string |
| status: string |
| error: string | null |
| created_at: string |
| } |
|
|
| export interface DeliveryLogsResponse { |
| delivery_logs: DeliveryLog[] |
| total: number |
| } |
|
|
| |
|
|
| export interface PipelineStepDetails { |
| data_source_mode?: 'live' | 'demo' |
| [key: string]: unknown |
| } |
|
|
| export interface PipelineStep { |
| step: string |
| status: string |
| duration_s: number |
| details?: PipelineStepDetails |
| } |
|
|
| export interface PipelineRun { |
| run_id: string |
| started_at: string |
| ended_at: string |
| status: string |
| duration_s: number |
| steps: PipelineStep[] |
| total_cost_usd: number |
| |
| mandis_processed?: number |
| commodities_tracked?: number |
| } |
|
|
| export interface PipelineRunsResponse { |
| runs: PipelineRun[] |
| |
| |
| total?: number |
| source?: string |
| } |
|
|
| export interface PipelineStats { |
| total_runs: number |
| success_rate: number |
| mandis_monitored: number |
| commodities_tracked: number |
| price_conflicts_found: number |
| total_cost_usd: number |
| last_run: string | null |
| data_sources: string[] |
| |
| successful_runs?: number |
| avg_cost_per_run_usd?: number |
| source?: string |
| } |
|
|
| |
|
|
| const STALE_5MIN = 5 * 60 * 1000 |
|
|
| |
|
|
| export interface HealthResponse { |
| status: string |
| |
| |
| region?: 'kenya' | 'india' |
| pipeline_data?: boolean |
| source?: string |
| error?: string |
| } |
|
|
| export function useHealth() { |
| return useQuery<HealthResponse>({ |
| queryKey: ['health'], |
| queryFn: () => fetchJson<HealthResponse>('/api/health'), |
| staleTime: STALE_5MIN, |
| }) |
| } |
|
|
| export function useMandis() { |
| return useQuery<MandisResponse>({ |
| queryKey: ['mandis'], |
| queryFn: () => fetchJson<MandisResponse>('/api/mandis'), |
| staleTime: STALE_5MIN, |
| }) |
| } |
|
|
| export function useMarketPrices() { |
| return useQuery<MarketPricesResponse>({ |
| queryKey: ['market-prices'], |
| queryFn: () => fetchJson<MarketPricesResponse>('/api/market-prices'), |
| staleTime: STALE_5MIN, |
| }) |
| } |
|
|
| export function usePriceForecasts() { |
| return useQuery<PriceForecastsResponse>({ |
| queryKey: ['price-forecast'], |
| queryFn: () => fetchJson<PriceForecastsResponse>('/api/price-forecast'), |
| staleTime: STALE_5MIN, |
| }) |
| } |
|
|
| export function useSellRecommendations() { |
| return useQuery<SellRecommendationsResponse>({ |
| queryKey: ['sell-recommendations'], |
| queryFn: () => fetchJson<SellRecommendationsResponse>('/api/sell-recommendations'), |
| staleTime: STALE_5MIN, |
| }) |
| } |
|
|
| export function usePriceConflicts() { |
| return useQuery<PriceConflictsResponse>({ |
| queryKey: ['price-conflicts'], |
| queryFn: () => fetchJson<PriceConflictsResponse>('/api/price-conflicts'), |
| staleTime: STALE_5MIN, |
| }) |
| } |
|
|
| export function useModelInfo() { |
| return useQuery<ModelInfoResponse>({ |
| queryKey: ['model-info'], |
| queryFn: () => fetchJson<ModelInfoResponse>('/api/model-info'), |
| staleTime: STALE_5MIN, |
| }) |
| } |
|
|
| export function useDeliveryLogs() { |
| return useQuery<DeliveryLogsResponse>({ |
| queryKey: ['delivery-logs'], |
| queryFn: () => fetchJson<DeliveryLogsResponse>('/api/delivery-logs'), |
| staleTime: STALE_5MIN, |
| }) |
| } |
|
|
| export function usePipelineRuns() { |
| return useQuery<PipelineRunsResponse>({ |
| queryKey: ['pipeline-runs'], |
| queryFn: () => fetchJson<PipelineRunsResponse>('/api/pipeline-runs'), |
| staleTime: STALE_5MIN, |
| }) |
| } |
|
|
| export function usePipelineStats() { |
| return useQuery<PipelineStats>({ |
| queryKey: ['pipeline-stats'], |
| queryFn: () => fetchJson<PipelineStats>('/api/pipeline-stats'), |
| staleTime: STALE_5MIN, |
| }) |
| } |
|
|