ó
    ÞÃi[  ã                   ó~  • S SK JrJrJrJrJr  S SKrS SKrS SKJ	r	  S SK
Jr  S SKJrJr  S SKJrJr  S SKrS SKrS SKrS SKrS SKJr  S SKr\" 5         \" 5       r\R4                  " S5      r " S	 S
\5      r " S S\5      r\" S\R4                  " S5      S9r\R?                  \5      r \RB                  " SSS9r"\"RF                  S 5       r$\"RF                  S 5       r%S\&S\'4S jr(S\&4S jr)S\'S\*S\\&   4S jr+S\'4S jr,S\-S\&4S jr.S\'S\&4S  jr/\Ra                  S!5      \" S5      S4S"\S#\4S$ jj5       r1g)%é    )Ú	APIRouterÚ
UploadFileÚFileÚBackgroundTasksÚHTTPExceptionN)ÚHumanMessage)ÚChatGoogleGenerativeAI)Ú	BaseModelÚField)ÚListÚOptional)Úload_dotenvÚDEEPGRAM_API_KEYc                   ó>   • \ rS rSr% \\S'   \\S'   \\S'   \\S'   Srg)Ú
VideoEventé   Ú	timestampÚtaskÚdescriptionÚcategory© N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__ÚintÚ__annotations__ÚstrÚ__static_attributes__r   ó    Ú/app/src/api.pyr   r      s   ‡ ØƒNØ
ƒIØÓØ†Mr    r   c                   óR   • \ rS rSr% \" SSS9r\\   \S'   \" SSS9r	\
\   \S'   S	rg)
ÚAllAnalyzerResponseé"   .z#List of identified tasks or issues.)r   ÚissuesNzSummary of the analysis.Úsummaryr   )r   r   r   r   r   r%   r   r   r   r&   r   r   r   r   r    r!   r#   r#   "   s6   ‡ Ù$ØÐ>ñ €FˆD�Ñó ñ # 4Ð5OÑP€GˆX�c‰]ÖPr    r#   zgemini-2.5-flashÚGOOGLE_API_KEY)ÚmodelÚapi_keyÚasgiÚ*)Ú
async_modeÚcors_allowed_originsc              ƒ   ó$   #   • [        SU 5        g 7f)Nz[SOCKET] Client connected:©Úprint)ÚsidÚenvirons     r!   Úconnectr3   3   s   é € ä	Ð
&¨Õ,ùó   ‚c              ƒ   ó$   #   • [        SU 5        g 7f)Nz[SOCKET] Client disconnected:r/   )r1   s    r!   Ú
disconnectr6   8   s   é € ä	Ð
)¨3Õ/ùr4   ÚdataÚreturnc                 óÎ   • U R                  5       R                  SS5      R                  SS5      n [        U 5      S-  nU(       a  U SSU-
  -  -  n [        R                  " U 5      $ )NÚ
Ú Ú é   Ú=)ÚstripÚreplaceÚlenÚbase64Ú	b64decode)r7   Úmissing_paddings     r!   Údecode_base64rE   @   s\   € Ø�:‰:‹<×Ñ  bÓ)×1Ñ1°#°rÓ:€DÜ˜$“i !‘m€OÞØ��q˜?Ñ*Ñ+Ñ+ˆÜ×Ò˜DÓ!Ð!r    c                 ó|   • [         R                  " SU 5      u  p[        R                  " U5      R	                  5       $ )z&Convert an OpenCV frame to base64 JPEGz.jpg)Úcv2ÚimencoderB   Ú	b64encodeÚdecode)ÚframeÚ_Úbuffers      r!   Úframe_to_base64rN   H   s.   € ä—’˜V UÓ+�I€AÜ×Ò˜FÓ#×*Ñ*Ó,Ð,r    Úvideo_bytesr   c                 óN  • [         R                  " SS9 nUR                  U 5        UR                  5         [        R
                  " UR                  5      nUR                  5       (       d
   SSS5        gUR                  [        R                  5      =(       d    Sn[        US-  U-  5      nUR                  [        R                  U5        UR                  5       u  pgUR                  5         U(       a  [        U5      sSSS5        $  SSS5        g! , (       d  f       g= f)z<Extract a frame at the given timestamp (ms) from video bytesz.mp4)ÚsuffixNé   iè  )ÚtempfileÚNamedTemporaryFileÚwriteÚflushrG   ÚVideoCaptureÚnameÚisOpenedÚgetÚCAP_PROP_FPSr   ÚsetÚCAP_PROP_POS_FRAMESÚreadÚreleaserN   )rO   r   ÚtmpÚcapÚfpsÚframe_numberÚretrK   s           r!   Úget_frame_at_timestampre   N   sÚ   € ä	×	$Ò	$¨FÒ	3°sØ�	‰	�+ÔØ�	‰	ŒÜ×Ò˜sŸx™xÓ(ˆØ�|‰|�~‰~Ø÷ 
4Ð	3ð �g‰g”c×&Ñ&Ó'×-¨2ˆÜ˜I¨Ñ,°Ñ3Ó4ˆØ�‰”×'Ñ'¨Ô6Ø—X‘X“Z‰
ˆØ�‰ŒÞÜ" 5Ó)÷ 
4Ñ	3ð ÷ 
4ð ÷ 
4Ô	3ð ús   •ADÁ6BDÄ
D$c              ƒ   ó(  ^ #   •  S nU 4S jn[         R                  " U" 5       U" 5       5      I S h  v•N u  p4/ nUR                   HH  n[        T UR                  5      nUR                  5       nU=(       d    SUS'   UR                  U5        MJ     UUR                  S.n	[        R                  SU	5      I S h  v•N   g  NŽ N! [         a@  n
[        SU
5        [        R                  SS	[        U
5      05      I S h  v•N     S n
A
g S n
A
ff = f7f)
Nc               “   ó   #   • g7f)Nzthis is demo transcriptionr   r   r    r!   Útranscribe_taskÚ1analyze_video_background.<locals>.transcribe_taskf   s   é € à/ùs   ‚c               “   óÜ   >#   • [         R                  " T5      R                  5       n Sn[        SUS.SU SS./S9n[        R
                  " [        R                  U/5      I S h  v•N $  N7f)Na  Analyze the attached office video for maintenance, repairs, and cleaning issues (electrical, decor, furniture, etc.). For each issue, provide a structured list with: timestamp (ms), task name, description, and category. Write a summary for the whole video as well.Útext)Útyperk   Úmediaú	video/mp4)rl   r7   Ú	mime_type)Úcontent)rB   rI   rJ   r   ÚasyncioÚ	to_threadÚstructured_llmÚinvoke)Ú	video_b64ÚpromptÚmessagerO   s      €r!   Úllm_taskÚ*analyze_video_background.<locals>.llm_taskj   so   øé € Ü×(Ò(¨Ó5×<Ñ<Ó>ˆIð?ð ô #à#¨VÑ4Ø$¨iÀkÑRðñˆGô !×*Ò*¬>×+@Ñ+@À7À)ÓL×LÐLÑLùs   ƒA"A,Á%A*Á&A,r;   Úscreenshot_b64)r%   r&   Útask_detectedz"[VIDEO_ANALYSIS] Background Error:Ú
task_errorÚerror)rq   Úgatherr%   re   r   ÚdictÚappendr&   ÚsioÚemitÚ	Exceptionr0   r   )rO   rh   rx   ÚtranscriptionÚ
llm_resultÚissues_with_screenshotsÚissuerz   Ú
issue_dictÚresponse_payloadÚes   `          r!   Úanalyze_video_backgroundr‹   c   só   øé € ð-8ò	0õ	Mô$ +2¯.ª.¹Ó9JÉHËJÓ*W×$WÑ!ˆð #%ÐØ×&Ô&ˆEÜ3°KÀÇÁÓQˆNØŸ™›ˆJØ+9×+?¸RˆJÐ'Ñ(Ø#×*Ñ*¨:Ö6ñ	 'ð .Ø!×)Ñ)ñ
Ðô �h‰h�Ð(8Ó9×9Ñ9ñ# %Xñ" 	:øäó 8ÜÐ2°AÔ6Ü�h‰h�| g¬s°1«vÐ%6Ó7×7Ö7ûð8üs]   ƒD…-C ²C³BC Â;CÂ<C Ã DÃC ÃC Ã
DÃ0D
Ã?DÄ D
ÄDÄ
DÄDÚdeepgram_responsec                 óX   •  U S   S   S   S   S   S   $ ! [         [        4 a     gf = f)zK
Extracts the main transcript text from a Deepgram transcription response.
ÚresultsÚchannelsr   ÚalternativesÚ
transcriptr;   )ÚKeyErrorÚ
IndexError)rŒ   s    r!   Úextract_transcriptr”   ”   sI   € ðà  Ñ+¨JÑ7¸Ñ:¸>ÑJÈ1ÑMØñ
ð 	
øô ”jÐ!ó Ùðús   ‚ –)¨)Úcontent_typec              ƒ   óP  #   • SnS[          3US.n[        R                  " SSSSS9n[        R                  " US9 IS	h  v•N n UR	                  X#U S
9I S	h  v•N nUR                  5         [        UR                  5       5      sS	S	S	5      IS	h  v•N   $  NW N@ N	! [        R                   aW  n[        SUR                  R                  5        [        UR                  R                  UR                  R                  S9eS	nAff = f! , IS	h  v•N  (       d  f       g	= f7f)zC
Send video/audio bytes to Deepgram and return transcription JSON.
zAhttps://api.deepgram.com/v1/listen?model=nova-3&smart_format=truezToken )ÚAuthorizationzContent-Typeg      $@g      ^@g     Àr@)r3   r^   rU   Úpool)ÚtimeoutN)Úheadersrp   zDeepgram returned error:)Ústatus_codeÚdetail)r   ÚhttpxÚTimeoutÚAsyncClientÚpostÚraise_for_statusr”   ÚjsonÚHTTPStatusErrorr0   Úresponserk   r   r›   )rO   r•   Úurlrš   r™   Úclientr¤   rŠ   s           r!   Útranscribe_videor§   ¡   sï   é € ð N€Cð "Ô"2Ð!3Ð4Ø$ñ€Gô
 �mŠm D¨u¸EÈÑN€Gä× Ò ¨×1Ò1°Vð		Ø#Ÿ[™[¨À{˜[ÐS×SˆHØ×%Ñ%Ô'Ü% h§m¡m£oÓ6÷	 2×1Ó1áSñ 2øô
 ×$Ñ$ó 	äÐ,¨a¯j©j¯o©oÔ>ÜØŸJ™J×2Ñ2¸1¿:¹:¿?¹?ñð ûð	ú÷ 2×1Ö1üsx   ‚>D&Á BÁD&ÁDÁBÁBÁ,BÂD&ÂBÂD&ÂBÂD&ÂD	Â2ADÄD	Ä	DÄD#ÄDÄD#ÄD&z/upload_videoÚfileÚbackground_tasksc              ƒ   óà   #   • U (       d  SS0$ U R                   =(       d    SnU R                  5       I S h  v•N nUR                  [        U5        [	        X25      I S h  v•N nSSUS.$  N3 N7f)Nr}   zNo video providedrn   Úokz2Video received. Analysis is running in background.)Ústatusrw   r„   )r•   r^   Úadd_taskr‹   r§   )r¨   r©   r•   rO   r„   s        r!   Úupload_videor®   ¾   st   é € ö ØÐ,Ð-Ð-à×$Ñ$×3¨€LØŸ	™	›×#€Kð ×ÑÔ6¸ÔDÜ*¨;ÓE×E€Mð ØGØ&ñð ñ $ñ
 Fùs!   ‚4A.¶A*·(A.ÁA,Á A.Á,A.)2Úfastapir   r   r   r   r   rB   rq   Úlangchain_core.messagesr   Úlangchain_google_genair	   Úpydanticr
   r   Útypingr   r   ÚosÚsocketiorG   rS   Údotenvr   r�   ÚrouterÚgetenvr   r   r#   ÚllmÚwith_structured_outputrs   ÚAsyncServerr�   Úeventr3   r6   r   ÚbytesrE   rN   r   re   r‹   r   r”   r§   r    r®   r   r    r!   Ú<module>r¾      s€  ðß OÕ OÛ Û Ý 0Ý 9ß %ß !Û 	Û Û 
Û Ý Û ñ „Ù	‹€à—9’9Ð/Ó0Ð ô�ô ôQ˜)ô Qñ Ø
 b§i¢iÐ0@Ó&Añ€ð ×+Ñ+Ð,?Ó@€ð ×Ò fÀ3ÑG€ð ‡�ñ-ó ð-ð ‡�ñ0ó ð0ð"˜ð " ô "ð-˜cô -ð¨ð ¸#ð À(È3Á-ô ð*.8°ô .8ðb
¨$ð 
°3ô 
ð¨ð ¸Sô ð: ‡�ˆ_Óá˜D“zØ(,ñØ
ðà%ôó ñr    