
    ׸i                        d dl Z d dl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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dd
lmZmZmZmZmZmZmZmZmZmZ d dlZd dlZd dl Z d dl!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, d dl-m.Z. d dl/m0Z0 d dl1Z1d dl2Z2d dl3m4Z4 d dl5Z5d dl6m7Z7 d dl8m9Z9 ejt                  jw                  ejt                  jw                  e<            Z=ejt                  j}                  e=ddd      Z? e@e?      5 ZA e5j                  eA      ZCddd       d;dZD ej                  eF      ZGd<dZHd=dZId ZJd>dZKd ZLd ZMd ZN G d d       ZOd!ePd"ePfd#ZQd$ ZRd% ZSd&ePd'ePd"eTfd(ZUd) ZVd* ZWd+ ZXd, ZY ej                  eF      ZGd- ZZd. Z[ G d/ d0      Z\d1 Z]d2 Z^d=d3Z_d4 Z`d5 Zad6 Zb G d7 d8      Zcd9 Zdd: Zey# 1 sw Y   xY w)?    N)quote)TfidfVectorizer)cosine_similarity)User)EmailMessage)settings   )
UserClient)
r
   TblCandidateResumeTblJobDescription
EmailQueueWhatsAppQueueSMSQueueAssignJdTblMatchedProfiles
PublicLink	TblClient)etree)timezone)	timedelta)validate_email)ValidationError)SMTPRecipientsRefused)defaultdict)parse_datetime)ZoneInfomastersmail_configszemail_templates.jsonc                     t         d   |    }|d   }|d   }|r*t         d   d   }|j                  dd      }d| | d	}||fS t         d   d
   }|dz   |z   }||fS )Nemailstitlebodyfooterhtml
z<br>z&<html><body style='font-family:Arial'>z</body></html>text

)EMAIL_CONFIGreplace)keyis_htmltemplatesubjectr"   r#   s         $/var/www/talchi_dev/masters/utils.pyget_email_templater/   )   s    H%c*HwGFDh'/||D&)7vfX^T
 D= h'/f}v%D=    c                 F   t        j                         j                  d d }t        d       t        d|       t        d|        t        d|       t        d|       t        j
                  j                  || ||      }t        d|j                         t        d	       |S )
N   z,========== GENERATING PUBLIC LINK ==========zGenerated Token:
Resume ID:JD ID:z
Link Type:)token	resume_idjd_id	link_typezSaved Object ID:z+===========================================)uuiduuid4hexprintr   objectscreateid)r6   r7   r8   r5   objs        r.   generate_public_linkrA   <   s    JJLSb!E	
89	
e$	,	"	(E	,	"



#
#	 $ C 

cff%	
78Lr0   c                 <   t        |t              r|g}g }|D ]  }	 t        |       |j                  |       ! g }|r7t        |t              r|g}|D ]  }		 t        |	       |j                  |	       ! |st
        j                  d       y	 t        | ||||      }|rd|_	        |j                  d       t
        j                  d| d	|        y
# t        $ r t
        j                  d|        Y w xY w# t        $ r t
        j                  d|	        Y w xY w# t        $ r`}
t
        j                  d|
        t        j                  j                  dj!                  |      | ||ddt        |
             Y d }
~
yd }
~
wt"        $ r}
t%        j&                         t)        d      z   }t
        j                  d| d| d|
        t        j                  j                  dj!                  |      | ||dd|t        |
             Y d }
~
yd }
~
wt        $ re}
t+        d| d|
        t
        j                  d| d|
        t        j                  j                  || ||ddt        |
             Y d }
~
yd }
~
wt"        $ r}
t%        j&                         t)        d      z   }t+        d| d| d|
        t
        j                  d| d| d|
        t        j                  j                  || ||dd|t        |
             Y d }
~
yd }
~
ww xY w)Nz&[EMAIL-SEND] INVALID_TO_SKIPPED email=z#[EMAIL-SEND] INVALID_CC_SKIPPED cc=z&[EMAIL-SEND] No valid recipient emailsFr-   r"   
from_emailtoccr$   fail_silentlyz[EMAIL-SEND] status=SENT to=z cc=Tz:[EMAIL-SEND] status=FAILED reason=INVALID_RECIPIENT error=,FAILEDr   )to_emailr-   r"   rD   statusretry_count
last_error   minutesz[EMAIL-SEND] status=QUEUED to=z next_retry_at= error=PENDINGr	   )rK   r-   r"   rD   rL   rM   next_retry_atrN   z7[EMAIL-SEND] status=FAILED reason=INVALID_RECIPIENT to=)
isinstancestrr   appendr   loggerwarningerrorr   content_subtypesendinfor   r   r=   r>   join	Exceptionr   nowr   r<   )r-   r"   rK   rD   	cc_emailsr+   valid_toemailvalid_ccrF   e
next_retrys               r.   send_email_saferg   Q   sY   (C :H M	M5!OOE"M Hi%"I 	KBKr"#	K =>a!
 $*E!


'*8*D
C	
 K  	MNNCE7KL	M # K!DRDIJK6 ! HL	
 	!!XXh'!1v 	" 	
  \\^i&::
,XJoj\QXYZX[\	
 	!!XXh'!$1v 	" 		
   GzQXYZX[\]EhZwWXVYZ	
 	!!!1v 	" 	
  \\^i&::
,XJ 7'Ls4	
 	,XJ 7'Ls4	

 	!!!$1v 	" 		
 -sd   CC<AD# !C98C9<!D D #	L,AFLA>HL"AJLBLLc                    t        |       j                  dd      j                  dd      j                  dd      } | j                  d      sd| z   } d|d| d}t        j                  d	d
}	 t        j                  t        j                  ||d      }|j                  dk(  r<|j                         }|j                  d      du rt        j                  d|         yt        |j                        # t        $ rt}t        j                          t#        d      z   }t$        j&                  j)                  | |dd|t        |             t        j+                  d|  d|        Y d }~yd }~ww xY w)N+  -91qenglish)routemessagelanguagenumbersapplication/json)authorizationContent-Type
   )jsonheaderstimeout   returnTz[SMS] SENT to=rO   rP   rS   r	   )to_phonerq   rL   rM   rT   rN   z[SMS] QUEUED to=rR   F)rV   r)   
startswithr   FAST2SMS_API_KEYrequestspostFAST2SMS_URLstatus_coderx   getrX   r]   r_   r&   r   r`   r   r   r=   r>   rY   )r}   rq   payloadry   resresponse_datare   rf   s           r.   send_sms_safer     s`    	H	b		b		b		  t$(? 	G "22*G
mm!!	
 ??c!HHJM  *d2nXJ78!! \\^i&::
$1v 	  	
 	)(71#>?s    -A1C4 C4 4	E1=A*E,,E1c                     t         j                  t         j                  z   dj                  fdt	        |       D              }|S )Nrj   c              3   H   K   | ]  }t        j                          y wN)randomchoice).0_
characterss     r.   	<genexpr>z$generate_password.<locals>.<genexpr>F  s     L6==4Ls   ")stringascii_lettersdigitsr^   range)lengthpasswordr   s     @r.   generate_passwordr   A  s6    ))FMM9
 77LeFmLLr0   c                 @    t         j                   d| j                   S )Nz/apply/)r   CAREERapply_token_urljds    r.   generate_apply_linkr   J  s    oogb&8&8%9::r0   c                     t        |d      }d| }d|  dd}t        j                  ||      }|j                  dk(  S )	Nrj   )safez%https://api.linkedin.com/v2/ugcPosts/zBearer z2.0.0)AuthorizationzX-Restli-Protocol-Version)ry      )r   r   deleter   )access_tokenpost_urnencoded_urnurlry   r   s         r.   delete_linkedin_postr   M  sQ    r*K1+
?C #<.1%,G
 //#w
/C??c!!r0   c                     d}dd| j                    d}| j                  |j                  ||j                  |j                  d}ddt        |j                        z   dS )	Nz"https://api.foundit.in/v1/job/postrt   zBasic )rv   r   )username	job_titlejob_descriptionlocationexperience_minsuccessFI_)rL   foundit_job_id)portal_passwordportal_usernamer   job_locationyears_of_experiencerV   pk)configr   r&   r   ry   r   s         r.   post_to_founditr   Y  sj    
.C +!&"8"8!9:G **\\OO00G  53ruu:3EFFr0   c                   $    e Zd Zd Zd Zd Zd Zy)
LlmPromptsc                     d|  dS )Na  
            Role:
            Act as an Expert HR Data Parser and Resume Analyst.
            Input Data:
            I will provide you with the raw text from an EMAIL BODY containing a candidate's resume or profile. The text may include email headers, signatures, forwarding history, and conversational text (e.g., "Please find attached...").
            Your Task:
            Noise Filtering: actively ignore email metad ata, "Sent from my iPhone" footers, legal disclaimers, and conversational introductions. Isolate the actual candidate profile data.
            Semantic Analysis:
            Standardization: transfer the specific to given JSON format.
            Format: Output the data strictly into the JSON format defined below.
            Rules for Extraction:
            Name: Identify the candidate's name, not the recruiter's or sender's name.
            Age : Calculate the age from the date of birth, blank if date for birth is not specified
            Gender : Gender of the candidate either Male or FeMale, blank if not gende is not available 	
            Employment type : Current Job type like Contract or Employee or Part Time or Freelancer, leave blank if not available 
            Dates: Ensure dates are formatted consistently (e.g., "Month Year" or "Year").
            Title: Identify from the resume. if resume doesn't have the title, create a suitable title for the resume.
            Primary Skills: more experience skills
            Responsibility Summary: summary of all the skills, work experience responsibilities and project experience.
            Domain Skills: Industry or Buisiness Related skills
            Missing Data: If a specific field is not found, return "Not Specified" (do not use null or empty strings).
            Output Format:
            Return ONLY a single valid JSON object. Do not include any conversational text.
            ```json
            {
                "personal_information": {
                    "first_name": "String",
                    "last_name" : "String",
                    "full_name": "String",
                    "email": "String",
                    "mobile": "String",
                    "linkedin_url": "String",
                    "portfolio_url": "String",
                    "location": "String",
					"age": "String",
					"gender": "String",
					"notice_period": "String",
					"empoyment_type"
                },
                "title": "String",
                "total_exp": "String",
                "salary" : "String",
                "professional_summary": "String",
                "responsibility_summary": "String',
                "primary_skills": ["String"],
                "skills": {
                    "technical_skills": ["String"],
                    "soft_skills": ["String"],
                    "tools_and_frameworks": ["String"]
                },
                "domain_skills": ["String"],
                "work_experience": [
                    {
                        "job_title": "String",
                        "company": "String",
                        "location": "String",
                        "start_date": "String",
                        "end_date": "String",
                        "is_current": Boolean,
                        "responsibilities": "String"
                    }
                ],
                "education": [
                    {
                        "degree": "String",
                        "institution": "String",
                        "location": "String",
                        "graduation_year": "String"
                    }
                ],
                "projects": [
                    {
                        "project_name": "String",
                        "description": "String",
                        "technologies_used": ["String"]
                    }
                ],
                "certifications": [
                    {
                        "name": "String",
                        "issuer": "String",
                        "year": "String"
                    }
                ],
                "languages": ["String"]
            }
            ```
            Input Email Body:	
            	
         )resume_texts    r.   resume_extraction_promptz#LlmPrompts.resume_extraction_promptn  s"    Xp M 	qY Y	r0   c                     d|  d}|S )NaQ  
            Role:
            Act as an Expert Technical Recruiter and Data Parsing AI.
            Input Data:
            I will provide you with the raw text from an EMAIL BODY or PDF or Word, which containing an  unstructured Job Description (JD).
            Your Task:
            Analyze: Read the text and identify key job details. Ignore email metadata (signatures, "Sent from my iPhone", greetings, and thread headers).
            Semantic Extraction & Tuning:
            Interpret Meaning: If the email says, "looking for a rockstar in Python," interpret this as "Expert proficiency in Python" under skills.
            Standardize: Expand only universal recruitment abbreviations (e.g., "wfh" -> "Remote"). Strictly preserve Client Acronyms, Project Codes, and Proper Nouns exactly as written (e.g., keep "LTA", "JPMC", "DBS" as is; do not expand them).
            Categorize: Semantically distinguish between what is "Required" (Must have) vs. "Preferred" (Nice to have/Bonus).
            Refine: Clean up the grammar and tone of the extracted text to be professional and suitable for a formal JD.
            Audit Transformation: Track every specific change made, including which input headers were mapped to which output keys.
            Format: Output the data strictly into the specific JSON format defined below.
            Rules for Extraction:
            If a field is not mentioned in the email, return "Not Specified".
            jd_date: Extract the date from the email text if present, otherwise use "Current".
            job_title : Retain the given title in the JD
            ai_title : Tuned and Generated Title from the JD
            job_type: type of Job in the JD example Contract or Employee or etc..
            job_id: reference for the JD or JD identifier
            duration : Duration of the Job requirement in months, if not specified use 24+ months
            about_company: If not explicitly stated, try to infer the company name/domain from the context, or leave as "Not Specified".
            no_of_open_positions: If not explicitly stated, give default value as 1
            primary_skills: highly important skills required for the JD
            secondary_skills: technical skills exclude the primary skills
            domain_requirements: must specified as domain skills in the JD
            Specific Instruction for "changes" field:
            You must generate a semicolon-separated string listing THREE types of changes:
            MAPPING: Which input section was mapped to which JSON key (e.g., "Mapped 'Key Responsibilities' to 'responsibilities'").
            CORRECTION: Content fixes (e.g., "Corrected '58 years' to '5-8 Years'").
            INFERENCE: Data derived from context (e.g., "Inferred 'LTA' is the Domain/Client").
            Output Format:
            Return ONLY a single valid JSON object. Do not include any conversational text.
            ```json
            {
            "ai_title" : "String",
            "job_title" : "String",
            "job_type" : "String",
            "job_id" : "String",
            "about_company"  : "String",
            "no_of_open_positions" : "String",
            "job_summary"  : "String",
            "responsibilities" : "String",
            "domain_requirements" : "String",
            "certification_requirements" : "String",
            "security_clearance_requirements" : "String",
            "years_of_experience" : "String",
            "duration" : "String",
            "onsite_job" : "String",
            "job_location" : "String",
            "salary_range" : "String",
            "required_qualifications" : "String",
            "preferred_qualifications" : "String",
            "working_hours" : "String",
            "benefits" : "String",
            "requirement_priority" : "String",
            "search_pattern" : {
                "job_title": "String",
                "location": "String",
                "education": ["String"],
                "primary_skills": ["String"],
                "secondary_skills": ["String"],
                "soft_skills": ["String"],
                "tools_and_frameworks": ["String"],
                "salary_range": "String",
                "keywords": ["String"],
                "domain_requirements": ["String"]
            },
            "changes": "String",
            }
            ```

            Input Email Body:
            r   r   )final_body_textjd_generate_prompts     r.   jd_extraction_promptzLlmPrompts.jd_extraction_prompt  s)    J"T  	UKX "!r0   c                     d|  dS )Na  
            Role:
            Act as an Expert Technical Recruiter and Data Parsing AI.
            Input Data:
            I will provide you with the JSON text, which containing list of structured Job Description (JD).
            Your Task:
            Analyze: Read each JD in the JSON and generate the search patterns in specific JSON structure
            Format: Output the data strictly into the specific JSON format defined below.
            Rules for Extraction:
            jd_id : Retain the given jd_id in the JD
            job_title : Retain the given title in the JD
            primary_skills: highly important skills required for the JD
            secondary_skills: technical skills exclude the primary skills
            domain_requirements: must specified as domain skills in the JD
            Output Format:
            Return list of valid JSON object. Do not include any conversational text.
            ```json
            [
                {
                    "jd_id" : "String",
                    "search_pattern" : {
                        "job_title": "String",
                        "location": "String",
                        "education": ["String"],
                        "primary_skills": ["String"],
                        "secondary_skills": ["String"],
                        "soft_skills": ["String"],
                        "tools_and_frameworks": ["String"],
                        "salary_range": "String",
                        "keywords": ["String"],
                        "domain_requirements": ["String"]
                    }
                }
            ]
            ```
            
            Input JSON:
            r   r   )r   s    r.   jd_search_pattern_promptz#LlmPrompts.jd_search_pattern_prompt  s     %J  	K& &	r0   c                     d|  dS )Nz`
            Generate a structured JSON report  for this interview.
            Interview Logs: a  

            Output Format:
            ``` json 
            {
                "Candidate_Strengths" : "String[]",
                "Candidate_Weaknesses": "String[]",
                "Score": {
                    "communication": 'String", 
                    "attitude": "String", 
                    "Technical": "String"
                },
                "Final_Hiring_Recommendation": "String (Excellent/Very Good/Good/Fair/Poor)"
            }
            ```
        r   )interview_datas    r.   l0_interview_summary_promptz&LlmPrompts.l0_interview_summary_promptB  s    +, -	 	r0   N)__name__
__module____qualname__r   r   r   r   r   r0   r.   r   r   m  s    ZxM"^'Rr0   r   r!   r|   c                     | sy| j                         j                         } t        j                  dd|       } t        j                  dd|       } t        j                  dd|       j                         } | S )Nrj   z[_\-\/]+rk   z[^a-z0-9 ]+\s+)striplowerresub)r!   s    r.   normalize_resume_titler   V  sb    KKM!E FF;U+EFF>2u-EFF63&,,.ELr0   c                 b   t        j                  d|       }t        j                  d|      }t        j                  d||      }g }g }|j	                         D ]3  \  }}}	}
}dj                  |||	       }dj                  ||
|       }|dk(  rI|j                  t        j                  |             |j                  t        j                  |             |dk(  rQ|j                  dt        j                  |       d       |j                  dt        j                  |       d       |d	k(  r*|j                  dt        j                  |       d       |d
k(  s|j                  dt        j                  |       d       6 dj                  |      dj                  |      fS )z
    Returns (old_html, new_html)
    old_html: highlights removed/changed words (blue)
    new_html: highlights added/changed words (green)
    z\w+|\s+|[^\w\s]Nrj   equalr)   zD<span style='background:#dbeafe;border-radius:4px;padding:1px 3px;'>z</span>zD<span style='background:#dcfce7;border-radius:4px;padding:1px 3px;'>r   insert)	r   findalldifflibSequenceMatcherget_opcodesr^   rW   r$   escape)old_linenew_line
old_tokens
new_tokenssm
old_result
new_resulttagi1i2j1j2old_partnew_parts                 r.   highlight_inline_diffr   h  s    .9J.9J		 	 z:	>BJJ!~~/ ERR77:b,-77:b,-'>dkk(34dkk(34I deiepepqyezd{  |C  D  E deiepepqyezd{  |C  D  EH_ deiepepqyezd{  |C  D  EH_ deiepepqyezd{  |C  D  E!E$ 77:
 333r0   c                 F   dd| j                    d| j                   d| j                   g}| j                  r|j	                  d| j                          t        | j                        }|j                  d| d| j                   g       dj                  |      |fS )	Nu   🚀 We are Hiring!u   🔹 Role: u   📍 Location: u   🧠 Experience: u   💰 Salary: u   👉 Apply here: u   🆔 Ref ID: r'   )	r   r   r   salary_rangerW   r   jd_display_idextendr^   )r   lines	apply_urls      r.   build_facebook_post_textr     s    
bll^$
"//*+
B2234	E 
}R__$567#B$4$45I	LL
I;'
(()* 
 ;;uy((r0   title1title2c                     | r|syt        d      }|j                  | |g      }t        |dd |dd       d   d   }t        |dz  d      S )Ng        ro   )
stop_wordsr   r	      d   )r   fit_transformr   round)r   r   
vectorizertfidf_matrix
similaritys        r.   calculate_title_similarityr     s_     I6J++VV,<=L"<!#4l1Q6GHKANJc!1%%r0   c                     | r|sy | j                         } |j                         }t        |       dk  st        |      dk  ry t        | |      S )N   )r   lenr   )ai_titler   s     r.   safe_similarityr    sI    9~~H!I
8}qC	NQ.%h	::r0   c                     t         j                  j                  dt        j                  j                  |       j	                  dd            j                         S )z@
    Returns Delivery Managers assigned to the given client
    zDelivery Manager (DM)clientuser_idTflat)groups__nameid__in)r   r=   filterr
   values_listdistinctr  s    r.   get_client_delivery_managersr    sV     <<,!!(( ) 

+id+
+	  
 hjr0   c                    	 | D ]  }|j                   st        dd      \  }}|j                  |      }|j                  |j                  xs d d|j                  xs d j                         |||      }t        ||j                         |j                   t        j                  d        y	 y # t        $ r}t        d
|       Y d }~yd }~ww xY w)Nai_title_mismatch_notificationFr+   )r   rj   rk   )dm_namer   r   r   r-   r"   rK   rD   r+   TEmail unexpected error:)rc   r/   format
first_name	last_namer   rg   r   EMAIL_HOST_USERr_   r<   )	dm_usersr   r   r   r   dmr-   r"   re   s	            r.   notify_dm_low_matchr    s     	B88./OMGT nn% % G ;;==.B/q1C0DEKKM+#!	  D ZZ\#33 3	4  '+s   B/B4 2B4 4	C=CCc                    | j                   r| j                  syt        | j                   | j                        }|y|| _        | j	                  dg       |dk\  ry| j
                  syt        | j
                        }|j                         st        d| j
                         yt        || j                  | j                   || j                         y)z=
    jd_obj must already be saved (jd_display_id exists)
    Nai_title_similarityupdate_fieldsP   z&No Delivery Managers found for client:)r   r   r  r  save	client_idr  existsr<   r  r   )jd_objr   r  s      r.   $check_ai_title_similarity_and_notifyr$    s    
 ??&"2"2 J
 !+F
KK45K6R+F,<,<=H??68H8HIr0   c                    t        dd      \  }}|j                  |||d      }	 t        ||j                         | gt        j
                  d       y# t        $ r"}t        j                  d|        Y d }~yd }~ww xY w)	Nuser_created_accountFr  z,https://auto-recruiter.itconnectus.com/login)	full_namer   r   	login_urlr  TzEmail sending failed: )	r/   r  rg   r   r   r  r_   rX   rZ   )rc   r   r   r'  r-   r"   re   s          r.   send_user_created_mailr)    s    &'=uMMGT;;@	  DW//	
  -aS12s   -A 	B A;;B c                    	 t        dd      \  }}|j                  |      }|j                  ||      }t        ||j                         | gt        j
                  d       y# t        $ r}t        d|       Y d }~yd }~ww xY w)	Nresume_acknowledgementFr  r   candidate_namer   r  Tr  )r/   r  rg   r   r   r  r_   r<   )rK   r.  r   r-   r"   re   s         r.   send_resume_ack_emailr/  $  s    *+CUS..9.5{{)  

 	Z//	
  '+s   A"A% %	B.A??Bc                   d    e Zd Zd Zd Zd Zd Zed        Zed        Z	de
de
fd	Zed
        Zy)DocumentTextExtractionc                    g }ddi}t        j                  |       5 }|j                         D ]  }|j                  d      st	        j
                  |j                  |            }|j                  d|      D ]S  }|j                  s|j                  j                         s+|j                  |j                  j                                U  	 d d d        dj                  |      S # 1 sw Y   xY w)Nw<http://schemas.openxmlformats.org/wordprocessingml/2006/mainzword/header.//w:t
namespacesr%   )zipfileZipFilenamelistr~   r   
fromstringreadxpathr&   r   rW   r^   )	file_pathry   r7  znamerootts          r.   extract_headers_xmlz*DocumentTextExtraction.extract_headers_xml?  s    YZ
__Y' 	;1

 ;??=1 ++AFF4L9D!ZZZZH ;66afflln#NN166<<>:;;	; yy!!	; 	;s   %C+AC+	C+$-C++C4c                 t   	 t        j                  |       5 }|j                  d      }d d d        t        j                        }ddi}g }g }|j                  d|      D ]V  }|j                  j                  d      rz|j                  d|      }|D ]*  }	|	j                  s|j                  |	j                         , |sddj                  |      j                         }
|
r|j                  |
       g }|j                  j                  d	      s|j                  d
|      D ]  }g }|j                  d|      D ]O  }|j                  d|      }dj                  d |D              j                         }|s?|j                  |       Q |sm|j                  dj                  |              Y dj                  |      }|j                         st        d      |j                         S # 1 sw Y   xY w# t        $ r*}t        d|        t        dt        |             d }~ww xY w)Nzword/document.xmlr3  r4  z.//w:body/*r6  z}pr5  rj   z}tblz.//w:trz.//w:tcc              3   N   K   | ]  }|j                   s|j                     y wr   )r&   r   rB  s     r.   r   z:DocumentTextExtraction.extract_docx_xml.<locals>.<genexpr>l  s     0VAqvv0Vs   %%z | r%   z(No readable text found in Word document.z&Failed to extract Word Document text: z+Failed to extract text from Word document: )r8  r9  r<  r   r;  r=  r   endswithr&   rW   r^   r   r_   r<   rV   )r>  r?  xml_contentrA  r7  r   current_lineelementtextsrB  linerow	row_cellscell
cell_texts
cell_valuedoc_textre   s                     r.   extract_docx_xmlz'DocumentTextExtraction.extract_docx_xmlM  s   /	T+ :qff%89: ##K0D]^JEL::m
:K @;;''-#MM(zMJE" 866(//78 $!ww|4::<!LL.')[[))&1&}}Y:}N @$&	$'IIiJI$O =D)-H)TJ)+0V0V)V)\)\)^J) ) 0 0 <= %!LLI)>?@@8 yy'H>># JKK>>##U: :X  	T:1#>?I#a&RSS	TsO   H G7A;H %H AH A)H  H A H 7H<H 	H7%H22H7c           
         	 t        j                         5 }t        j                  dddd| d|gt        j                  t        j                  d       t
        j                  j                  t
        j                  j                  |             d   }t
        j                  j                  ||d	z         }t
        j                  j                  |      st        d
      t        |ddd      5 }|j                         j                         }d d d        st        d      |cd d d        S # 1 sw Y   !xY w# 1 sw Y   y xY w# t        $ r}t        d|       d }~ww xY w)Nlibreofficez
--headlessz--convert-toztxt:Textz--outdirT)stdoutstderrcheckr   z.txtzLibreOffice conversion failedrzutf-8ignore)encodingerrorszEmpty LibreOffice outputzLibreOffice extraction failed: )tempfileTemporaryDirectory
subprocessrunDEVNULLospathsplitextbasenamer^   r"  r_   openr<  r   )r>  tmpdirbasetxt_filefr&   re   s          r.   extract_with_libreofficez/DocumentTextExtraction.extract_with_libreoffice  s:   	C,,. &%$&
!"F &--%-- ww''(8(8(CDQG77<<v>ww~~h/#$CDD(C'(K ,q668>>+D, #$>??5 (, ,) 8  	C=aSABB	CsM   E CD9.D-D9#	E -D6	2D99E>E E 	E!EE!c                     	 t        j                  |       5  	 d d d        y# 1 sw Y   y xY w# t         j                  $ r Y yw xY w)NTF)r8  r9  
BadZipFile)r>  s    r.   is_docxzDocumentTextExtraction.is_docx  sB    	+   !! 		s#   . ". +. . AAc                 6   t         j                  |       rG	 t         j                  |       }t         j                  |       }dj	                  d ||fD              }|S 	 t         j                  |       S # t
        $ r Y !w xY w# t
        $ r Y t        d      w xY w)Nr%   c              3   &   K   | ]	  }|s|  y wr   r   rF  s     r.   r   z6DocumentTextExtraction.process_word.<locals>.<genexpr>  s      '1A's   z)Unable to extract text from Word document)r1  rn  rS  rC  r^   r_   rk  )r>  	body_textheader_text
final_texts       r.   process_wordz#DocumentTextExtraction.process_word  s    !)))4	2CCIN	4HHS!YY ' +Y7' 
 "!	)BB9MM	  
  	CDD	s$   AA3 B 3	A?>A?	BBc                 p   	 t        j                  |       5 }g }|j                  D ]&  }|j                         }|s|j	                  |       ( 	 d d d        st        d      dj                  |      S # 1 sw Y   'xY w# t
        $ r*}t        d|        t        dt        |             d }~ww xY w)NzNo readable text found in PDF.r%   zFailed to extract PDF text: z!Failed to extract text from PDF: )	
pdfplumberrf  pagesextract_textrW   r_   r^   r<   rV   )r>  pdfpdf_textpager&   re   s         r.   process_pdfz"DocumentTextExtraction.process_pdf  s    	J+ .sII .D,,.D -	..  @AA99X&&. .  	J045?AxHII	Js3   B $A6A6%B 6A?;B 	B5%B00B5headerr|   c                     t        j                  dd| j                  dd      j                         j	                               S )Nr   rk   r   )r   r   r)   r   r   )r}  s    r.   normalize_excel_headerz-DocumentTextExtraction.normalize_excel_header  s9    vvNN3$**,224
 	
r0   c                    |dv rt        j                  |       }n|dv r	 t        j                  |       }i dg ddg dd	g d
dddgdddgdddgdddgdg ddddgdddgddd gd!g d"d#d$d%gd&d'gd(d(d)gd*d+d,gd-d.d/gd0d1gg d2d3}j                  D ci c]  }t
        j                  |      | }}i }|j                         D ]/  \  }}|D ]%  }	t
        j                  |	      }
|
|v s||
   ||<    / 1 g }|j                         D ]y  \  }}i }|j                         D ]N  }|j                  |      }|r4t        j                  ||         rt        ||         j                         nd4||<   P |j                  |       { |S # t        $ r t        j                  | d      }Y w xY wc c}w )5N)z.xlsxz.xls)z.csvlatin1)r[  r   )z	job titlejobtitledesignationr!   job_type)zjob typejobtypetyper   )zyears of experience
experiencezrequired experienceabout_companyzabout companyzcomapany aboutjob_summaryzjob summarysummaryresponsibilitieszroles & responsibilitiesdomain_requirementszdomain requirementsdomainrequirementscertification_requirements)zcertification requirementszcertifications requirementscertificationscertificationzrequired certificationzrequired certificationssecurity_clearance_requirementszsecurity clearance requirementszclearance requirements
onsite_jobz
onsite jobonsiter   zjob locationr   required_qualifications)zrequired qualificationsqualificationszqualification requiredpreferred_qualificationszpreferred qualificationszqualification preferredworking_hourszworking hoursbenefitsbenefitsearch_patternzsearch patternpatternrequirement_priorityzrequirement prioritypriorityzsalary rangesalary)zopen positionszrequired positionsznumber of positions)r   no_of_open_positionsrj   )pd
read_excelread_csvUnicodeDecodeErrorcolumnsr1  r  itemsiterrowskeysr   notnarV   r   rW   )r>  	extensiondfheader_name_mapcolexcel_headersheader_lookup	key_value
variationsvariantnormalized_variantnormalized_rowsr   rM  normalized_rowexcel_columns                   r.   process_excel_or_csvz+DocumentTextExtraction.process_excel_or_csv  s   ))y)B("?[[+
J
7
 "#_
 o/?@	

 M95
 !35O P
 "$9;O#P
 )  +@
 .0QSk/l
 <2
 ^Z8
 &'n
 ')CE^(_
 o.
 Y/
  /;!
" #%;Z$H#
$ ,X6$c'
, ]_\f\fgUX/FFsKSPgg%4%:%:%< 	!Iz% %;%R%RSZ%["%6/<=O/PM),		 kkm 	3FAsN,113 	,00; $\1B(C L)*002 y) "">2	3 e & ?[[X>?2 hs   F "F< F98F9N)r   r   r   rC  rS  rk  rn  staticmethodrt  r|  rV   r  r  r   r0   r.   r1  r1  >  sm    "0TdCB E E( J J$
s 
s 
 8 8r0   r1  c                 r   	 t         j                  j                  d      j                  |       }t        j                  j                  |      }|j
                  }|st        d       y|j                  }|st        d       y|j                  j                   d|j                  j                   j                         }|j                  }|j                   d|j                   }	t        d	d
      \  }
}|
j!                  ||	      }
t#        |j                  |j                  d      }t$        j&                   d| d}t        d|       t#        |j                  |j                  d      }t$        j&                   d| d}|r7t#        |j                  |j                  d      }t$        j(                   d| }n7t#        |j                  |j                  d      }t$        j&                   d| d}t        d|       t*        j                  j-                  |      j                  d      }|D cg c]:  }|j.                  r,|j.                  j
                  r|j.                  j
                  < }}g }|j0                  r:t3        |j0                        }|D cg c]  }|j
                  r|j
                   }}t5        t7        ||z               }||v r|j9                  |       |j!                  ||j:                  ||	||      }t        d       t=        |
|j                         ||t$        j>                  d
       t        d       y
c c}w c c}w # t         j@                  $ r t        d       Y yt        j@                  $ r t        d       Y ytB        $ r}t        d|       Y d }~yd }~ww xY w)Ncandidate_idr6   r7   z2Shortlist email skipped: Candidate email not foundFzHShortlist Mobile number skipped: Candidate Mobile number email not foundrk   r   shortlisted_candidate_htmlTr  )r   tracking_tokenjobz/job/l0//zGenerated Job URL:	shortlist/shortlist-details/client_submission_consentz"/client_submission_consent/?token=zGenerated Shortlist URL:r   user)r.  resume_sourcer   r  form_urljd_urlz-----mail sendingr-   r"   rK   ra   rD   r+   z-----mail sent successfullyz'Shortlist email error: Resume not foundz#Shortlist email error: JD not foundz!Shortlist email unexpected error:)"r   r=   select_relatedr   r   rc   r<   mobile_numberr  r  r  r   r   r6   r7   r/   r  rA   r   r   	INTERVIEWr   r
  r  r!  r  listsetremover  rg   r  DoesNotExistr_   )r6   r7   consent_requiredresumer   rK   	to_mobiler.  r   r  r-   r"   token_careerr  r5   r  assigned_usersarecruiter_emails	dm_emailsdelivery_managersr  ra   re   s                           r.   send_shortlist_emailr    s}   z#++::>JNN O 
 &&***7<<FG((	\]"//::;1V=P=P=Z=Z<[\bbdLL	",,-Qrxxj9*+GQUV..) ! 

 ,F,<,<bhhNOO$H\N!<"F+$V%5%5rxxMoo&&9%B()9)9288E`aE",,--OPUwWH()9)9288[QE"//**=eWAFH((3!))00 1 

.
  	
 #1
vv!&&,, FFLL
 

 	<< <R\\ J#488 I 
 -	9:;	y X&{{) ..)  
 	!"//	
> 	+,{
n ** 78)) 34 115sP   A(M +M F0M 5?M4)M M<BM 
M N69N6N6 N11N6c                 6   t         j                  j                  | j                        j	                         }t
        j                  j                  | j                        j	                         }|r|sy|j                  }t        j                  j                  |      j	                         }|sy|j                  }| j                  j                  d      }|j                   d|j                   }|j                   d|j                   }t        j                    d| }	t#        d	d
      \  }
}|
j%                  |j&                        }
|j%                  ||	      }t)        |
|j+                         |j,                  t        j.                  d
       y
)Nr  r  Fr   %d %b %Y %I:%M %prk   r   r  $candidate_interest_confirmation_htmlTr  r,  )r.  r  r  )r   r=   r
  job_idfirstr   r6   r  r   r  interview_datetimestrftimer  r  r7   r   r   r/   r  r   rg   r   rc   r  )matched_profiler   r  candidate_profileassigned	recruiterinterview_dtr.  r  r  r-   r"   s               r.   send_thanks_notificationsr    s   		"	"	)	)$$ 
* 
eg   ''..!++ / eg  V++&&"&-335HI"55>>?RSL)445Q7H7R7R6STN(()288*5N//""5n5EFH&.MGT
 nn,,  G ;;%  D
 ZZ\"((++& r0   c                     	 t        d|        | j                  d      \  }}t        d|       t        d|       t        j                  j	                  ||      j                         }|st        d       yt        d|j                         ||_        d	|_        t        j                         |_        |j                          t        d
       t        |       y# t        $ r)}t        d       t        j                           Y d }~yd }~ww xY w)NzProcessing token:r   r3   r4   )r6   r  u   ❌ No matched profile foundFzMatched found:
Interestedu   ✅ Status updatedTu   ❌ ERROR OCCURRED)r<   splitr   r=   r
  r  r?   accepted_messagerL   r   r`   accepted_atr   r  r_   	traceback	print_exc)r  
reply_text
interestedr6   r7   matchedre   s          r.   process_shortlist_replyr    s    #!>2)//4	5lI&h$,,33 4 
 %' 	
 01

+#- %&lln"#!'* "#s   A4C 7A#C 	D$DDc                    t        t        j                               }|j                  d      }|j                  d      }|t	        d      z   j                  d      }t        | j                  | j                  d      }	t        j                   d|	 }d| d| d| d	| d
| d| d| dt        j                   d| d}
|
S )Nz%Y%m%dT%H%M%SZ   rP   l0_interview/interview_welcome/?token=zXBEGIN:VCALENDAR
VERSION:2.0
PRODID:-//AutoRecruiter//EN
METHOD:REQUEST
BEGIN:VEVENT
UID:z	
DTSTAMP:z	
DTSTART:z
DTEND:z
SUMMARY:Interview - z*
DESCRIPTION:Online Interview\nJoin here: z

LOCATION:z!
ORGANIZER;CN=ITConnectUS:MAILTO:z(
ATTENDEE;CN=Candidate;RSVP=TRUE:MAILTO:z5
STATUS:CONFIRMED
SEQUENCE:0
END:VEVENT
END:VCALENDAR)rV   r9   r:   r  r   rA   r6   r  r   r  r  )r  candidate_emailr  interview_linkjd_titleuiddtstampdtstartdtendr5   ics_contents              r.   generate_ics_filer  "  s   
djjl
C##$45G##$45GIb11;;<LME !!E !**++EeWMN	
 e ) )  'j )55C4D E"# $++3+C+C*D E22A1B C	 * r0   c                    	 t         j                  j                  | j                        }t        j                  j                  | j
                        }|j                  }| j                  }t        | j
                  | j                  d      }t        j                   d| }t        j                  j                  |      j                  d      j                         }|r8|j                  r,|j                  j                   r|j                  j                   nd }|j"                   d|j$                   }	|j'                  d      }
t)        d	d
      \  }}|j+                  |j,                        }|j+                  |	|j,                  |
|      }t/        | |j                   |||j,                        }t1        ||j3                         t        j4                  |j                   g|r|gng       }d|_        |j9                  d|d       |j;                  d       y
# t<        $ r}t?        d|       Y d }~yd }~ww xY w)Nr  r  r  r  r   r  rk   r  interview_scheduled_calendarTr  r,  )r.  r   r  r  rC   r$   zinterview_invite.icsztext/calendar; method=REQUEST)filenamecontentmimetypeFrG   zICS email error:) r   r=   r   r  r   r6   r  r  rA   r   r  r   r
  r  r  r  rc   r  r  r  r/   r  r   r  r   r   r  r[   attachr\   r_   r<   )r  r   r  	candidater  r5   r  r  recruiter_emailr.  formatted_dtr-   r"   r  rc   re   s                   r.   send_interview_calendar_inviter  I  s   >&&**1G1G*H#++///:S:S/T''	&99$_%>%>@V@VXfg !!""<UGD 	 ##**b*1@@HNNP19hmmPXP]P]PcPc(----im%00193F3F2GH#,,-@A*+ISWX..ll ! 
 {{)ll+)	  
 (OOLL
 // $3 
 !'+4 	 	
 	


'  !$s   HH! !	I *H;;I c                    t        t              }| D ]   }||j                     j                  |       " |j	                         D ]  \  }}|r|j
                  sg }t               }|D ]  }|j                  }|j                  }|j                  d|j                   d|j                   d|r|j                  nd dt        j                  |j                        j                  d       d	       |st!        |      }	|	D ]*  }
|
j
                  s|j#                  |
j
                         ,  t%        |      }t'        dd	
      \  }}|j)                  |      }|j)                  |j*                  xs |j,                  dj/                  |      d      }t1        ||j3                         |j
                  t        |      t4        j6                  d	        y )Nz#
                JD Reference ID : z#
                Job Title       : z#
                Client          : zN/Az#
                Assigned Time   : z%d-%m-%Y %I:%M %pz
                jd_assignment_notificationFr  )jd_countrj   z6https://auto-recruiter.itconnectus.com/job_description)recruiter_namejd_listr(  r  )r   r  r  rW   r  rc   r  r   r!  r   r   client_namer   	localtime
created_atr  r  addr   r/   r  r  r   r^   rg   r   r   r  )assignmentsgroupedassignr  recruiter_assignmentsjd_linesra   r   
client_objr  r  r
  r-   r"   s                 r.   notify_recruiter_multiple_jdsr    s   $G ,##F+, -4MMO 0
(	(	E	+ 	0FBJOO##%#3#3"4 5##%<<. 1#=G:#9#9U"S T##+#5#5f6G6G#H#Q#QRe#f"g h	 $@$L!+ 0Bxx!bhh/0	0& ,-*+GQVW.. ! 
 {{$//E93E3EGGH%N  
 	__9o//	
S0
r0   c                       e Zd Zd Zd Zy)DBAuthFiltersc                 "   | r| j                   j                  ddg      j                         s| j                  r,t	        t
        j                  j                  dd            }|S t	        | j                  j                  dd            }|S g S )N	RecruiterImplementer Super Adminname__inr!  Tr  )	groupsr
  r"  is_superuserr  r   r=   r  client_mappings)r  
client_idss     r.   get_client_by_auth_userz%DBAuthFilters.get_client_by_auth_user  s    {{!!K9R+S!T[[]aearar!%%11+D1I
 	 "((44[t4L
  Ir0   c                 d   | r,| j                   j                  dg      j                         r<t        t        j
                  j                  |       j                  dd            }|S | j                   j                  dg      j                         s| j                  r,t        t        j
                  j                  dd            }|S t        | j                  j                  d	d            }t        t        j
                  j                  |
      j                  dd            }|S g S )Nr  r  )r  r   Tr  r  r7   r!  )client_id__in)
r  r
  r"  r  r   r=   r  r   r   r!  )r  jd_idsr"  s      r.   get_jd_by_auth_userz!DBAuthFilters.get_jd_by_auth_user  s   {{!!K=!9@@B$$+++6BB4dBS$ M ##.G-H#IPPRVZVgVg%--99'9M M "((44[t4L
 %--V*V5 [t[4 MIr0   N)r   r   r   r#  r'  r   r0   r.   r  r    s     r0   r  c                    	 t         j                  j                  | j                        j	                         }t
        j                  j                  | j                        j	                         }|r|sy|j                  }|j                   d|j                   j                         }|j                  d      }t        dd      \  }}|j                  ||j                        }|j                  ||j                  d	      |j                  d
      |      }t        j                  j                  |      j!                  d      }	|	D 
cg c]:  }
|
j"                  r,|
j"                  j$                  r|
j"                  j$                  < }}
g }|j&                  r:t)        |j&                        }|D cg c]  }|j$                  r|j$                   }}t+        t-        |            }t+        t-        |            }|syt/        ||j                         ||t0        j2                  d       yc c}
w c c}w # t4        $ r}t7        d|       Y d }~yd }~ww xY w)Nr  r  Frk   followup_datetimefollowup_candidate_mailr  r-  response
rec_remark)r.  candidate_responser,  followup_timer   r  r  TzFollow-up reminder mail error:)r   r=   r
  r  r  r   r6   r  r  r  r   r   r/   r  r   r   r  r  rc   r!  r  r  r  rg   r   r  r_   r<   )profiler+  r   r  r  r.  r.  r-   r"   r  r  r  r  r  r  	to_emailsra   re   s                     r.   send_followup_mailr1    s8   F&&--.. . 

%' 	 $++22'' 3 

%' 	 ''	%00193F3F2GHNNP %89*+DeT..)|| ! 

 {{)'||J7||L1'	  
 "))00 1 

.
  	
 #1
vv!&&,, FFLL
 

 	<< <R\\ J $588 I 
 -./	Y(	//	
 =
,  .2sC   A4H< 7CH< ?H2)H< 8H7,H< -H< 2
H< <	IIIc                     t        j                         } t        j                  j	                  g       }|D ]  }d}|j
                  xs g }|D ]  }|j                  d      }|s|j                  d      r)t        |j                  dd            }t        |      }|sRt        j                  |      r|j                  t        d            }|t        |	      z
  }	t        d
|        t        d|	       t        d|       |	| cxk  r|k  sn t        d       t        ||       d|d<   d} |s||_        |j                  dg        y )N)candidate_responsesFr)  reminder_sentreminder_before_minutes<   zAsia/Kolkata)tzinforP   zNow:z	Reminder:z	Followup:zSending reminder mail...Tr3  r  )r   r`   r   r=   excluder3  r   intr   is_naiver)   r   r   r<   r1  r   )
r`   profilesr/  updated	responsesrY  followupreminder_beforefollowup_dtreminder_times
             r.   process_followup_remindersrB  7  sI   
,,.C!))11b1IH *@//52	 !	Auu01Huu_%!!%%(A2"FGO(2K  -)11.9Q1R')O*LLM&#+}-+{+2{201"7A.%)/"C!	F *3G'LL(='>L?U*@r0   )F)NNcareer)NF)   )fr   r   urllib.parser   r   r   r   r$   sklearn.feature_extraction.textr   sklearn.metrics.pairwiser   django.contrib.auth.modelsr   django.core.mailr   django.confr   modelsr
   rb  r   r   r   r   r   r   r   r   r   loggingr_  r]  r8  lxmlr   rv  pandasr  django.utilsr   datetimer   django.core.validatorsr   django.core.exceptionsr   smtplibr   r  r9   collectionsr   rx   django.utils.dateparser   zoneinfor   rc  dirname__file__BASE_DIRr^   TEMPLATE_FILErf  rj  loadr(   r/   	getLoggerr   rX   rA   rg   r   r   r   r   r   r   rV   r   r   r   floatr   r  r  r  r$  r)  r/  r1  r  r  r  r  r  r  r  r1  rB  r   r0   r.   <module>r^     s      	   ; 6 + )    	 `  `  `        !  1 2 )   #  1 77??277??845Xy.BXY	-  A499Q<L " 
		8	$*~n7r;
"G(g gR# # $"4H)(&s &C &E &
;	@%N 
		8	$24Q Qf{T>@%N%N?B7
r( (THT0@c0   s   GG