o
    wh5                     @   s  d dl Z d dlZd dlmZmZmZmZ d dlmZ d dl	m
Z
 d dlZd dlmZ d dlmZ d dlmZ ejejd eeZeG d	d
 d
ZeG dd dZeG dd dZG dd dZG dd dZG dd dZdd Zedkre  dS dS )    N)DictListOptionalTuple)	dataclass)SequenceMatcher)
ChatOllama)PromptTemplate)HumanMessage)levelc                   @   s"   e Zd ZU dZeed< eed< dS )
Departmentz%Data class for department informationidnameN)__name__
__module____qualname____doc__int__annotations__str r   r   I/var/www/eduai.edurigo.com/doc_train/edurigo_ai/TNA/production/tna_dep.pyr      s   
 r   c                   @   s&   e Zd ZU dZeed< ee ed< dS )
TNARequestzData class for TNA requestuser_promptorganization_departmentsN)r   r   r   r   r   r   r   r   r   r   r   r   r      s   
 r   c                   @   s:   e Zd ZU dZeed< eed< eed< eed< eed< dS )TNAResponsezData class for TNA responsedepartment_iddepartment_nameinferred_departmentsimilarity_scorematchedN)	r   r   r   r   r   r   r   floatboolr   r   r   r   r      s   
 r   c                   @   sD   e Zd ZdZddefddZdedefdd	Zd
edefddZdS )DepartmentInferenceEnginez&Handles department inference using LLM
gemma3:12b
model_namec              
   C   sN   zt |d| _td|  W dS  ty& } z	td|   d}~ww )zInitialize the LLM model)modelzInitialized LLM with model: zFailed to initialize LLM: N)r   llmloggerinfo	Exceptionerror)selfr%   er   r   r   __init__'   s   z"DepartmentInferenceEngine.__init__r   returnc              
   C   s   t dgdd}z%|j|d}| jt|dg}|j }| |}t	d|  |W S  t
yG } ztd|  W Y d}~d	S d}~ww )
z
        Infer the most relevant department for the given user prompt
        
        Args:
            user_prompt: User's business goal or challenge
            
        Returns:
            Inferred department name
        r   a^  
            You are an expert business analyst specializing in organizational structure and training needs.
            
            Based on the following business goal or challenge, identify the SINGLE most relevant department.
            
            User Goal/Challenge: {user_prompt}
            
            Common departments include:
            - Sales
            - Marketing
            - HR (Human Resources)
            - Operations
            - Finance
            - Product Management
            - Development/Engineering
            - Customer Service
            - Quality Assurance
            - Research and Development
            
            Instructions:
            1. Analyze the user's goal/challenge carefully
            2. Identify which department would be primarily responsible for addressing this goal
            3. Return ONLY the department name (e.g., "Sales", "Marketing", "HR")
            4. Use general department names, not specific subdivisions
            5. If the goal spans multiple departments, choose the PRIMARY one
            
            Department:
            )input_variablestemplate)r   )contentzInferred department: zError in department inference: NUnknown)r	   formatr'   invoker
   r2   strip_clean_department_namer(   r)   r*   r+   )r,   r   prompt_templateformatted_promptresponseinferred_deptr-   r   r   r   infer_department0   s    
 

z*DepartmentInferenceEngine.infer_department	dept_namec                 C   sD   | dd dd}| dd dd}|dd }|d}|S )	z#Clean and normalize department namezDepartment: r   zTeam:Team
r   z "')replacesplitr6   )r,   r=   r   r   r   r7   k   s
   
z0DepartmentInferenceEngine._clean_department_nameN)r$   )r   r   r   r   r   r.   r<   r7   r   r   r   r   r#   $   s
    	;r#   c                   @   s@   e Zd ZdZedededefddZededefdd	Zd
S )SimilarityMatcherzPHandles string similarity matching between inferred and organization departmentsstr1str2r/   c                 C   s   t | }t |}td|| }||krdnd}d}||v s$||v r&d}t| }t| }|rE|rEt||t|| }	nd}	t	||||	}
|
S )z
        Calculate similarity between two strings using multiple methods
        
        Args:
            str1: First string
            str2: Second string
            
        Returns:
            Similarity score between 0 and 1
        Ng      ?        g?)
rC   _normalize_stringr   ratiosetrB   lenintersectionunionmax)rD   rE   	str1_norm	str2_normseq_similarityexact_matchsubstring_matchwords1words2word_similarityfinal_scorer   r   r   calculate_similarity|   s   

z&SimilarityMatcher.calculate_similaritysc                 C   sl   |   } tdd| } tdd| } dddddddd	d	d
d
d
dd
d}| D ]
\}}| ||} q'|  S )zNormalize string for comparisonz[^a-zA-Z0-9\s]r>   z\s+ hritrdzcustomer supportproductdevelopment	developer)zhuman resourceszhuman resourcezinformation technologyzresearch and developmentzresearch & developmentzcustomer servicezcustomer carezproduct managementzproduct managerzsoftware developmentzsoftware engineeringengineering
programmerprogramming)lowerresubitemsrA   r6   )rX   replacementsoldnewr   r   r   rG      s*   z#SimilarityMatcher._normalize_stringN)	r   r   r   r   staticmethodr   r!   rW   rG   r   r   r   r   rC   y   s    'rC   c                   @   st   e Zd ZdZddedefddZded	efd
dZ	ded	e
fddZdedee d	efddZded	efddZdS )	TNASystemz:Main TNA System class that orchestrates the entire processr$   Q?r%   similarity_thresholdc                 C   s,   t || _t | _|| _td|  dS )z
        Initialize TNA System
        
        Args:
            model_name: LLM model name
            similarity_threshold: Minimum similarity score for department matching
        z2TNA System initialized with similarity threshold: N)r#   inference_enginerC   similarity_matcherrm   r(   r)   )r,   r%   rm   r   r   r   r.      s   
zTNASystem.__init__request_datar/   c              
   C   s   zB|  |}| j|j}| ||j}|d | jkr-t|d j|d j	||d dd}ntdd||d dd}t
d|  |W S  tye } zt
d	|  tddd
dddW  Y d}~S d}~ww )a  
        Process TNA request and return department mapping result
        
        Args:
            request_data: Dictionary containing user_prompt and organization_departments
            
        Returns:
            TNAResponse with department mapping result
        r   
departmentT)r   r   r   r   r    r   NullFzTNA processing completed: zError processing TNA request: ErrorrF   N)_parse_requestrn   r<   r   _find_best_matchr   rm   r   r   r   r(   r)   r*   r+   )r,   rp   tna_requestr   
best_matchr:   r-   r   r   r   process_request   s@   

zTNASystem.process_requestc                 C   s"   dd |d D }t |d |dS )z)Parse request data into TNARequest objectc                 S   s    g | ]}t |d  |d dqS )r   r   r   r   )r   ).0deptr   r   r   
<listcomp>  s    z,TNASystem._parse_request.<locals>.<listcomp>r   r   r   r   )r   )r,   rp   departmentsr   r   r   rt   	  s   zTNASystem._parse_requestr;   org_departmentsc              	   C   sz   ddd}|D ]}| j ||j}||d kr||d< ||d< qtd| d|d r/|d jnd d	|d d
d |S )zAFind the best matching department from organization's departmentsNrF   )rq   r   r   rq   zBest match for 'z': Nonez	 (Score: z.4f))ro   rW   r   r(   r)   )r,   r;   r   rw   r{   r   r   r   r   ru     s   6zTNASystem._find_best_match	json_datac              
   C   s   zt |}| |}d|j|j|jt|jd|j| j	dW S  t j
yC } ztd|  dd| ddd	W  Y d
}~S d
}~w tye } ztd|  dt|ddd	W  Y d
}~S d
}~ww )z
        Process JSON request and return JSON response
        
        Args:
            json_data: JSON string with request data
            
        Returns:
            Dictionary with response data
        T   )successr   r   r   r   r    threshold_usedzJSON decode error: FzInvalid JSON format: r   rr   )r   r+   r   r   NzProcessing error: )jsonloadsrx   r   r   r   roundr   r    rm   JSONDecodeErrorr(   r+   r*   r   )r,   r   rp   r:   r-   r   r   r   process_json_request)  s8   




zTNASystem.process_json_requestN)r$   rl   )r   r   r   r   r   r!   r.   r   r   rx   r   rt   r   r   ru   r   r   r   r   r   rk      s    3rk   c               	   C   s   t dd} dddddddd	d
ddddddddddgd}td | t|}td td|d   td|d   td|d   td|d   td|d   td|d   td |d!   d"S )#zExample usage of the TNA Systemrl   )rm   z%I Want to improve my technical skills   
Operationsry      HR   Finance   zProduct Management   sales   	Developerr}   zProcessing TNA request...z
TNA Results:z	Success: r   zDepartment ID: r   zDepartment Name: r   zInferred Department: r   zSimilarity Score: r   z	Matched: r    zThreshold Used: r   N)rk   printr   r   dumps)
tna_systemsample_requestresultr   r   r   mainS  s(   
r   __main__)r   loggingtypingr   r   r   r   dataclassesr   difflibr   rd   langchain_ollamar   langchain.promptsr	   langchain.schemar
   basicConfigINFO	getLoggerr   r(   r   r   r   r#   rC   rk   r   r   r   r   r   <module>   s2    
UL !
