
    $j Q                         d Z ddlZddlZddlmZmZ ddlmZmZ ddlm	Z	m
Z
  ej        e          Z G d de	          Z G d d	e	          Z G d
 de          Z G d de          Z G d de          ZdS )z
Query analysis abstraction for the memory system.

Provides an interface for analyzing natural language queries to extract
structured information like temporal constraints.
    N)ABCabstractmethod)datetime	timedelta)	BaseModelFieldc                   d    e Zd ZU dZ ed          Zeed<    ed          Zeed<   de	fdZ
d	S )
TemporalConstraintzl
    Temporal constraint extracted from a query.

    Represents a time range with start and end dates.
    z#Start of the time range (inclusive))description
start_datez!End of the time range (inclusive)end_datereturnc                 p    | j                             d           d| j                            d           S )N%Y-%m-%d to )r   strftimer   selfs    k/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/hindsight_api/engine/query_analyzer.py__str__zTemporalConstraint.__str__   s7    /**:66``DM<R<RS]<^<^```    N)__name__
__module____qualname____doc__r   r   r   __annotations__r   strr    r   r   r
   r
      s           !5-RSSSJSSS+NOOOHhOOOa a a a a a ar   r
   c                   >    e Zd ZU dZ edd          Zedz  ed<   dS )QueryAnalysisz
    Result of analyzing a natural language query.

    Contains extracted structured information like temporal constraints.
    Nz%Extracted temporal constraint, if any)defaultr   temporal_constraint)r   r   r   r   r   r"   r
   r   r   r   r   r    r        sV           6;U"I6 6 6+d2     r   r    c                   V    e Zd ZdZedd            Zed	dededz  defd            Z	dS )
QueryAnalyzerz
    Abstract base class for query analysis.

    Implementations analyze natural language queries to extract structured
    information like temporal constraints, entities, etc.
    r   Nc                     dS )z
        Load the query analyzer model.

        This should be called during initialization to load the model
        and avoid cold start latency on first analyze() call.
        Nr   r   s    r   loadzQueryAnalyzer.load4   s	     	r   queryreference_datec                     dS )a  
        Analyze a natural language query.

        Args:
            query: Natural language query to analyze
            reference_date: Reference date for relative terms (defaults to now)

        Returns:
            QueryAnalysis containing extracted information
        Nr   )r   r'   r(   s      r   analyzezQueryAnalyzer.analyze>   s	     	r   r   NN)
r   r   r   r   r   r&   r   r   r    r*   r   r   r   r$   r$   ,   s|             ^  S (T/ ]    ^  r   r$   c                   V    e Zd ZdZd Zd
dZddededz  defdZ	dedede
dz  fd	ZdS )DateparserQueryAnalyzeraF  
    Query analyzer using dateparser library.

    Uses dateparser to extract temporal expressions from natural language
    queries. Supports 200+ languages including English, Spanish, Italian,
    French, German, etc.

    Performance:
    - ~10-50ms per query
    - No model loading required (lazy import on first use)
    c                     d| _         dS )z%Initialize dateparser query analyzer.N)_search_datesr   s    r   __init__z DateparserQueryAnalyzer.__init__Z   s    !r   r   Nc                 \    | j         $ddlm} || _         |                      d           dS dS )zLoad dateparser and warm up internal data structures.

        Triggers the real initialization cost (regex tables, timezone data) at
        load time so the first actual recall doesn't pay the cold-start penalty.
        Nr   )search_datestoday)r0   dateparser.searchr3   )r   r3   s     r   r&   zDateparserQueryAnalyzer.load^   sI     %666666!-Dw''''' &%r   r'   r(   c                    |t          j                    }|                                }|                     ||          }|t	          |          S |                                  |ddd}	 |                     ||          }nU# t          $ rH}t          	                    dt          |          j        |           t	          d          cY d}~S d}~ww xY w|st	          d          S h dfd	|D             }|st	          d          S |d
         \  }	}
|
                    d
d
d
d
          }|
                    dddd          }t	          t          ||                    S )a  
        Analyze query using dateparser.

        Extracts temporal expressions from the query text. Supports multiple
        languages automatically.

        Args:
            query: Natural language query (any language)
            reference_date: Reference date for relative terms (defaults to now)

        Returns:
            QueryAnalysis with temporal_constraint if found
        Nr"   pastF)RELATIVE_BASEPREFER_DATES_FROMRETURN_AS_TIMEZONE_AWARE)settingszFdateparser raised %s on query (treating as no temporal constraint): %s>   docanfrimaymonsatsunthutuewedwillmarchc                 p    g | ]2\  }}|                                 vst          |          d k    .||f3S )   )lowerlen).0textdatefalse_positivess      r   
<listcomp>z3DateparserQueryAnalyzer.analyze.<locals>.<listcomp>   sI    xxx*$4::<<WfCfCfjmnrjsjsvwjwjw$jwjwjwr   r   hourminutesecondmicrosecond   ;   ?B r   r   )r   nowrK   _extract_periodr    r&   r0   	Exceptionloggerwarningtyper   replacer
   )r   r'   r(   query_lowerperiod_resultr<   resultsevalid_results_parsed_dater   r   rP   s                @r   r*   zDateparserQueryAnalyzer.analyzek   s    !%\^^N kkmm,,[.II$ ]CCCC 			 ,!'(-
 
	;(((BBGG 	; 	; 	;NNXQ   
 !T:::::::::	;  	; T:::: qppxxxxxxx 	; T:::: 'q); !((a!QR(SS
&&Br"RX&YY1Czdl1m1m1mnnnns   .B 
C=CCCc                 |	   dt           dt           dt          fd}t          j        d|t          j                  r|t          d          z
  } |||          S t          j        d|t          j                  r |||          S t          j        d	|t          j                  r. ||t          d
          z
  |t          d          z
            S t          j        d|t          j                  r. ||t          d          z
  |t          d          z
            S t          j        d|t          j                  r. ||t          d
          z
  |t          d          z
            S t          j        d|t          j                  r. ||t          d          z
  |t          d          z
            S t          j        d|t          j                  r. ||t          d          z
  |t          d          z
            S t          j        d|t          j                  r. ||t          d          z
  |t          d          z
            S t          j        d|t          j                  rE|t          |                                dz             z
  } |||t          d          z             S t          j        d|t          j                  rK|                    d          }|t          d          z
  }|                    d          } |||          S t          j        d|t          j                  r4|j        dz
  } |t          |dd          t          |dd                    S t          j        d|t          j                  rR|                                dz   dz  }	|	d k    rd}	|t          |	          z
  }
 ||
|
t          d          z             S ddd
d!dddd"d#d$d%dd&}|	                                D ]\  }}t          j        d'| d(|t          j                  }|r~t          |                    d                    }t          ||d          }|dk    rt          |dd          }n%t          ||dz   d          t          d          z
  } |||          c S d)S )*z
        Extract period-based temporal expressions (week, month, year, weekend).

        These need special handling as they represent date ranges, not single dates.
        Supports multiple languages.
        startendr   c           	          t          |                     dddd          |                    dddd                    S Nr   rR   rW   rX   rY   rZ   r
   ra   rj   rk   s     r   
constraintz;DateparserQueryAnalyzer._extract_period.<locals>.constraint   I    % ==a!QR=SS"RPVWW   r   z&\b(yesterday|ayer|ieri|hier|gestern)\b   daysz(\b(today|hoy|oggi|aujourd\'?hui|heute)\bz'\b(a\s+)?couple\s+(of\s+)?days?\s+ago\brJ   z\b(a\s+)?few\s+days?\s+ago\b      z(\b(a\s+)?couple\s+(of\s+)?weeks?\s+ago\b)weeksz\b(a\s+)?few\s+weeks?\s+ago\bz)\b(a\s+)?couple\s+(of\s+)?months?\s+ago\bZ      z\b(a\s+)?few\s+months?\s+ago\b   <   ui   \b(last\s+week|la\s+semana\s+pasada|la\s+settimana\s+scorsa|la\s+semaine\s+derni[eè]re|letzte\s+woche)\b      z\\b(last\s+month|el\s+mes\s+pasado|il\s+mese\s+scorso|le\s+mois\s+dernier|letzten?\s+monat)\bdayud   \b(last\s+year|el\s+a[ñn]o\s+pasado|l\'anno\s+scorso|l\'ann[ée]e\s+derni[eè]re|letztes?\s+jahr)\b      z\b(last\s+weekend|el\s+fin\s+de\s+semana\s+pasado|lo\s+scorso\s+fine\s+settimana|le\s+week-?end\s+dernier|letztes?\s+wochenende)\br         	   
      )z$january|enero|gennaio|janvier|januaru-   february|febrero|febbraio|f[ée]vrier|februaru   march|marzo|mars|m[äa]rzzapril|abril|aprile|avrilzmay|mayo|maggio|maizjune|junio|giugno|juin|junizjuly|julio|luglio|juillet|juliu   august|agosto|ao[uû]tz(september|septiembre|settembre|septembrez'october|octubre|ottobre|octobre|oktoberznovember|noviembre|novembreu1   december|diciembre|dicembre|d[ée]cembre|dezemberz\b(z)\s+(\d{4})\bN)r   r
   research
IGNORECASEr   weekdayra   yearitemsintgroup)r   r'   r(   rp   drj   firstrk   r   days_since_satrB   month_patternspattern	month_nummatchs                  r   r\   z'DateparserQueryAnalyzer._extract_period   sA   	h 	X 	:L 	 	 	 	 9>r}UU 	$!2!2!22A:a### 9@%WW 	>:nn=== 9?VV 	f:nya/@/@/@@.S\bcSdSdSdBdeee94eR]KK 	f:nya/@/@/@@.S\bcSdSdSdBdeee 9@%WW 	h:nyq/A/A/AA>T]deTfTfTfCfggg95ubmLL 	h:nyq/A/A/AA>T]deTfTfTfCfggg 9A5"-XX 	h:nyb/A/A/AA>T]ceTfTfTfCfggg96r}MM 	i:nyc/B/B/BBNU^dfUgUgUgDghhh 9xM
 
 	@
 #YN4J4J4L4Lq4P%Q%Q%QQE:eUYA->->->%>??? 9kM
 
 	*
 #**q*11E)++++CKKAK&&E:eS))) 9sM
 
 	L
 "&*D:htQ22HT2r4J4JKKK 9 RM
 
 		<
 -4466:a?N""!" 9.#A#A#AAC:c3):):):#:;;; 56=>)*()#$+,./&'8979+-AC
 
 #1"6"6"8"8 		. 		.GYI=W===ubmTTE .5;;q>>** y!44??"4R00CC"4Q::YA=N=N=NNC!z%-----. tr   r+   r,   )r   r   r   r   r1   r&   r   r   r    r*   r
   r\   r   r   r   r.   r.   M   s        
 
" " "( ( ( (Bo BoS Bo(T/ Bo] Bo Bo Bo BoHwS w( wGY\`G` w w w w w wr   r.   c                       e Zd ZdZddedefdZdd	Zd
 Zdedede	dz  fdZ
ddededz  defdZd Zdedede	dz  fdZdS )TransformerQueryAnalyzera#  
    Query analyzer using T5-based generative models.

    Uses T5 to convert natural language temporal expressions into structured
    date ranges without pattern matching or regex.

    Performance:
    - ~30-80ms on CPU, ~5-15ms on GPU
    - Model size: ~80M params (~300MB download)
    google/flan-t5-smallcpu
model_namedevicec                 >    || _         || _        d| _        d| _        dS )a^  
        Initialize T5 query analyzer.

        Args:
            model_name: Name of the HuggingFace T5 model to use.
                       Default: google/flan-t5-small (~80M params, ~300MB download)
                       Alternative: google/flan-t5-base (~1GB, more accurate)
            device: Device to run model on ("cpu" or "cuda")
        N)r   r   _model
_tokenizer)r   r   r   s      r   r1   z!TransformerQueryAnalyzer.__init__5  s$     %r   r   Nc                    | j         dS 	 ddlm}m} n# t          $ r t	          d          w xY wt
                              d| j         d           |                    | j                  | _	        |                    | j                  | _         | j         
                    | j                   | j                                          t
                              d           dS )z*Load the T5 model for temporal extraction.Nr   )AutoModelForSeq2SeqLMAutoTokenizerz`transformers is required for TransformerQueryAnalyzer. Install it with: pip install transformerszLoading query analyzer model: z...zQuery analyzer model loaded)r   transformersr   r   ImportErrorr^   infor   from_pretrainedr   tor   eval)r   r   r   s      r   r&   zTransformerQueryAnalyzer.loadD  s    ;"F	IIIIIIIII 	 	 	r  	
 	IT_IIIJJJ'77HH+;;DOLLt{###122222s    .c                 .    |                                   dS )z>Lazy load the T5 model for temporal extraction (calls load()).N)r&   r   s    r   _load_modelz$TransformerQueryAnalyzer._load_modelW  s    		r   r'   r(   c                 x   ddl }|                                }dt          dt          ffd}dt          dt          dt          fd} |j        d	|          rt          d
          z
  } |||          S  |j        d|          rEt                                          dz             z
  } |||t          d          z             S  |j        d|          rK                    d
          }	|	t          d
          z
  }
|
                    d
          } |||
          S  |j        d|          r4j	        d
z
  } |t          |d
d
          t          |dd                    S  |j        d|          r( |d          } |||t          d
          z             S dd
dddddd}|
                                D ]3\  }} |j        d| d|          r ||          } |||          c S 4d
dddddddddddd }|
                                D ]\  }} |j        d| d!|          }|rt          |                    d
                    }|dk    rd}n*t          ||d
z   d
          t          d
          z
  j        } |t          ||d
          t          |||                    c S dS )"z
        Extract temporal expressions using rule-based patterns.

        Handles common patterns reliably and fast. Returns None for
        patterns that need model-based extraction.
        r   Nr   r   c                 n                                     | z
  dz  }|dk    rd}t          |          z
  S Nr|   r   rs   r   r   r   days_agor(   s     r   get_last_weekdayzFTransformerQueryAnalyzer._extract_with_rules.<locals>.get_last_weekdayf  B    &..007:a?H1}}!I8$<$<$<<<r   rj   rk   c           	          t          |                     dddd          |                    dddd                    S rm   rn   ro   s     r   rp   z@TransformerQueryAnalyzer._extract_with_rules.<locals>.constraintl  rq   r   z\byesterday\brr   rs   z\blast\s+week\br|   r}   z\blast\s+month\br~   z\blast\s+year\br   r   z\blast\s+weekend\bru   rv   rJ   r   )mondaytuesday	wednesdaythursdayfridaysaturdaysundayz	\blast\s+z\br   r   r   r   )januaryfebruaryrH   aprilr@   junejulyaugust	septemberoctobernovemberdecemberz\s+(\d{4})\b)r   rK   r   r   r
   r   r   r   ra   r   r   r   r   )r   r'   r(   r   rb   r   rp   r   rj   r   rk   yrB   weekdaysnamenummonthsr   r   last_days     `                 r   _extract_with_rulesz,TransformerQueryAnalyzer._extract_with_rules[  s    				kkmm	=c 	=h 	= 	= 	= 	= 	= 	=	h 	X 	:L 	 	 	 	 29%{33 	$!2!2!22A:a### 29'55 	@"YN4J4J4L4Lq4P%Q%Q%QQE:eUYA->->->%>??? 29(+66 	*"**q*11E)++++CKKAK&&E:eS))) 29'55 	F#a'A:hq!Q//!R1D1DEEE 29*K88 	<""1%%C:c3):):):#:;;;  AA1XYghtuvv!)) 	( 	(ID#ry.d...<< ($$S))!z!Q'''''( 
 
   	Y 	YID#BI8D888+FFE Y5;;q>>**"99!HH (sQw : :YA=N=N=N NSH!z(4a"8"8(4h:W:WXXXXXY tr   c                     t          j                                         |          }|t          |          S                                   dt
          dt           ffd}t          d          z
  } |d          }d	                    d
           d|                    d
           d|                    d
           d|                    d
           d|                    d
           d| d}                     |ddd          } fd|	                                D             } 
                                5    j        j        di |ddddd}	ddd           n# 1 swxY w Y    j                            |	d         d                                          }                     |          }
t          |
          S )a  
        Analyze query for temporal expressions.

        Uses rule-based extraction for common patterns (fast & reliable),
        falls back to T5 model for complex/unusual patterns.

        Args:
            query: Natural language query
            reference_date: Reference date for relative terms (defaults to now)

        Returns:
            QueryAnalysis with temporal_constraint if found
        Nr7   r   r   c                 n                                     | z
  dz  }|dk    rd}t          |          z
  S r   r   r   s     r   r   z:TransformerQueryAnalyzer.analyze.<locals>.get_last_weekday  r   r   rr   rs   ru   z	Today is r   zR. Extract date range or "none".

June 2024 = 2024-06-01 to 2024-06-30
yesterday = r   z
last Saturday = z
what is the weather = none
z =pti   T)return_tensors
max_length
truncationc                 L    i | ] \  }}||                     j                  !S r   )r   r   )rM   kvr   s      r   
<dictcomp>z4TransformerQueryAnalyzer.analyze.<locals>.<dictcomp>  s-    BBB41a!QTT$+&&BBBr   ry   rJ   Fg      ?)max_new_tokens	num_beams	do_sampletemperaturer   )skip_special_tokensr   )r   r[   r   r    r   r   r   r   r   r   _no_gradr   generatedecodestrip_parse_generated_output)r   r'   r(   resultr   	yesterdaylast_saturdaypromptinputsoutputstemporals   ` `        r   r*   z TransformerQueryAnalyzer.analyze  s    !%\^^N ))%@@ V<<<< 		=c 	=h 	= 	= 	= 	= 	= 	= #YA%6%6%66	((++~66zBB   
++  2;1C1CJ1O1O  ''
33	  :G9O9OPZ9[9[	     Y]^^BBBB6<<>>BBB]]__ 	w 	w*dk*vvVvBRS_druvvvvG	w 	w 	w 	w 	w 	w 	w 	w 	w 	w 	w 	w 	w 	w 	w ''
'MMSSUU //GG::::s   E--E14E1c                 t    	 ddl }|                                S # t          $ r ddlm}  |            cY S w xY w)z"Get torch.no_grad context manager.r   N)nullcontext)torchno_gradr   
contextlibr   )r   r   r   s      r   r   z!TransformerQueryAnalyzer._no_grad  s]    	!LLL==??" 	! 	! 	!......;==   	!s    77r   c                 N   |r(|                                                                 dv rdS 	 ddl}d} |j        |||j                  }|r|                    d          }|                    d          }t          j        |d          }t          j        |d          }	|                    dddd          }|	                    d	d
d
d          }	|	|k     r"t          
                    d| d|	            dS t          ||	          S n# t          t          f$ r Y dS w xY wdS )a9  
        Parse T5 generated output into TemporalConstraint.

        Expected format: "YYYY-MM-DD to YYYY-MM-DD"

        Args:
            result: Generated text from T5
            reference_date: Reference date for validation

        Returns:
            TemporalConstraint if valid output, else None
        )nonenullnoNr   z.(\d{4}-\d{2}-\d{2})\s+to\s+(\d{4}-\d{2}-\d{2})rr   rv   r   rR   rW   rX   rY   zInvalid date range: r   rZ   )rK   r   r   r   r   r   r   strptimera   r^   r_   r
   
ValueErrorAttributeError)
r   r   r(   r   r   r   	start_strend_strr   r   s
             r   r   z0TransformerQueryAnalyzer._parse_generated_output  s_     	--//3III4	IIIGGBIgvr}==E T!KKNN	++a..%.y*EE
#,WjAA (//QqXY/ZZ
#++BrW]+^^ j((NN#T*#T#T(#T#TUUU4)Z(SSSS!T$ N+ 	 	 	44	 ts   CD ;D D"!D")r   r   r+   r,   )r   r   r   r   r   r1   r&   r   r   r
   r   r    r*   r   r   r   r   r   r   r   )  s       	 	 3     3 3 3 3&  R Rh RK]`dKd R R R Rh7; 7;S 7;(T/ 7;] 7; 7; 7; 7;r	! 	! 	!,c ,8 ,PbeiPi , , , , , ,r   r   )r   loggingr   abcr   r   r   r   pydanticr   r   	getLoggerr   r^   r
   r    r$   r.   r   r   r   r   <module>r      su     				 # # # # # # # # ( ( ( ( ( ( ( ( % % % % % % % %		8	$	$a a a a a a a a	 	 	 	 	I 	 	 	    C   BY Y Y Y Ym Y Y Yxv v v v v} v v v v vr   