Ë
    VK­jv!  ã            	      ó8  — d Z ddlmZ ddlZddlZddlmZ ddlmZ ddl	m
Z
mZ ddlmZmZ d	Zd
Zd\  ZZZdZdZ ej,                  d«      Z ej,                  de› de› d�ej0                  «      Z ej,                  de› d�ej0                  «      Z ej,                  de› d�ej0                  «      Z ej,                  dej0                  «      Z ej,                  d«      Zd d„Zd!d„Zd d„Z d"d„Z!d#d„Z"d$d„Z#d%d„Z$dddddddddœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d&d„Z%y)'aQ  Phrase suggestions for bottom lines and problem discussions.

`rebuild` splits every stored bottom line and problem discussion for a center
into sentences and writes them to `phrases` with the forecast's context
(problem types, likelihood, size, locations, date). `suggest` ranks sentences
for a draft by how closely their forecast matches it and by how often the
wording was reused across forecasts.

Danger-level words are masked to "[rating]" so a suggestion never sets the
rating for the forecaster. Imported archives are legacy-era text: descriptive
wording to borrow from, not guidance.
é    )ÚannotationsN)Údate)Ú
Connectioné   )ÚfetchallÚfetchone)Ú_jaccardÚ_season_closeness)Úbottom_lineÚproblemz[rating])é   i�  é   i N  z*(?:low|moderate|considerable|high|extreme)z.\b(?:LOW|MODERATE|CONSIDERABLE|HIGH|EXTREME)\bz\bz#(?=(?:[\s,]+(?:to|and|or|avalanche|z|\(\d\)))*[\s,]+danger\b)a$  (\bdanger\s+(?:(?:is|are|be|remains?|will|should|could|may|stays?|also|again|back|still|rated|at|near|mostly|generally|becomes?|increases?|rises?|climbs?|reach(?:es)?|decreases?|drops?|returns?|ranges?|from|to|up|down|for|today|tonight|tomorrow|quickly|slowly|gradually|likely|expected)\s+)+)z&(\[rating\],?\s+(?:to|and|or|then)\s+)z[\b(?:mt|mtn|st|hwy|approx|e\.g|i\.e|ft|vs|jan|feb|mar|apr|jun|jul|aug|sept?|oct|nov|dec)\.$u"   (?<=[.!?])\s+(?=[\"â€œ(]?[A-Z0-9])c                óÆ   — t         j                  t        | «      } t        j                  t        | «      } t        j                  d„ | «      } t
        j                  d„ | «      S )Nc                ó2   — | j                  d«      t        z   S ©Nr   ©ÚgroupÚRATING©Úms    ú(/var/www/avy-guidance/api/app/phrases.pyú<lambda>zmask_danger.<locals>.<lambda>5   s   € ¨A¯G©G°A«J¼Ñ,?€ ó    c                ó2   — | j                  d«      t        z   S r   r   r   s    r   r   zmask_danger.<locals>.<lambda>6   s   €  a§g¡g¨a£j´6Ñ&9€ r   )Ú_CAPS_LEVELÚsubr   Ú_LEVEL_BEFORE_DANGERÚ_DANGER_VERB_LEVELÚ_RATING_PAIR)Útexts    r   Úmask_dangerr!   2   sK   € Ü�?‰?œ6 4Ó(€DÜ×#Ñ#¤F¨DÓ1€DÜ×!Ñ!Ñ"?ÀÓF€DÜ×ÑÑ9¸4Ó@Ð@r   c                ón  — | sg S g }t        j                  d| j                  dd«      «      D ]…  }dj                  |j                  «       «      }d}t        j                  |«      D ]6  }|r|› d|› �n|}t
        j                  |«      rŒ$|j                  |«       d}Œ8 |sŒu|j                  |«       Œ‡ |S )Nz\n\s*\núÚ ú )ÚreÚsplitÚreplaceÚjoinÚ_SENTENCE_ENDÚ_ABBREVÚsearchÚappend)r    ÚoutÚparaÚbufÚparts        r   Úsplit_sentencesr2   9   s­   € ÙØˆ	Ø
€CÜ—‘˜ T§\¡\°$¸Ó%;Ó<ò 	ˆØ�x‰x˜Ÿ
™
›Ó%ˆØˆÜ!×'Ñ'¨Ó-ò 	ˆDÙ%(�S�E˜˜4˜&‘/¨dˆCÜ—>‘> #Õ&Ø—
‘
˜3”Ø‘ð		ò
 Ø�J‰J�s�Oð	ð €Jr   c                ó´   — t        j                  dd| j                  «       «      }dj                  t        j                  dd|«      j	                  «       «      S )z3Grouping key: case, digits and punctuation ignored.z\d+(?:\.\d+)?ú#r%   z[^a-z#\[\]]+)r&   r   Úlowerr)   r'   )r    Úts     r   Ú	normalizer7   J   s@   € ä
�‰Ð  d§j¡j£lÓ3€AØ�8‰8”B—F‘F˜?¨C°Ó3×9Ñ9Ó;Ó<Ð<r   c                óB  — t        «       g }}t        | «      D ]„  }t        t        |«      cxk  r	t        k  r#n n t        |j                  «       «      t        k  rŒCt        |«      }t        |«      }|sŒ\||vsŒa|j                  |«       |j                  ||f«       Œ† |S )z;Usable (text, norm) sentences from one field, deduplicated.)Úsetr2   ÚMIN_LENÚlenÚMAX_LENr'   Ú	MIN_WORDSr!   r7   Úaddr-   )r    Úseenr.   ÚsÚns        r   Úphrases_fromrB   P   sƒ   € ä“�rˆ#€DÜ˜TÓ"ò ˆÜœ#˜a›&Ô+¤GÕ+¬s°1·7±7³9«~Ä	Ò/IØÜ˜‹NˆÜ�a‹LˆÚ�˜$’Ø�H‰H�QŒKØ�J‰J˜˜1�vÕðð €Jr   c                óf  — | j                  d|f«       g }t        | d|f«      D ]D  }t        |d   «      D ]1  \  }}|j                  ||d   d|d   ddg |||d   |d   |d	   f«       Œ3 ŒF t        | d
|f«      D ]N  }t        |d   «      D ];  \  }}|j                  ||d   d|d   g|d   |d   |d   |||d   |d   |d	   f«       Œ= ŒP | j	                  «       5 }|j                  d|«       ddd«       t        |«      t        |D �ch c]  }|d   |d   f’Œ c}«      dœS # 1 sw Y   Œ6xY wc c}w )z>Replace the center's phrase library from its stored forecasts.z(DELETE FROM phrases WHERE center_id = %sa3  SELECT f.id, f.valid_date, f.source, f.guidance_era, f.bottom_line,
                  coalesce(array_agg(DISTINCT p.problem_type) FILTER (WHERE p.id IS NOT NULL), '{}') AS types
           FROM forecasts f LEFT JOIN forecast_problems p ON p.forecast_id = f.id
           WHERE f.center_id = %s GROUP BY f.idr   ÚidÚtypesNÚ
valid_dateÚsourceÚguidance_eraz÷SELECT p.forecast_id, p.problem_type, p.likelihood, p.size_max, p.locations, p.discussion,
                  f.valid_date, f.source, f.guidance_era
           FROM forecast_problems p JOIN forecasts f ON f.id = p.forecast_id WHERE f.center_id = %sÚ
discussionÚforecast_idr   Úproblem_typeÚ
likelihoodÚsize_maxÚ	locationszëINSERT INTO phrases (center_id, forecast_id, field, problem_types, likelihood, size_max, locations,
                   text, norm, valid_date, source, guidance_era)
               VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)é   é   )ÚphrasesÚdistinct)Úexecuter   rB   r-   ÚcursorÚexecutemanyr;   )	ÚconnÚ	center_idÚrowsÚfr    ÚnormÚpÚcurÚrs	            r   Úrebuildr^   ^   s¯  € à‡L�LÐ;¸i¸\ÔJØ€DÜØð	3ð 
ˆóò 
Kˆô ' q¨Ñ'7Ó8ò 	K‰JˆD�$Ø�K‰K˜ A d¡G¨]¸A¸g¹JÈÈdÐTVÐX\Ð^bØ˜<™¨!¨H©+°q¸Ñ7HðJõ Kñ	Kð
Kô Øð	gð 
ˆóò 	gˆô ' q¨¡Ó7ò 	g‰JˆD�$Ø�K‰K˜ A mÑ$4°iÀ!ÀNÑBSÐATÐVWÐXdÑVeÐghÐisÑgtØ˜;™¨¨t°Q°|±_ÀaÈÁkÐSTÐUcÑSdðfõ gñ	gð	gð 
�‰‹ð 
˜#Ø�‰ðJð ô		
÷
ô ˜4“y¬cÈÖ2NÀA°A°a±D¸!¸A¹$²<Ò2NÓ.OÑPÐP÷
ð 
üò 3Os   ÃD"ÄD.
Ä"D+c                ó�   — t        j                  d| xs dj                  «       «      d d }dj                  d„ |D «       «      xs d S )Nz	[a-z0-9]+r$   rP   z & c              3  ó&   K  — | ]	  }|› d �–— Œ y­w)z:*N© )Ú.0Úws     r   ú	<genexpr>z"_prefix_tsquery.<locals>.<genexpr>ƒ   s   è ø€ Ò. 1˜˜˜2”hÑ.ùs   ‚)r&   Úfindallr5   r)   )ÚqÚwordss     r   Ú_prefix_tsqueryrh   �   s>   € Ü�J‰J�| a¢g¨2§_¡_Ó%6Ó7¸¸Ð;€EØ�:‰:Ñ.¨Ô.Ó.Ò6°$Ð6r   c           	     ó†  — |rdt        || d   «      z  nd}|dk(  r$||rdt        |t        | d   «      «      z  z   S dz   S |r|t        |t        | d   xs g «      «      z  }|r.| d   r)|d	t        t	        |«      t	        | d   «      z
  «      z  z  }|�.| d
   �)|d	t        t        |«      t        | d
   «      z
  «      z  z  }|S )Ng      ø?rF   g        r   g       @Úproblem_typesrN   rL   gš™™™™™Ù?rM   )r
   r	   r9   ÚabsÚintÚfloat)ÚrowÚfieldrE   rL   rM   rN   rF   r@   s           r   Ú_contextrp   †   sà   € ÙBLˆÔ 
¨C°Ñ,=Ó>Ò>ÐRU€AØ�ÒØÉ�Cœ( 5¬#¨c°/Ñ.BÓ*CÓDÑDÑWÐWÐSVÑWÐWÙØ	ŒX�i¤ S¨Ñ%5Ò%;¸Ó!<Ó=Ñ=ˆÙ�c˜,Ò'Ø	ˆS”3”s˜:“¬¨S°Ñ->Ó)?Ñ?Ó@Ñ@Ñ@ˆØÐ  J¡Ð ;Ø	ˆS”3”u˜X“¬¨s°:©Ó)?Ñ?Ó@Ñ@Ñ@ˆØ€Hr   é   )rK   rj   rL   rM   rN   rF   rf   Úlimitc               óp  — ddg||g}}t        |xs g «      }|dk(  r&|h}|j                  d«       |j                  |«       n-|r+|j                  d«       |j                  t        |«      «       t        |	«      }|r"|j                  d«       |j                  |«       t	        | ddj                  |«      › d	t        › �|«      }t        |xs g «      }i }|D ]“  }t        |||||||«      }|j                  |d
   «      }|€*|d   t        «       |d   |d   t        «       |dœx||d
   <   }|d   j                  |d   «       |d   j                  |d   «       t        |d   |«      |d<   Œ• g }|j                  «       D ]h  }t        |d   «      }|j                  |d   ||d   |d   |d   dhk(  t        |d   v t        |d   dt        j                   |«      z  z   d«      dœ«       Œj |j#                  d„ ¬«       | xr t%        | d|f«       }|d t        dt'        |
d«      «       t        |«      |dœS )Nzcenter_id = %sz
field = %sr   z&problem_types @> ARRAY[%s]::smallint[]zproblem_types && %s::smallint[]z tsv @@ to_tsquery('english', %s)zˆSELECT forecast_id, problem_types, likelihood, size_max, locations, text, norm, valid_date, guidance_era
            FROM phrases WHERE z AND z  ORDER BY valid_date DESC LIMIT rZ   r    rF   rJ   )r    Úforecast_idsÚ	last_usedÚexample_forecast_idÚerasÚcontextrt   rw   rH   rx   ru   rv   Úlegacygš™™™™™é?é   )r    Úusesru   rv   ry   Ú
has_ratingÚscorec                ó   — | d    | d    fS )Nr}   r{   ra   )Úis    r   r   zsuggest.<locals>.<lambda>½   s   € ˜q ™z˜k¨A¨f©I¨:Ð6€ r   )Úkeyz2SELECT 1 FROM phrases WHERE center_id = %s LIMIT 1r   é2   )ÚitemsÚmatchedÚlibrary_empty)r9   r-   Úsortedrh   r   r)   ÚMAX_CANDIDATESrp   Úgetr>   ÚmaxÚvaluesr;   r   ÚroundÚmathÚlog1pÚsortr   Úmin)rV   rW   ro   rK   rj   rL   rM   rN   rF   rf   rr   ÚwhereÚparamsrE   ÚtsqrX   ÚlocsÚgroupsr]   ÚctxÚgr‚   rA   Úemptys                           r   Úsuggestr—   “   sy  € ð & |Ð4°yÀ%Ð6Hˆ6€EÜ�Ò# Ó$€EØ�	ÒØ�ˆØ�‰Ð=Ô>Ø�‰�lÕ#Ù	Ø�‰Ð6Ô7Ø�‰”f˜U“mÔ$Ü
˜!Ó
€CÙ
Ø�‰Ð7Ô8Ø�‰�cÔÜØð Ø '§¡¨UÓ 3Ð4Ð4TÔUcÐTdð	hàó	€Dô ˆyŠ˜BÓ€DØ €FØò .ˆÜ�q˜% ¨
°H¸dÀJÓOˆØ�J‰J�q˜‘yÓ!ˆØˆ9Ø-.¨v©YÌËÐ\]Ð^jÑ\kØ<=¸mÑ<LÔVYÓV[Ðhkñ%mð mˆF�1�V‘9Ñ à	ˆ.Ñ×Ñ˜a Ñ.Ô/Ø	ˆ&‰	�‰�a˜Ñ'Ô(Ü˜1˜Y™<¨Ó-ˆˆ)Šð.ð €EØ�]‰]‹_ò ˆÜ��.Ñ!Ó"ˆØ�‰Ø�f‘I q°q¸±~Ð^_Ð`uÑ^vØ˜‘i H :Ñ-¼VÀqÈÁyÐ=PÜ˜1˜Y™<¨#´·
±
¸1³Ñ*=Ñ=¸qÓAñ
õ 	ðð 
‡J�JÑ6€JÔ7ØˆHÒoœX dÐ,`ÐclÐbnÓoÐo€EØÐ3œS ¤C¨¨r£NÓ3Ð4ÄÀVÃÐ_dÑeÐer   )r    ÚstrÚreturnr˜   )r    ú
str | Noner™   z	list[str])r    rš   r™   zlist[tuple[str, str]])rV   r   rW   rl   r™   Údict)rf   rš   r™   rš   )rn   r›   ro   r˜   rE   zset[int]rN   zset[str]rF   údate | Noner™   rm   )rV   r   rW   rl   ro   r˜   rK   ú
int | Nonerj   zlist[int] | NonerL   r�   rM   zfloat | NonerN   zlist[str] | NonerF   rœ   rf   rš   rr   rl   r™   r›   )&Ú__doc__Ú
__future__r   r‹   r&   Údatetimer   Úpsycopgr   Údbr   r   Ú	retrievalr	   r
   ÚFIELDSr   r:   r<   r=   r†   Ú_LEVELÚcompiler   ÚIr   r   r   r+   r*   r!   r2   r7   rB   r^   rh   rp   r—   ra   r   r   ú<module>r¨      s’  ðñõ #ã Û 	Ý å ç "ß 2à	#€Ø	€Ø(Ñ €ˆ�)Ø€à	6€Øˆb�j‰jÐJÓK€à!�r—z‘zØ	ˆ&ˆÐ4°V°HÐ<UÐVÐXZ×X\ÑX\óÐ ð  �R—Z‘Zðjð 	€xˆrðð ‡D�DóÐ ð ˆr�z‰zÐCÀFÀ8È2ÐNÐPR×PTÑPTÓU€Ø
ˆ"�*‰*ÐsÐuw×uyÑuyÓ
z€Ø�—
‘
Ð@ÓA€óAóó"=óó QóF7ó

ð Y]Ø.2ÈTÐlpØ*.È$Ð`dØñ,fØ+ð,fØ@Jð,fØ]ið,fà'ð,fà<Gð,fàS]ð,fð ð,fð !%ô,fr   