
    hi
F                        d 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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Zdd
lmZmZmZ ddlmZmZmZ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)m*Z*m+Z+m,Z,  e         ejZ                         Z.e.j_                   ej`                  ddddddd              ejb                         Z2e2jg                  e.       e2ji                  ejj                         edefd       Z6 eddde6ddd d!d"d#d$i%      Z7e7jq                  ed&gd'd&gd&g(       e7js                  d)ed*d+gd,d-.       ed/d01       ed2d34       edd54       edd64       edd74       edd84       edd94       ee      fd:e:d;e:d<e;d=e:d>e:d?e:d@e:dAefdB       Z<e7js                  dCed*d+gdDE       ed       ed      fdFe:dGe:fdH       Z=e7j}                  dIdJgdKL      dM        Z?e7j}                  dNedOgdPdQR       ee      fdAefdS       Z@e7j}                  dTedUgdVdWR       ee      fdAefdX       ZAe7j}                  dYeBe   dZgd[d\R      d]d ee      fd^e;d_e;dAefd`       ZCe7j}                  daedZgdbdcR       ee      fdde;dAefde       ZDe7j}                  dfedZgdgdhR       ee      fdie:dAefdj       ZEe7js                  dke*dZgdldmR       ee      fdne)dAefdo       ZFe7js                  dpedqgdrdsR      dnefdt       ZGe7js                  duedvgdwdxR      dnefdy       ZHe7js                  dzedvgd{d|R      dnefd}       ZIe7j                  d~      d        ZKe7j                  d      d        ZLeMdk(  rJddlNZN e; ej                  dd            ZP ej                  d      dk(  ZQ eNj                  ddePeQd       yy)ud   
Application FastAPI principale - Bot WhatsApp CV
100% FastAPI avec PostgreSQL et Swagger intégré
    N)datetime)asynccontextmanager)FastAPIDependsHTTPExceptionstatusForm)PlainTextResponse)CORSMiddleware)Session)load_dotenv)get_dbcreate_tablescheck_connection)UserResponseStatsResponseHealthResponseMessageRequestTemplateMessageRequestMessageResponseErrorResponse)UserService)conversation_handler)twilio_service)profile_search_service)ProfileSearchRequestProfileSearchResponseProfileSearchResultProfileMatchScorez/%(log_color)s%(levelname)s:%(name)s:%(message)scyangreenyellowredzred,bg_white)DEBUGINFOWARNINGERRORCRITICAL)
log_colorsappc                  K   t         j                  d       t         j                  d       t         j                  d       	 t                t                t        t        j                  dd            }t         j                  d|        t         j                  d| d	       t         j                  d
| d       t         j                  d| d       t         j                  d| d       t         j                  d| d       t         j                  d       t        j                  d      dk(  r*t         j                  d       t         j                  d       t         j                  d       t         j                  d       t         j                  d       d t         j                  d       t         j                  d       y# t        $ r#}t         j                  d|        Y d}~d}~ww xY ww)z(Gestion du cycle de vie de l'applicationz<============================================================u8   🤖 Bot WhatsApp CV - Démarrage (FastAPI + PostgreSQL)u   ❌ Erreur DB: NPORT@  u   🌐 Serveur: http://localhost:u   📱 Webhook: http://localhost:/webhook/whatsappu   📊 Stats: http://localhost:/statsu   🏥 Health: http://localhost:/healthu   📖 Swagger: http://localhost:/docsu   📚 ReDoc: http://localhost:/redocENVIRONMENTdevelopmentu   ⚠️  Mode DÉVELOPPEMENTu'   ⚠️  Utilisez ngrok: ngrok http 8000 u   ✅ Serveur prêt !u   🛑 Arrêt de l'application...u   👋 Application arrêtée)
loggerinfor   r   	Exceptionerrorintosgetenvwarning)r*   eports      0/home/www/therecruiter.miabetepe.com/app/main.pylifespanrA   4   sw     KK
KKJK
KK, ryy&'D
KK1$89
KK1$7HIJ
KK/vV<=
KK0g>?
KK1$u=>
KK/vV<=
KK	yy=045@A
KKO
KK%&
KKO	 KK12
KK,-1  ,qc*++,s1   A H G E:H 	G=G82H 8G==H u   🤖 WhatsApp CV Bot APIuj  
    ## Bot WhatsApp intelligent pour collecter CVs et profils LinkedIn
    
    ### Fonctionnalités
    - ✅ Collecte automatisée via WhatsApp
    - ✅ Parsing intelligent de CV avec Google Gemini
    - ✅ Scraping LinkedIn avec Apify
    - ✅ Base de données PostgreSQL
    - ✅ API REST complète
    
    ### Stack Technique
    - **Framework**: FastAPI (async)
    - **Base de données**: PostgreSQL + SQLAlchemy
    - **WhatsApp**: Twilio API
    - **IA CV**: Google Gemini Flash
    - **LinkedIn**: Apify Scraper
    
    ### Webhooks Twilio
    Configurez le webhook Twilio sur `/webhook/whatsapp`
    2.0.0r1   r2   zOmar - GDE Flutterzsupport@exemple.com)nameemailrC   MIT)titledescriptionversionrA   docs_url	redoc_urlcontactlicense_info*T)allow_originsallow_credentialsallow_methodsallow_headersr.      zWebhooks TwiliozWebhook principal WhatsAppu=   Point d'entrée pour recevoir les messages WhatsApp de Twilio)response_classstatus_codetagssummaryrG   .u*   Numéro expéditeur (whatsapp:+1234567890))rG   r5   zContenu du message texte)defaultrG   u   Nombre de médias jointsu   URL du premier médiau   Type MIME du médiau%   Texte du bouton cliqué (Quick Reply)u(   Payload de la commande du bouton cliquéFromBodyNumMedia	MediaUrl0MediaContentType0
ButtonTextButtonPayloaddbc           	        K   	 |r|n|}|r t         j                  d|  d| d| d       nt         j                  d|         t        j                  || ||||      }	t	        j
                  | |	       y# t        $ rC}
t         j                  d|
 d	
       	 t	        j
                  | d       n#  Y nxY wY d}
~
yd}
~
ww xY ww)u   
    Webhook Twilio pour recevoir les messages WhatsApp.

    Twilio envoie les données en form-data.
    Pour les clics sur boutons (Quick Reply), ButtonPayload contient la commande complète.
    u   🔘 Bouton cliqué par z: text='z' payload=''u   📨 Webhook de )r_   from_numbermessage_body	num_media	media_urlmedia_content_typer5   u   ❌ Erreur webhook: T)exc_infou'   ❌ Erreur. Réessayez ou tapez /reset.N)r6   r7   r   process_messager   send_messager8   r9   )rX   rY   rZ   r[   r\   r]   r^   r_   effective_bodyresponse_textr>   s              r@   whatsapp_webhookrl      s     0*7TKK24&KXeWffghiKK*4&12 -<<'0
 	##D-8 +A3/$?	''.WX	sG   CA1A6 5C6	C?B=B10B=1B53B=8C=CCz/webhook/statuszCallback statut des messages)rS   rT   rU   rV   
MessageSidMessageStatusc                 B   K   t         j                  d|  d|        yw)z/Webhook pour les updates de statut des messagesu   📊 Status: z = r5   )r6   r7   )rm   rn   s     r@   status_callbackrp      s$      KK-
|3}o>?s   /u	   GénéralzPage d'accueil de l'API)rU   rV   c                  2   K   ddddddddd	d
ddddddS w)ud   
    Point d'entrée de l'API.
    Retourne les informations de base et la liste des endpoints.
    zWhatsApp CV Bot APIrB   runningr   
PostgreSQLzGoogle Gemini FlashApify)	cv_parserlinkedin_scraperr.   r0   r/   
/api/usersr1   r2   )webhookhealthstatsusersdocsredoc)rC   rH   r   	frameworkdatabaseai	endpoints r       r@   homer      sE      & . '

 +!
 s   r0   
MonitoringzHealth checku<   Vérifie l'état de santé du service et de ses dépendances)response_modelrU   rV   rG   c                    K   	 | j                  d       d}	 t        j                         }|rdnd}t        dt	        j
                         ||      S #  d}Y BxY w#  d}Y 0xY ww)u^   
    Endpoint de santé pour monitoring.
    
    Vérifie:
    - PostgreSQL
    - Twilio
    zSELECT 1	connecteddisconnectedhealthy)r   	timestampr   twilio)executer   get_account_infor   r   utcnow)r_   	db_statustwilio_infotwilio_statuss       r@   health_checkr      sp      #


:	
'$557'2 //#	 #"	'&s,   A%A A !A%AA%A" A%r/   StatistiqueszStatistiques globalesz-Obtenir les statistiques d'utilisation du botc                    K   	 t               }|j                  |       }t        di |S # t        $ r3}t        j                  d|        t        dt        |            d}~ww xY ww)u   
    Statistiques globales du bot.
    
    Retourne:
    - Nombre total d'utilisateurs
    - Inscriptions complétées
    - CVs reçus
    - Profils LinkedIn
    - Taux de complétion
    u   ❌ Erreur stats:   rT   detailNr   )r   	get_statsr   r8   r6   r9   r   str)r_   user_servicer{   r>   s       r@   r   r     sd     $<"}&&r*%u%% <)!-.CF;;<s$   A)%* A)	A&.A!!A&&A)rx   UtilisateurszListe des utilisateursu5   Récupérer la liste des utilisateurs avec pagination2   limitoffsetc                 b   K   t        | d      } t               }|j                  || |      }|S w)u   
    Liste des utilisateurs avec pagination.
    
    - **limit**: Nombre d'utilisateurs à retourner (max 100)
    - **offset**: Position de départ pour la pagination
    d   )r   r   )minr   get_all_users)r   r   r_   r   r|   s        r@   	get_usersr   9  s6     $ sOE=L&&rv&FELs   -/z/api/users/id/{user_id}u    Détails d'un utilisateur par IDuH   Récupérer les informations d'un utilisateur par son identifiant uniqueuser_idc                 d   K   t               }|j                  ||       }|st        dd      |S w)uh   
    Récupérer un utilisateur par son ID.

    - **user_id**: Identifiant unique de l'utilisateur
         Utilisateur non trouvér   )r   get_user_by_idr   )r   r_   r   users       r@   r   r   Q  s>       =L&&r73D,
 	

 Ks   .0z/api/users/{phone_number}u   Détails d'un utilisateuru9   Récupérer les informations d'un utilisateur spécifiquephone_numberc                    K   | j                  d      sd| z   } t               }|j                  ||       }|st        dd      |S w)ut   
    Récupérer un utilisateur par numéro de téléphone.
    
    - **phone_number**: Numéro avec ou sans +
    +r   r   r   )
startswithr   get_user_by_phoner   )r   r_   r   r   s       r@   get_userr   m  sV       ""3'\)=L))"l;D,
 	

 Ks   AAz/api/search-profileszRechercher des profilsuY   Rechercher des candidats selon des critères (compétences, expérience, formation, etc.)requestc                 @  K   	 t        j                  ||       \  }}g }|D ]-  }|j                  t        |d   t	        d	i |d                / t        |||       S # t        $ r3}t        j                  d|        t        dt        |            d}~ww xY ww)
u  
    Recherche avancée de profils avec scoring automatique.
    
    **Critères disponibles:**
    - **skills**: Liste de compétences (ex: ["Python", "React", "AWS"])
    - **min_years_experience**: Années d'expérience minimum
    - **max_years_experience**: Années d'expérience maximum
    - **companies**: Entreprises ciblées (ex: ["Google", "Microsoft"])
    - **positions**: Postes recherchés (ex: ["Senior Developer", "Tech Lead"])
    - **education_degrees**: Diplômes (ex: ["Master", "PhD"])
    - **education_institutions**: Établissements (ex: ["MIT", "Stanford"])
    - **languages**: Langues parlées (ex: ["Français", "Anglais"])
    - **location**: Localisation (ex: "Paris", "Remote")
    
    **Options:**
    - **match_all_skills**: true = toutes les compétences requises, false = au moins une
    - **match_threshold**: Score minimum (0.0 à 1.0) pour filtrer les résultats
    - **limit**: Nombre de résultats (max 100)
    - **offset**: Pagination
    
    **Scoring:**
    - Score global calculé automatiquement (0.0 à 1.0)
    - Pondération: Compétences 40%, Expérience 35%, Formation 25%
    - Résultats triés par score décroissant
    
    **Exemple de requête:**
```json
    {
      "skills": ["Python", "Django", "PostgreSQL"],
      "min_years_experience": 3,
      "companies": ["Google", "Microsoft"],
      "match_all_skills": false,
      "match_threshold": 0.5,
      "limit": 10
    }
```
    r   match_score)r   r   )total_resultsresultssearch_criteriau   ❌ Erreur recherche: r   r   Nr   )r   search_profilesappendr   r   r   r8   r6   r9   r   r   )r   r_   r   totalformatted_resultsresultr>   s          r@   r   r     s     `</??GL  	F$$# 1 JF=4I J	 %%#
 	
  <-aS12CF;;<s)   BAA B	B(.BBBz/api/test-messageTestszTest d'envoi de messagez#Envoyer un message WhatsApp de testc                 
  K   	 t        j                  | j                  | j                        }t	        ||rd      S d      S # t
        $ r3}t        j                  d|        t        dt        |            d}~ww xY ww)z^
    Envoyer un message WhatsApp de test.

    Utile pour tester la configuration Twilio.
       Message envoyé   Échec d'envoisuccessmessageu   ❌ Erreur test: r   r   N)
r   ri   tor   r   r8   r6   r9   r   r   r   r   r>   s      r@   test_messager     s~     	< --gjj'//J)0%
 	
6F
 	
  <(,-CF;;<s2   B8A BA B	B .A;;B  Bz/api/send-messageMessagesu)   Envoyer un message WhatsApp personnaliséuT   Envoyer un message WhatsApp avec un contenu libre (actualités, notifications, etc.)c                 v  K   	 t        j                  | j                  | j                        }t        j                  d| j                   d|rdnd        t        ||rd      S d      S # t        $ r@}t        j                  d| j                   d|        t        d	t        |      
      d}~ww xY ww)u   
    Envoyer un message WhatsApp personnalisé.

    - **to**: Numéro WhatsApp destinataire (ex: whatsapp:+33612345678)
    - **message**: Contenu libre du message
    u   📤 Message envoyé à :    ✅   ❌r   r   r   u   ❌ Erreur envoi message à r   r   N)r   ri   r   r   r6   r7   r   r8   r9   r   r   r   s      r@   ri   ri     s     
< --gjj'//J.wzzl"gUSX<YZ[)0%
 	
6F
 	
  <3GJJ<r!EFCF;;<s5   B9A!A- %B9&A- ,B9-	B66;B11B66B9z/api/send-template-messagez/Envoyer un message WhatsApp via template Twilioum   Envoyer un message WhatsApp basé sur un template approuvé Twilio (Content API), avec injection de variablesc                   K   	 t        j                  | j                  | j                  | j                        }t
        j                  d| j                   d| j                   d|rdnd        t        ||rd	      S d	      S # t        $ r@}t
        j                  d
| j                   d|        t        dt        |            d}~ww xY ww)u  
    Envoyer un message WhatsApp via un template Twilio.

    - **to**: Numéro WhatsApp destinataire (ex: whatsapp:+33612345678)
    - **content_sid**: SID du template Twilio (ex: HXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)
    - **variables**: Variables à injecter dans le template, indexées à partir de `"1"` (ex: `{"1": "John", "2": "Développeur"}`)

    Les templates doivent être créés et approuvés dans la console Twilio (Content API).
    )r   content_sid	variablesu   📤 Template u    envoyé à r   r   r   u   Message template envoyéu   Échec d'envoi du templater   u   ❌ Erreur envoi template à r   r   N)r   send_template_messager   r   r   r6   r7   r   r8   r9   r   r   r   s      r@   r   r   	  s     "< 66zz++''

 	nW%8%8$9gjj\QS]dTYjoSpqr29.
 	
?[
 	
  <4WZZL1#FGCF;;<s5   CA:B >C?B C	C;C

CCr   c                 <   K   ddt        | j                        dS w)NFu   Endpoint non trouvé)r   r9   path)r   urlr   excs     r@   not_found_handlerr   /  s$      'GKK  s   r   c                 D   K   t         j                  d|        dddS w)Nu   ❌ Erreur serveur: FzErreur interne du serveur)r   r9   )r6   r9   r   s     r@   internal_error_handlerr   8  s*     
LL'u-., s    __main__r,   r-   r3   r4   zapp.main:appz0.0.0.0r7   )hostr?   reload	log_level)S__doc__r;   loggingr   
contextlibr   fastapir   r   r   r   r	   fastapi.responsesr
   fastapi.middleware.corsr   sqlalchemy.ormr   dotenvr   colorlogapp.databaser   r   r   app.schemasr   r   r   r   r   r   r   app.services.user_servicer   !app.services.conversation_handlerr   app.services.twilio_servicer   #app.services.profile_search_servicer   r   r   r   r   StreamHandlerhandlersetFormatterColoredFormatter	getLoggerr6   
addHandlersetLevelr%   rA   r*   add_middlewarepostr   r:   rl   rp   getr   r   r   listr   r   r   r   r   ri   r   exception_handlerr   r   __name__uvicornr<   r?   r   runr   r   r@   <module>r      s   
   * A A / 2 "   A @   2 B 6 F k k  !(
 
 
"   .X..5"	 	 
			   '    #. #. #.N 
$( $&
 	=!H   %%%   $
	(O 
  S&RSR-GH0JK$4KL!$<QR45\]d8bc&/.
.
. . 	.
 . . . 	..b $
	* 
  4jd 
% 	 

4 !
N 	  &-V_ 7 <  
	#? 	  #*&/ < <<( %
	$G 	  &/ 	" 
	.Z 	  &/* 
	'K 	  &/0 (
	$k 
  &/?<!?<?<?<D "
%5 
 < <<$ "
7f 
 < <<(  "
= 
 <)? <<> s  s  zyryy&'DRYY}%6FGKK r   