
    Ljh              	      8   d Z ddlmZ ddlZddlZddlZddlZddlZddlmZm	Z	 ddl
mZ ddlZddlmZ ddlmZmZmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlZej@                  jC                  ej@                  jE                  e#            Z$ eej@                  jK                  e$d              ejL                  dd      Z' ejL                  dd      Z(dZ)dZ*ddddZ+d Z, e- ejL                  dd            Z.ej@                  jK                  e$d      Z/ ej`                  ejb                  d    ejd                  d            Z3 ejh                  d ejj                        Z6d! Z7 ejp                   e9ej@                  jK                  e/d"                  D  ci c]  } | d#   | 
 c} Z: ejp                  ej@                  jK                  e/d$            Z;e;d%   Z<e;d&   Z=e=D cg c]  }e: e>|         d'    c}Z?e=D cg c]  }e: e>|         j                  d(d)       c}ZA ejh                  d*      ZBd+ ZCd, ZD eD       ZEdfd-ZFd.ZGd/d0d1id0d2id1d3d4d1d3d4d5d0d6id3d7d8d9d:gd;ZH ed<=      ZIejb                  j                  d>d?      ZJejb                  j                  d@d?      ZK ed?dAB      fdgdCZL G dD dEe      ZM G dF dGe      ZN G dH dIe      ZOdJ ZPdK ZQdL ZRdde*fdMZSdN ZTdO ZUeIj                  eJ dP      dQ        ZVeIj                  eJ dR eeL      gS      dhdT       ZXeIj                  eJ dU eeL      gS      didV       ZYeIj                  eJ dW eeL      gS      dX        ZZeIj                  eJ dY eej@                  jK                  e$dZ      [      dZ\       eIj                  eJxs d]      d^        Z\eIj                  eJ d_      d`        Z]e^dak(  rddl_Z_ e_j                  dbdcdde       yyc c} w c c}w c c}w )juu  
QuitSure AI Support — API service.

One stateless endpoint the app frontend calls. Given a user message (+ optional history),
returns an answer grounded ONLY in the curated knowledge base, plus an escalation decision
so the devs know when to hand the chat to a human coach (in Freshchat).

Never connects to Freshchat. Never learns from coach transcripts (Ram's call).
Design rationale: docs/DESIGN.md   Frontend contract: docs/API.md

Run:
    python3 scripts/build_kb.py && python3 scripts/build_index.py   # one-time / on KB change
    uvicorn app:app --port 8082
A simple test chat UI is served at  http://localhost:8082/
    )annotationsN)datetimetimezone)Optional)load_dotenv)DependsFastAPIHeaderHTTPException)FileResponse)StaticFiles)	BaseModel)genai)typesz.envGEMINI_MODELzgemini-2.5-flashGEMINI_EMBED_MODELzgemini-embedding-001i      zDQuitSure Original, the 6-day intensive program (users quit on Day 6)zCQuitSure Relaxed, the 42-day gradual program (users quit on Day 42)zLeansure, the fitness program)P3P9P11c                6    | sy| j                         }|dv r|S y)ae  The KB tags smoking content as either Original (P3) or Relaxed (P9). P9/LTP is the ONLY
    42-day Relaxed program; every other smoking program (P1, P2, P4, P5, P7...) is a 6-day
    Original-style program, so it maps to P3 for both retrieval filtering and naming. P11 is
    Leansure (separate). Keeps a P1/P5 user from seeing none of the Original answers.N)r   r   r   )upper)codecs     '/var/www/python/quitsure-support/app.pycanonical_programr   7   s%    
 

AM    RETRIEVAL_FLOORz0.55dataGEMINI_API_KEYi N  )timeout)api_keyhttp_optionsuo  suicid|kill(?:ing)? myself|end(?:ing)? my life|hurt(?:ing)? myself|harm(?:ing)? myself|self.?harm|want to die|wanna die|don.?t want to live|no reason to live|end it all|take my (?:own )?life|khud ?kushi|khud.?khushi|aatmahatya|atmahatya|marna chaht|mar jana chaht|jeena nahi|jina nahi|jeene ka mann nahi|mujhe (?:ab )?jeena nahi|ab nahi jeena|khud ?ko ?khatam|khud ?ko ?maar|khud ?ko ?nuksan|jaan de ?d|jaan deni|zindagi khatam|आत्महत्या|खुदकुशी|मरना चाहत|जीना नहीं|खुद को खत्म|खुद को मार|जान दे|जान दूंc                    t        j                  d| t         j                        ryt        t        j                  |             S )Nz"smok\w*\s+(?:to|and)\s+hurt myselfF)researchIbool_CRISIStexts    r   	is_crisisr,   _   s0     
yy6bddCt$%%r   zkb.jsonidz	index.npzvectorsidsprogramsplatformallz	[a-z0-9]+c                H    t         j                  | j                               S N)	_TOKEN_REfindalllowerr*   s    r   _tokr8   u   s    TZZ\**r   c                 4   d t         D        D  cg c]F  } t        dj                  | d   | j                  dd      | j                  dd      | d   g            H }} t	        |      }t        j                  |D cg c]  }t	        |       c}t
        j                        }|rt        |j                               nd	}i }|D ]*  }t        |      D ]  }|j                  |d
      dz   ||<    , |j                         D ci c]*  \  }}|t        j                  d||z
  dz   |dz   z  z         , }	}}|D 
cg c]  }
i  }}
t        |      D ]*  \  }}|D ]   }||   j                  |d
      dz   ||   |<   " , ||	||dS c c} w c c}w c c}}w c c}
w )Nc              3  @   K   | ]  }t         t        |           y wr4   )KBint).0is     r   	<genexpr>z_build_bm25.<locals>.<genexpr>{   s     4QbQj4s    questiontopic tagsanswerdtype        r      g      ?)tfidfdlavgdl)	INDEX_IDSr8   joingetlennparrayfloat32floatmeansetitemsmathlog	enumerate)edocsndrL   rM   dftr   rK   _rJ   js                r   _build_bm25rd   y   s   4)46 1Z=!%%*<aeeFB>OQRS[Q\]^_ 6D 6D	A	4(a3q6(

	;B !E"'')sE	B %Q 	%AFF1aL1$BqE	%% CE((*
M$!Q1dhhqAECKAG4455
MC
M	"	B	$ +1 	+A!uyyA*BqE!H	++ SU;;6 ) N	s   AF;F
/F;	Fc                   t        t        |             }t        d   t        d   t        d   t        d   f\  }}}}t        j                  t        |      t        j                        }t        t        |            D ]c  }	|d|z
  ||r||	   |z  ndz  z   z  }
d}|D ]=  }||	   j                  |      }|s||j                  |d      ||dz   z  z  ||
z   z  z  }? |||	<   e |S )zOOkapi BM25 score of the query against every indexed doc (aligned to INDEX_IDS).rJ   rK   rL   rM   rF   rI   rH   )	rW   r8   _BM25rR   zerosrQ   rT   rangerP   )queryk1bqrJ   rK   rL   rM   scoresrc   normsra   fs                 r   bm25_scoresrq      s    DKAteElE$KwOBRXXc"gRZZ0F3r7^ QUQ5"Q%%-cBBC 	CA1		!ASWWQ_R!V5TBB	C q	 Mr   aC  You are the QuitSure Assistant, an automated support assistant inside the
QuitSure smoking-cessation app. You are NOT a human and NOT a named coach, never claim to be.
Never output placeholders or merge-fields (e.g. %name%, ____).
Never use em-dashes or en-dashes in your replies. Use commas, periods, or parentheses instead.
Your ONLY job is to help with: the QuitSure app and programs, the user's quit-smoking journey,
and their subscription / billing / account. Nothing else.

TONE: Be warm, encouraging, and human, like a caring quit-smoking coach who is genuinely on the
user's side. Acknowledge how they feel, celebrate their effort, and be patient and reassuring.
Sound friendly and natural, never robotic, curt, or clinical. You may rephrase for warmth, but
never add any fact, step, price, or policy that is not in the approved answers.
Even for simple or factual questions (how to log out, gift cards, a tech step), keep a warm human
touch, a short kind opener or closer. Never give a cold one-line answer.

LANGUAGE: Reply in the SAME language and script the user writes in. If they write in Hinglish
(romanized Hindi mixed with English, in Latin script), reply in that same natural romanized Hinglish
style, NOT in pure English and NOT in Devanagari Hindi. If they write in Devanagari Hindi, reply in
Hindi. Keep the exact approved facts, steps, and links, just expressed in their language.

Answer ONLY from the APPROVED ANSWERS provided below. Match their warm, supportive tone.
Never invent facts, prices, steps, or policies that are not in the approved answers.

Decide in this order:
1. OFF-TOPIC / time-pass: if the message is NOT about QuitSure, quitting smoking, the app, or the
   user's account (e.g. general knowledge, news, sports, math, coding, jokes, weather, recipes,
   casual chit-chat), do NOT answer it. Give a brief, friendly one-line redirect to what you can
   help with. -> escalate=false, escalate_reason="out_of_scope". Do NOT send these to a coach.
2. Otherwise set escalate=true when ANY of these is true:
   - It IS about QuitSure but the approved answers don't contain the info -> "no_confident_answer"
   - Medical/clinical questions -> "medical_topic", UNLESS the approved answers directly cover the
     question, in which case answer from that approved content (e.g. an approved answer about using
     Champix or nicotine substitutes with the program). Escalate a medical question only when the
     approved answers do NOT cover it (e.g. personal dosing or a drug interaction we have no answer for).
     Normal quit-smoking experiences (irritability, cravings, sleep, mood, appetite) are not medical
     and may be answered warmly.
   - Self-harm, suicidal thoughts, or crisis -> "crisis"
   - The user explicitly asks for a human / coach / agent -> "user_requested"
   - The user is clearly frustrated or angry -> "user_frustrated"
   - Needs a human to look up or fix THIS user's specific account state: charged but subscription
     not active, "I paid but no access", "where is my refund" / refund requested but not received,
     a double charge -> "account_action". (General billing questions, and how to REQUEST a refund
     or "I want a refund", are ANSWERED from the approved refund process, not escalated. Only a
     refund STATUS problem that needs a human to check the account is escalated.)
3. Otherwise, answer directly from the approved answers.

ANSWER BEFORE YOU ESCALATE: if the approved answers contain concrete steps that would resolve the
user's issue, GIVE those steps rather than escalating, even if the message also sounds discouraged,
upset, or emotional. Many complaints that sound emotional are really technical/account issues with a
fix in the approved answers (e.g. "I lost all my progress", "my days reset", "everything is gone",
"it logged me out") -> give the recovery steps first (you may briefly acknowledge the feeling), and
only escalate if the steps do not cover their situation.

Questions about how QuitSure works, how effective it is, or how it compares to willpower, nicotine
patches, or other methods ARE covered by the approved answers (how it works, how it helps, how it is
different). Answer these from that content, do not escalate them.

CONTINUITY: Use the whole conversation, including your own previous replies. If the user sends a
short reply that continues the current topic (e.g. "yes", "sure", "help me", "ok", "tell me more",
"which one") or accepts an offer you just made, keep helping using what has already been discussed
and the approved answers. Do NOT escalate a simple continuation, and never offer help and then hand
off instead of giving it. Only escalate when the user genuinely needs information not covered.
If the user asks which option or program suits them or asks you to help them decide, HELP them like
a coach: briefly ask about the concrete factors that actually decide it (how much time they can give
each day, how soon they want to quit), then RECOMMEND the program that fits and say why, using the
approved answers. Do not just ask them to pick a pace or bounce the choice back to them. That is
grounded help, not a reason to escalate.

MULTI-PART QUESTIONS: If the user asks several things at once, answer every part you can from the
approved answers. Escalate ONLY if a specific part genuinely needs a human (an account lookup or a
medical topic), and even then, answer the other parts first and tell the user which one part you are
passing to the team. Never escalate the whole message just because one part needs a human, and never
invent an answer for a part the approved answers do not cover.

USER CONTEXT: If a USER CONTEXT block is provided (the user's program, current day, subscription
status), treat those facts as true and use them to answer questions about the user's own account or
progress directly, e.g. "am I subscribed" -> use subscription status, "what day am I on" -> use the
day. Only escalate account PROBLEMS that need a human to fix or look up (a specific charge, a refund
to process, a payment not reflecting), not simple status questions you already have the answer to.

IMPORTANT: Whatever the approved answers cover, you SHOULD answer, including medical questions the
approved answers address (e.g. using Champix or nicotine substitutes with the program, common
symptoms the doc explains). Escalate only what the approved answers do NOT cover, plus these
always-escalate cases even if related content exists: self-harm or crisis, an explicit request for a
human, and account-specific payment/refund problems for this user.

If the user greets you (hi/hello), thanks you, or makes small talk, reply warmly in one line as the
QuitSure Assistant and invite their question, and set escalate=false with escalate_reason "greeting".
Do NOT mention coaches or escalation unprompted, only at the moment you actually need to hand off.
When escalating: a short warm handoff line as "answer" (e.g. "Let me get a member of our support
team to help you with this.") plus a one-sentence "coach_summary". For "crisis", gently encourage
immediate help and that someone from the team is coming.

In "used_ids", list the id number(s) of the APPROVED ANSWERS you actually drew on to write your
answer (from the "[id N | ...]" labels). Leave it empty for greetings, off-topic declines, and
escalations where you used none.

Respond ONLY as JSON: {"answer": str, "escalate": bool, "escalate_reason": str|null, "coach_summary": str|null, "used_ids": int[]}
objecttypestringbooleanT)rs   nullablerS   integer)rs   rX   rv   )rE   escalateescalate_reasoncoach_summaryused_idsrE   rx   )rs   
propertiesrequiredzQuitSure AI Support)titleMOUNT_PREFIXrC   API_KEYz	X-API-Key)defaultaliasc                >    t         r| t         k7  rt        dd      y y )Ni  zinvalid or missing API key)status_codedetail)r   r   )	x_api_keys    r   require_keyr     s!    9'4PQQ (wr   c                  "    e Zd ZU ded<   ded<   y)Turnstrroler+   N)__name__
__module____qualname____annotations__ r   r   r   r     s    
I
Ir   r   c                  z    e Zd ZU dZded<   ded<   g Zded<   dZded<   dZded	<   dZded
<   dZ	ded<   dZ
ded<   y)ChatRequestNOptional[str]user_idr   messagez
list[Turn]historyprogramr1   localezOptional[int]program_daysubscription_status)r   r   r   r   r   r   r   r1   r   r   r   r   r   r   r   r   "  sN    !G]!LGZ!G]!"Hm" FM !%K%)--r   r   c                  V    e Zd ZU dZded<   dZded<   ded<   ded<   ded<   dZded	<   y)
FeedbackNr   r   
message_idr   r   rE   ratingnote)r   r   r   r   r   r   r   r   r   r   r   r   -  s/    !G]! $J$LKKD-r   r   c                 d    t        j                  t        j                        j	                         S r4   )r   nowr   utc	isoformatr   r   r   _nowr   6  s    <<%//11r   c                J   t         j                  j                  t        | gt	        j
                  dt                    }t        j                  |j                  d   j                  t        j                        }t        j                  j                  |      }|r||z  S |S )NRETRIEVAL_QUERY)	task_typeoutput_dimensionalitymodelcontentsconfigr   rF   )clientmodelsembed_contentEMBED_MODELr   EmbedContentConfigDIMrR   asarray
embeddingsvaluesrT   linalgrn   )r+   respvr^   s       r   embed_queryr   :  s}    ==&&''2C[^_ ' D
 	

4??1%,,BJJ?A
		qA1q51r   c                <   | j                   D cg c]  }|j                  dk(  s|j                    c}dd }| j                   D cg c]!  }|j                  dk(  s|j                  dd # c}dd }dj                  ||z   | j                  gz         S c c}w c c}w )z`Anchor retrieval to the recent context so short follow-ups ('sure', 'which one?') retrieve well.userN	assistant   r@   )r   r   r+   rO   r   )reqra   recent_userlast_assistants       r   retrieval_queryr   E  s    #&;;Ca!&&F2B166CBCHK,/KKQq166[;PaffTclQRTRUVN88K.0CKK=@AA DQs   BBBBc                   t        |      }t        |       }t        |z  g }t        t	                    D ]G  }|rdt
        |   vr|t
        |   vr|rt        |   dk7  rt        |   |k7  r7|j                  |       I |sg dfS t        |       t        |fd      }t        fd|D        fd      }d}	|D ci c]  }|d c}t        |      D ]  \  }
}|xx   d|	|
z   z  z  cc<    t        |      D ]  \  }
}|xx   d|	|
z   z  z  cc<    t        |fd	      d | }|D cg c])  }t        t        t        |            t        |         f+ }}t        t        fd
|D                    }||fS c c}w c c}w )Nr2   rH   c                    |     S r4   r   )r>   simss    r   <lambda>zretrieve.<locals>.<lambda>^  s    d1gX r   )keyc              3  4   K   | ]  }|   d kD  s|  yw)r   Nr   )r=   r>   bms     r   r?   zretrieve.<locals>.<genexpr>_  s     6ABqEAIa6s   c                    |     S r4   r   )r>   r   s    r   r   zretrieve.<locals>.<lambda>_  s    r!uf r   <   g      ?c                    |     S r4   r   )r>   fuseds    r   r   zretrieve.<locals>.<lambda>f  s    q	 r   c              3  (   K   | ]	  }|     y wr4   r   )r=   r>   r   s     r   r?   zretrieve.<locals>.<genexpr>j  s     .T!W.s   )r   r   
INDEX_VECSrh   rQ   INDEX_PROGRAMSINDEX_PLATFORMappendrq   sortedr[   r;   r<   rN   rU   max)ri   r   r1   kqvallowedr>   cos_rankbm_rankrrf_krtophitsbestr   r   r   s                 @@@r   retriever   L  s   (G	U	B?D G3t9 uN1$55'XYIZ:Zq)U2~a7HH7Tq 3w 
U	Bg#56H66<LMGE$%QV%E(# &1aC519%%&'" &1aC519%%&
1
22A
6C=@ARIaL!"E$q'N3ADA .g../D: & Bs   
F3.F	c                2    dj                  d | D              S )N

c           
   3  d   K   | ](  \  }}d |d    d|d   xs |d    d|d    d|d     * y	w)
z[id r-   z | rB   sourcez]
Q: rA   z
A: rE   Nr   )r=   r\   rb   s      r   r?   z build_context.<locals>.<genexpr>o  sR      Aq qwis1W:485VAjM?%PQRZP[}]s   .0)rO   )r   s    r   build_contextr   n  s     ;;   r   c                    t        j                         j                  dd | d<   | j                  d      sd| d<   n| j                  d      dv rdnd	| d<   | j                  d
      r| d
   dd | d
<   | S )zSAdd a message id (for feedback linking) and a suggested channel; cap coach_summary.N   r   rx   suggested_channelry   )account_actionservice_error	technicalcoachingrz   i,  )uuiduuid4hexrP   )outs    r   	_finalizer   u  s    

(("-C77:#' 3677;L3MQt3tK)3 	 
ww"?3DS9OJr   z/healthc                 :    dt        t              t        t        dS )Nok)status
kb_entriesr   retrieval_floor)rQ   r;   ANSWER_MODELr   r   r   r   healthr     s    #b'L.0 0r   z/chat)dependenciesc                	   t        | j                        rut        dddd| j                   g d      }t        j                  |d   t               | j                  | j                  | j                  | j                  ddd|d	   

       |S 	 | j                  xs d}t        |       }t        ||| j                        \  }}| j                  r:t        | j                  || j                        \  }}||kD  r||| j                  }}}g }| j                  r|j                  d| j                   d       t        j                  t!        |      |      }	|j                  d|	 d       | j"                  |j                  d| j"                   d       | j$                  r|j                  d| j$                   d       |rddj'                  |      z   dz   nd}
dj'                  d | j                  dd  D              d| j                   z   }|
 dt)        |       d| }t*        j,                  j/                  t0        |t3        j4                  t6        dt8        d       !      }t;        j<                  |j>                        }|jA                  d"d        |jA                  d#d        |j                  d"      d$k(  rd%|d&<   d'}|d&    xr |j                  d"      |v}|r.|tB        d(z   k  r"|jE                  dd)d*d+| j                   ,       |d&   s|j                  d"      |vr|D ci c]  \  }}|tB        kD  s|d-   | }}}|j                  d.      xs g D cg c]  }||v s||    }}|s%|r#tG        tI        |jK                                     g}|D cg c]  }|d/    d0|d1     c}|d2<   ng |d2<   t        |      }t        j                  |d   t               | j                  | j                  | j                  | j                  ||d3tM        |d&         |d"   |d	   4       |S c c}}w c c}w c c}w # tN        $ r}t        d5dd6d7| j                   g d      }t        j                  |d   t               | j                  | j                  | j                  | j                  d8dd6|d	   

       |cY d }~S d }~ww xY w)9Na  I'm really glad you reached out, and you don't have to go through this alone. Let me connect you with a member of our team right now. If you need immediate support, please reach out to a helpline. In India you can call Tele-MANAS at 14416 (free, 24x7) or AASRA at +91 9820466726. If you are outside India, please contact your local emergency number or a nearby suicide-prevention helpline. You matter, and help is available.TcrisiszCRISIS / self-harm signal: )rE   rx   ry   rz   sourcesr   crisis_filterrI   rE   )
r   tsr   r   r1   r   gaterx   ry   rE   r   )r   r1   zUser's app language: z (reply in this language).zUser's program: zK. An approved answer written for this program by name applies to this user.zUser is on day z of the program.zUser's subscription: .zUSER CONTEXT:

r   rC   c              3  p   K   | ].  }|j                   j                          d |j                   d 0 yw)z: r  N)r   r   r+   )r=   ra   s     r   r?   zchat.<locals>.<genexpr>  s,     RA166<<>*"QVVHB7Rs   46izUSER: zAPPROVED ANSWERS:
z

---
CONVERSATION:
zapplication/jsong?)system_instructionresponse_mime_typeresponse_schematemperaturer   ry   rz   out_of_scopeFrx   )r  greetingg?no_confident_answerz>Let me get a member of our support team to help you with this.zUser asked: )rx   ry   rE   rz   r-   r{   r   z / rA   r   r   )r   r   r   r   r1   r   r   best_simr   rx   ry   rE   zWI'm having a bit of trouble right now, so let me get someone from our team to help you.r   zService error while handling: error)(r,   r   r   dblog_chatr   r   r   r1   r   r   r   r   r   PROGRAM_NAMESrP   r   r   r   rO   r   r   r   generate_contentr   r   GenerateContentConfigSYSTEM_RULESRESPONSE_SCHEMAjsonloadsr+   
setdefaultr   updatenextiterr   r<   	Exception)r   r   eff_programrqr   r
  hits_mbest_mctxpnamectx_strconvopromptr   exemptansweredr\   ro   abover>   pickeds                        r   chatr'    s     $l &*h,G}*Ubdf g 	s<0TVS[[Z]ZeZe,,/\]!)#h-	A 
T kk)TS!!"kCLLQh ;;%ckk;QTQ]Q]^NFF %+VS[[h ::szz$9#**E_"`a!!"3K"@+N

%eW -+ , 	-??&

_S__DUUe3f(g""CJJ1FsG^G^F__`/a$bCF$tyy~5>B RRSAQRRW]^a^i^i]jUkk9/d0C/DD\]b\cd}}--..#/#5 /	 . 	
 jj#($/- 77$%7#C
O
 .:&S3773D+EV+S?T#99JJ6K^'3CKK=%A  C :377+<#=V#K,0HDAqA4GQtWaZHEH),)<)BR1qEzeAhRFRetELLN345JPQQ8S:@QC	NC	Nn
s<0TVS[[Z]ZeZe,,RZbC
O(<cRcNdH	' 
 IR R  	 $;%)o,J3;;-*Xegi j 	s<0TVS[[Z]ZeZe,,'TU!0X	H 
	sW   J!Q -P2?P2Q !	P8+P82-Q P=3A>Q 2Q 	S
A4S?S
S
z	/feedbackc                    t        j                  t               | j                  | j                  | j
                  | j                         ddiS )Nr   r   )r  log_feedbackr   r   r   r   r   )fbs    r   feedbackr+    s3    OODFBMM2::ryy"''Jdr   z/statsc                 *    t        j                         S r4   )r  	get_statsr   r   r   statsr.    s    <<>r   z/staticstatic)	directory)name/c                 ^    t        t        j                  j                  t        dd            S )Nr/  z
index.htmlr   ospathrO   ROOTr   r   r   homer8    s    T8\BCCr   z
/analyticsc                 ^    t        t        j                  j                  t        dd            S )Nr/  zanalytics.htmlr4  r   r   r   	analyticsr:    s    T85EFGGr   __main__zapp:appz0.0.0.0i  )hostport)g      ?g      ?)r   r   )r   r   )r*  r   )a__doc__
__future__r   r  rY   r5  r%   r   r   r   typingr   numpyrR   dotenvr   fastapir   r	   r
   r   fastapi.responsesr   fastapi.staticfilesr   pydanticr   googler   google.genair   r  r6  dirnameabspath__file__r7  rO   getenvr   r   r   TOP_Kr  r   rU   r   DATAClientenvironHttpOptionsr   compiler'   r)   r,   loadopenr;   _idxr   rN   r<   r   rP   r   r5   r8   rd   rf   rq   r  r  appr   r   r   r   r   r   r   r   r   r   r   r   r   postr'  r+  r.  mountr8  r:  r   uvicornrun)r\   r>   s   00r   <module>r[     si   #   	 	  '    ; ; * +    		wwrwwx01 BGGLLv& 'ryy);<bii,.DE
	 Q
O*
 			"3V<=	ww||D&!	bjj)9:#45#4#4U#C
E "**K DD
& $$))DdI)F$GHIQagqjIrwwrww||D+./)_
K	2;<Q"SV*Z(<=FG"SV*..U3G
 BJJ|$	+<$ 	aH 8$Y'$,$?"*=$	/BPTU :&
 )*
 zz~~nb1 **..B
' "(+!F R
9 
.) .y 2B !45 D
 L>	!"0 #0
 \N%
 0D/EFd GdN \N)
$GK4H3IJ K
 L>	 0D/EF G
 		\N'
"K"'',,tX:V$W^f	 g 	D D L>	$%H &H zGKK		5 E J
 =Gs   'P1P"P