o
    (ri5                     @   s  d dl Z d dlZd dlmZmZmZmZ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 d dlmZmZmZmZ d dlmZmZ d dlmZ d d	lmZmZ d d
lmZm Z  d dl!m"Z" d dl#m$Z$m%Z%m&Z& d dl'm(Z( ee)* j+j+Z,e,d Z-e-j.ddd eddgdZ/G dd deZ0e/1dedee(fdede fddZ2e/1dee(eefde0de defdd Z3G d!d" d"eZ4G d#d$ d$eZ5d%e6d&e7fd'd(Z8e/j1d)e4d*edee(eefd+ee de defd,d-Z9e/:d.ee(eefd/e6de defd0d1Z;e/1d2ee(eefd3e5de defd4d5Z<e/j:d6ee d*ee(eefde defd7d8Z=e/j:d9ed*ee(eefd:e>de defd;d<Z?e/:d=deefd:e>d>ee6 defd?d@Z@dS )A    N)	APIRouter
UploadFileFileDependsHTTPExceptionstatus)FileResponse)Path)SessionselectSQLModel)ListDictAnyOptional)JWTErrorjwt)datetime)get_sessionsettings)ResumeUser)extract_text_from_file)parse_resume_contentmatch_resume_to_jdbulk_rank_resumes)get_current_useruploadsT)parentsexist_okz/resumesresumes)prefixtagsc                   @   s  e Zd ZU eed< dZee ed< dZee ed< dZee ed< dZ	ee ed< dZ
ee ed< dZee ed< dZee ed	< dZee ed
< dZee ed< dZee ed< dZee ed< dZee ed< dZee ed< dZee ed< eed< eed< dS )SaveParsedRequestfilenameNnameemailphonelocationlinkedin_url
github_urlskillssummary
experienceprojects	educationcertifications	languagesothersraw_text	file_path)__name__
__module____qualname__str__annotations__r%   r   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2    r:   r:   D/var/www/html/Resume-Parser/resume-parser-inhouse/routers/resumes.pyr#      s$   
 r#   z/parse-only.filecurrent_userc           	         s   t  d}ddd | jD }| d| }t| }t|d}t| j	| W d   n1 s5w   Y  | j	
d t| I dH }|rM| s\| rVt| td	d
dt|}||d< | j|d< t||d< |S )z:Parses a resume and saves the file to disk for previewing.%Y%m%d_%H%M%S c                 S       g | ]}|  s|d v r|qS z._-isalnum.0cr:   r:   r;   
<listcomp>5        zparse_only.<locals>.<listcomp>_wbNr     z!Empty or unreadable file content.status_codedetailr3   r$   r4   )r   nowstrftimejoinr$   
UPLOAD_DIRopenshutilcopyfileobjr<   seekr   stripexistsosremover   r   r8   )	r<   r=   	timestamp	safe_namefinal_filename	dest_pathbuffertext_contentparsed_datar:   r:   r;   
parse_only/   s&   

rb   z/save-parseddatasessionc                    s  | j r!|tttj | j k }|r!tdd| j  ddtdi d| jd| jd| j d| j	d	| j
d
| jd| jdd| jidd| jidd| jidd| jidd| jidd| jidd| jidd| jidd| jid| j}|| |  || |S )z;Saves manually verified/edited resume data to the database.rK   zCandidate with email z already exists.rL   r$   r%   r&   r'   r(   r)   r*   r+   contentr,   r-   r.   r/   r0   r1   r2   raw_datatextr4   Nr:   )r&   execr   r   wherefirstr   r$   r%   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   addcommitrefresh)rc   r=   rd   existingresumer:   r:   r;   save_parsedM   sX    

	









rp   c                   @   s6   e Zd ZU eed< ee ed< eeeef  ed< dS )UploadResponsesuccess_countr    skippedN)	r5   r6   r7   intr9   r   r   r   r8   r:   r:   r:   r;   rq   n   s   
 rq   c                   @   s   e Zd ZU eed< dS )JDMatchRequestjd_textN)r5   r6   r7   r8   r9   r:   r:   r:   r;   ru   s   s   
 ru   r*   returnc              
      s   | rd| vr	i S z[|  ddd }t 4 I dH ;}|d| I dH }|jdkrK| }|d|d|d	d
W  d  I dH  W S W d  I dH  W i S 1 I dH s]w   Y  W i S  ty~ } ztd|  W Y d}~i S d}~ww )z3Simple GitHub scraper to fetch public profile data.z
github.com/Nzhttps://api.github.com/users/   public_repos	followersbio)r{   r|   r}   zError enriching GitHub data: )	rstripsplithttpxAsyncClientgetrM   json	Exceptionprint)r*   usernameclientresponserc   er:   r:   r;   enrich_github_datav   s0   
r   z/upload)response_modelfilesc                    s  g }g }h d}| D ]Z}|j }tj|d  }||vr(||dd qzt d}	d	dd |j D }
|	 d	|
 }t
| }t|d
}t|j| W d    n1 s^w   Y  |jd t|I d H }|rv| s||dd W qt|}|dds||dd W q|d}|r|tttj|k }|r||d| dd W q|d}|rt|I d H ni }td(i d|d|dd|d|dd|dd|dd|d|d|ddd|didd|didd|didd|did d|d id!d|d!id"d|d"id#d$|id%t|}|| || W q tyf } z||d&t| d W Y d }~qd }~ww |ry|  |D ]}|| qpt t!|||d'S ))N>   .pdf.txt.docx   zUnsupported file format)r$   reasonr>   r?   c                 S   r@   rA   rB   rD   r:   r:   r;   rG      rH   z"upload_resumes.<locals>.<listcomp>rI   rJ   r   zEmpty or unreadable content	is_resumeTzNot a valid Resumer&   zEmail z existsr*   r$   r%   r'   r(   r)   r,   )re   github_statsr-   re   r.   r/   r+   r0   r1   r2   rf   rg   r4   zSystem error: )rr   r    rs   r:   )"r$   rY   pathsplitextlowerappendr   rO   rP   rQ   rR   rS   rT   rU   r<   rV   r   rW   r   r   rh   r   r   ri   r&   rj   r   r8   rk   r   rl   rm   rq   len)r   r=   rd   uploaded_resumesskipped_filesallowed_extensionsr<   r$   extr[   r\   r]   r^   r_   r`   ra   r&   rn   r*   github_extraro   r   rr:   r:   r;   upload_resumes   s   






	

r   z/searchqc                    s&  | tt }| sdd |D S g }|D ]@}|jr"|jdnd}|jr-|jdnd}|jr8|jdnd}d|j d| d| d|d d	  d
	}	|	|j
|	d qt| |}
g }|
D ](}t|d t fdd|D d }|r|	||dd|ddd qat|dd ddS )Nc                 S   s   g | ]}|d ddqS )d   zNo queryro   scorer   r:   rE   r   r:   r:   r;   rG      s    z"search_resumes.<locals>.<listcomp>re   r?   zName: 	
Skills: 

Summary: 
Experience: i  z...)idrg   r   c                 3   s"    | ]}t |j kr|V  qd S N)r8   r   r   match_idr:   r;   	<genexpr>   s     z!search_resumes.<locals>.<genexpr>r   r   pitchr   c                 S      | d S Nr   r:   xr:   r:   r;   <lambda>       z search_resumes.<locals>.<lambda>Tkeyreverse)rh   r   r   allr+   r   r,   r-   r%   r   r   r   r8   nextsorted)r   r=   rd   r    resumes_briefr   r+   r,   exp	full_textmatchesranked_resultsmatch
resume_objr:   r   r;   search_resumes   s0   (


r   z/matchrequestc                    sR  | tt }|sg S g }|D ]M}|jr|jdnd}|jr(|jdnd}|jr3|jdnd}|jr>|jdnd}	d|j	 d|j
 d| d| d| d|	 }
||j	|
d	 qt| j|}g }|D ].}|d
 t fdd|D d }|r||j	|j
|dd|dd|dg d qjdd |D }t|dd ddS )Nre   r?   zCandidate ID: z
Name: r   r   r   z
Projects: )r   profiler   c                 3   s    | ]
}|j  kr|V  qd S r   )r   )rE   r   r_idr:   r;   r     s    zmatch_jd.<locals>.<genexpr>r   r   r   zNo analysis provided.missing_skills)	resume_idr%   r   r   r   c                 S   s   g | ]
}|d  dkr|qS )r   r   r:   )rE   resr:   r:   r;   rG   '  s    zmatch_jd.<locals>.<listcomp>c                 S   r   r   r:   r   r:   r:   r;   r   )  r   zmatch_jd.<locals>.<lambda>Tr   )rh   r   r   r   r+   r   r,   r-   r.   r   r%   r   r   rv   r   r   )r   r=   rd   r    
candidatesr   r+   r,   r   r.   contextrankingsresultsrankr   r:   r   r;   match_jd  s8   ,



	r   rx   c                    s   | tt S r   )rh   r   r   r   )r=   rd   r:   r:   r;   list_resumes+  s   r   z/{resume_id}r   c                    s"   | t| }|stddd|S )zGet a single resume by ID.  zResume not foundrL   )r   r   r   )r   r=   rd   ro   r:   r:   r;   
get_resume/  s
   r   z/file/{resume_id}tokenc                    s   |r+zt j|tjtjgd}|d}|stdddW n ty*   tdddw tddd|t| }|s?tdd	d|j	rIt
j|j	s`t|j }| rZt||jd
dS tdddt|j	|jd
dS )N)
algorithmssubi  zInvalid tokenrL   zInvalid or expired tokenzAuthentication token requiredr   zResume record not foundinline)r$   content_disposition_typez`Original resume file not found. It may have been uploaded before persistent storage was enabled.)r   decoder   
SECRET_KEY	ALGORITHMr   r   r   r   r4   rY   r   rX   rR   r$   r   )r   r   rd   payloadr   ro   fallback_pathr:   r:   r;   get_resume_file7  s*   

r   )ArY   r   fastapir   r   r   r   r   r   fastapi.responsesr   rT   pathlibr	   sqlmodelr
   r   r   typingr   r   r   r   joser   r   r   databaser   r   modelsr   r   utilsr   services.openai_servicer   r   r   routers.authr   __file__resolveparentBASE_DIRrR   mkdirrouterr#   postrb   rp   rq   ru   r8   dictr   r   r   r   r   r   rt   r   r   r:   r:   r:   r;   <module>   sf     "& W&&)"&*