
    KCj*              
           d Z ddlZddlZddlmZ ddlmZ  e       Z ee      Z	dZ
dededed	ed
ef
dZdededed	ed
ef
dZ G d d      Z e       Zy)u	  
LLM reasoning layer.

Production concerns specific to calling an external LLM API:
1. Timeouts — never let one slow LLM call hold a worker indefinitely.
2. Retries — transient network/5xx errors should retry with backoff,
   but only a bounded number of times (LLM_MAX_RETRIES), not forever.
3. Graceful degradation — if the LLM is unreachable after retries, the
   user should still get the raw model numbers with a template-based
   explanation, not a 502 for the entire request. The ML predictions
   are the product; the LLM is a presentation layer on top of them.
4. No hallucination — the system prompt explicitly forbids inventing
   numbers, and the user prompt only contains values that came from the
   aggregator, never free text the model could "fill in."
    N)get_settings)
get_loggeru  You are an agricultural decision assistant helping Indian farmers and agricultural officers understand machine learning model output about crop suitability.

Strict rules you must follow:
- Use ONLY the numbers and labels provided to you. Never invent or estimate a number that was not given.
- Do not override or contradict the model outputs. Your job is to explain them, not to second-guess them.
- If a model output is marked "degraded" or has null values, say so plainly rather than guessing a substitute number.
- If conflicts are listed, mention them honestly — do not smooth over genuine uncertainty.
- Use simple, direct language suitable for someone without a technical background. Avoid jargon like "anomaly score" without explaining what it means.
- Structure your response in exactly six sections, in this order:
  1. Crop suitability summary
  2. Climate assessment
  3. Expected yield
  4. Market insight
  5. Risk explanation
  6. Alternative crop suggestions
- Keep the whole response under 350 words.
districtcropmonthmodel_outputsreturnc                     d| d|  d| d|d    d|d    d|d	    d
|d    d|d    d|d    d|d    d|j                  dg        dS )NzCrop: z
District: z
Month: z

Model outputs:
- Climate: climatez
- Feasibility: feasibilityz

- Yield: yield_predictionz

- Trend: trendz
- Market: marketz
- Alternative crops: recommendationz
- Conflicts detected: 	conflictsz$
- Models that had issues this run: degraded_modelszL

Write the six-section explanation now, following the system rules exactly.)get)r   r   r   r   s       EC:\Crop_Prediction\Backend\crop-ai-system\app\services\llm_service.py_build_user_promptr   5   s    dV * w  )$% &m,- .

*
+	, -


 	! ""
# $#$456 7$[12 3$$1$5$56G$L#M NKN N    c                    |d   }|d   }|d   }|d   }|d   j                  dg       }|rdj                  d |D              nd	}	d
| d|  d| d|j                  dd       d|j                  dd      dd|j                  d       d|j                  d       d|j                  d       d|j                  d       d|j                  d       ddj                  |j                  d g             xs d! d"|	 d#S )$u   
    Used only if the LLM is unreachable after all retries. A plain
    template ensures the user still receives the actual model results —
    degraded presentation, not a failed request.
    r   r   r   r   r   alternativesz, c              3   &   K   | ]	  }|d      yw)r   N ).0as     r   	<genexpr>z(_fallback_explanation.<locals>.<genexpr>R   s     2!F)2s   znone availablezlAI explanation service is temporarily unavailable, showing raw model results.

1. Crop suitability summary: z in z for month z is classified as 'labelunknownz' (confidence 
confidencer   z.0%z,).
2. Climate assessment: forecast rainfall forecast_rainfall_mmz mm, anomaly level: anomaly_labelz.
3. Expected yield: expected_yield_ton_haz3 tonnes/hectare.
4. Market insight: price forecast price_forecast_per_quintalz per quintal, demand level: demand_levelz.
5. Risk explanation: z; r   zno conflicts detectedz#.
6. Alternative crop suggestions: .)r   join)
r   r   r   r   feasyldr   r   alts	alt_namess
             r   _fallback_explanationr,   G   sL    'D
*
+CI&G8$F)*..~rBD6:		2T22@PI((,vT(;ug N((7I67 8xxa05 644;KK@V4W3X Y!++o67 8!gg&=>? @--3ZZ8T-U,V W&&,jj&@%A B  $		-*;*;K*L M hQhi j,,5;a
	9r   c            
       8    e Zd Zd
dZd
dZdededededef
d	Zy)
LLMServicer	   Nc                     d | _         y )N)_clientselfs    r   __init__zLLMService.__init__d   s	    37r   c                     t         j                  st        j                  d       d | _        y t        j                  t         j                  t         j                        | _        y )Nuk   ANTHROPIC_API_KEY is not set — LLM explanations will use the fallback template until a key is configured.)api_keytimeout)settingsANTHROPIC_API_KEYloggerwarningr0   	anthropic	AnthropicLLM_TIMEOUT_SECONDSr1   s    r   initzLLMService.initg   sM    ))NNC  DL **..00
r   r   r   r   r   c           	         | j                   t        ||||      S t        ||||      }d }t        dt        j
                  dz         D ]  }	 | j                   j                  j                  t        j                  t        j                  t        d|dg      }|j                  D 	cg c]  }	|	j                  dk(  s|	j                    }
}	dj                  |
      j                         c S  t&        j5                  d|        t        ||||      S c c}	w # t         j"                  $ rM}|}t%        d|z  d      }t&        j)                  d	| d
| d       t+        j,                  |       Y d }~,d }~wt         j.                  $ rM}|}t%        d|z  d      }t&        j)                  d| d
| d       t+        j,                  |       Y d }~d }~wt         j0                  $ r}|}d|j2                  cxk  rdk  rNn nKt%        d|z  d      }t&        j)                  d|j2                   d| d       t+        j,                  |       n,t&        j5                  d|j2                   d|        Y d }~ Y d }~7d }~ww xY w)N      user)rolecontent)model
max_tokenssystemmessagestext

   zLLM rate limited, retrying in zs (attempt )z"LLM connection error, retrying in i  iX  zLLM server error z, retrying in szLLM client error z, not retrying: z;LLM call failed after retries, using fallback explanation: )r0   r,   r   ranger7   LLM_MAX_RETRIESrH   create	LLM_MODELLLM_MAX_TOKENSSYSTEM_PROMPTrD   typerI   r'   stripr;   RateLimitErrorminr9   r:   timesleepAPIConnectionErrorAPIStatusErrorstatus_codeerror)r2   r   r   r   r   user_prompt
last_errorattemptresponsebtext_blocksexcwaits                r   get_explanationzLLMService.get_explanationt   sG   <<(4NN(4N'+
Q 8 81 <= !	G <<0077",,'66('-+FG	 8  08/?/?T!166VCSqvvTTyy-3355!	F 	RS]R^_`$XtUMJJ9 U ++ ! 
1<,!?v[QXPYYZ[\

4  // ! 
1<,!CD6U\T]]^_`

4  ++ 
 
#///C/qG|R0DNN%6s6G~VZU[[\#]^JJt$ LL#4S__4EEUVYUZ![\ %
sL   AD'D<D
 DDJ,AE44J
AGJ(B
I??J)r	   N)	__name__
__module____qualname__r3   r>   strintdictrf   r   r   r   r.   r.   c   s<    8
+K +K3 +Ks +KSW +K\_ +Kr   r.   )__doc__rX   r;   app.core.configr   app.core.logging_configr   r7   rg   r9   rS   rj   rk   rl   r   r,   r.   llm_servicer   r   r   <module>rq      s       ( .>	H	4N NC N ND NUX N$C s 3 t X[ 8<K <K@ lr   