o
    cBj3                     @  s   U d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	m
Z
mZmZmZ ddlZddlmZ ddd	d
ddddddd
Zded< G dd dZdS )zLPer-BID customer sentiment configuration (keywords, rubric, detection mode).    )annotationsN)contextmanager)AnyDictListOptionalTuple)
DictCursorhybridTzthank you, thanks, great, excellent, happy, satisfied, love, perfect, wonderful, appreciate, good experience, helpful, amazing, pleasedzangry, frustrated, disappointed, terrible, worst, unhappy, complaint, refund, cancel, bad service, not happy, upset, horrible, never againz-okay, fine, maybe, not sure, average, alrightzClassify overall customer mood from their words only (ignore agent tone). positive = satisfied, grateful, or enthusiastic; negative = frustrated, angry, or complaining; neutral = factual, mixed, or unclear.      Active
detection_modecustomer_onlypositive_keywordsnegative_keywordsneutral_keywordsprompt_rubrickeyword_positive_thresholdkeyword_negative_thresholdmax_keyword_hitsstatusDict[str, Any]DEFAULT_SENTIMENT_CONFIGc                   @  s   e Zd Zdd Zedd Zd5ddZd6ddZd7ddZd8ddZ	d9ddZ
ed:ddZed;ddZed<d=d d!Zd>d&d'Zd(d)d?d-d.Zd@d1d2ZdAd3d4ZdS )BSentimentConfigHandlerc              	   C  sJ   || _ |dd|dd|dd|dd|d	d
dtdd| _d S )NDB_HOSTz	127.0.0.1DB_PORTi  DB_USERadminDB_PASSWORD DB_NAMEvoicebot_clusterutf8mb4T)hostportuserpassworddatabasecharsetcursorclass
autocommit)configgetr	   	db_config)selfr-    r1   C/home/aiteam/pcaa-dev/dashboard-backend/sentiment_config_handler.py__init__(   s   




zSentimentConfigHandler.__init__c                 c  sF    d }zt jdi | j}|V  W |r|  d S d S |r"|  w w )Nr1   )pymysqlconnectr/   close)r0   connr1   r1   r2   get_connection5   s   
z%SentimentConfigHandler.get_connectionreturnNonec                 C  s@   |   }| }|d W d    d S 1 sw   Y  d S )Na'  
                CREATE TABLE IF NOT EXISTS business_sentiment_config (
                  id INT AUTO_INCREMENT PRIMARY KEY,
                  bid VARCHAR(50) NOT NULL,
                  detection_mode VARCHAR(32) NOT NULL DEFAULT 'hybrid',
                  customer_only TINYINT(1) NOT NULL DEFAULT 1,
                  positive_keywords TEXT,
                  negative_keywords TEXT,
                  neutral_keywords TEXT,
                  prompt_rubric TEXT,
                  keyword_positive_threshold INT NOT NULL DEFAULT 2,
                  keyword_negative_threshold INT NOT NULL DEFAULT 2,
                  max_keyword_hits INT NOT NULL DEFAULT 5,
                  status VARCHAR(50) DEFAULT 'Active',
                  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                  UNIQUE KEY unique_bid (bid),
                  INDEX idx_bid (bid)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
                )r8   cursorexecute)r0   r7   r;   r1   r1   r2   ensure_table?   s   
"z#SentimentConfigHandler.ensure_tablebidstrOptional[Dict[str, Any]]c                 C  s   |    t|}|  -}| }|d|f | }|s'	 W d    d S t|d|d< |W  d    S 1 s<w   Y  d S )Nz>SELECT * FROM business_sentiment_config WHERE bid = %s LIMIT 1r   )r=   r?   r8   r;   r<   fetchoneboolr.   )r0   r>   r7   r;   rowr1   r1   r2   
get_configY   s   
	$z!SentimentConfigHandler.get_configr   c                 C  s*   |  |}|r	|S tt}t||d< |S )Nr>   )rD   dictr   r?   )r0   r>   existingdefaultsr1   r1   r2   get_config_or_defaultsh   s   
z-SentimentConfigHandler.get_config_or_defaultsintc                 C  s   |  |rdS | |t dS )Nr      )rD   save_configr   )r0   r>   r1   r1   r2   seed_defaults_if_emptyp   s   
z-SentimentConfigHandler.seed_defaults_if_emptypayloadc                 C  s  |    t|}t|dpd  }|dvrd}||ddr$dnd|dp+d	|d
p1d	|dp7d	|dp=d	tdt|dpFdtdt|dpQdtdt|dp\d|dpddd
}|  w}| }| 	|}|r|dr|
d|d |d |d |d
 |d |d |d |d |d |d |d |f t|d W  d    S |
d||d |d |d |d
 |d |d |d |d |d |d f t|jW  d    S 1 sw   Y  d S )Nr   r
   >   llmr
   keywordr   TrJ   r   r   r!   r   r   r   r   r   r   r   r   r   r   r   ida  
                    UPDATE business_sentiment_config
                    SET detection_mode=%s, customer_only=%s,
                        positive_keywords=%s, negative_keywords=%s, neutral_keywords=%s,
                        prompt_rubric=%s, keyword_positive_threshold=%s,
                        keyword_negative_threshold=%s, max_keyword_hits=%s,
                        status=%s, updated_at=NOW()
                    WHERE id=%s AND bid=%s
                    aq  
                INSERT INTO business_sentiment_config
                (bid, detection_mode, customer_only, positive_keywords, negative_keywords,
                 neutral_keywords, prompt_rubric, keyword_positive_threshold,
                 keyword_negative_threshold, max_keyword_hits, status)
                VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
                )r=   r?   r.   striplowermaxrI   r8   r;   rD   r<   	lastrowid)r0   r>   rM   modefieldsr7   r;   rF   r1   r1   r2   rK   v   sv   



$z"SentimentConfigHandler.save_configvaluec                 C  s$   d dd t| p	d  D S )Nr!   c                 s  s    | ]	}|  r|V  qd S N)isalnum).0chr1   r1   r2   	<genexpr>   s    z;SentimentConfigHandler._normalize_header.<locals>.<genexpr>)joinr?   rQ   rR   rW   r1   r1   r2   _normalize_header   s   $z(SentimentConfigHandler._normalize_headerr   c                 C  s   | d u rdS t |  S Nr!   )r?   rQ   r^   r1   r1   r2   _clean_cell   s   z"SentimentConfigHandler._clean_cellNdefaultOptional[int]c              	   C  sB   t | pd }|s|S ztt|W S  ttfy    | Y S w r`   )r?   rQ   rI   float	TypeError
ValueError)rW   rb   textr1   r1   r2   
_parse_int   s   z!SentimentConfigHandler._parse_intfilenamecontentbytesList[Dict[str, Any]]c              
     s  t jt|pd d }|dkr{zddlm} W n ty+ } ztd|d }~ww |t	
|dd}|j}t|jdd	}|sDg S fd
d|d D  g }	|dd  D ]!rftfddD sgqW|	 fddtt D  qW|	S |dvrtdz|d}
W n ty   |d}
Y nw d}|
d d }zt j|dd}|j}W n, tjy   |
 pdgd }|d|dkrd}n|d|dkrd}Y nw tjt	|
|d}fdd|D S )Nr!   rJ   z.xlsxr   )load_workbookz)openpyxl is required to upload XLSX filesT)	data_only)values_onlyc                   s   g | ]}  |qS r1   ra   rZ   cellr0   r1   r2   
<listcomp>   s    z<SentimentConfigHandler._read_upload_rows.<locals>.<listcomp>c                 3      | ]}  |V  qd S rX   rp   rq   rs   r1   r2   r\          z;SentimentConfigHandler._read_upload_rows.<locals>.<genexpr>c                   s*   i | ]} | |t k r| nd qS )r!   )len)rZ   idx)headersrC   r1   r2   
<dictcomp>   s   * z<SentimentConfigHandler._read_upload_rows.<locals>.<dictcomp>>   .csvr!   z%Only CSV and XLSX files are supportedz	utf-8-sigzlatin-1,i    z,;	|)
delimiters;	)	delimiterc                   s.   g | ]}|rt  fd d| D r|qS )c                 3  ru   rX   rp   )rZ   vrs   r1   r2   r\     rv   zFSentimentConfigHandler._read_upload_rows.<locals>.<listcomp>.<genexpr>)anyvalues)rZ   rC   rs   r1   r2   rt     s   . )ospathsplitextr?   rR   openpyxlrm   ImportErrorrf   ioBytesIOactivelist	iter_rowsr   appendrangerw   decodeUnicodeDecodeErrorcsvSniffersniffr   Error
splitlinescount
DictReaderStringIO)r0   ri   rj   extrm   excworkbooksheetr   rowsrg   r   sampledialect
first_linereaderr1   )ry   rC   r0   r2   _read_upload_rows   sX   

z(SentimentConfigHandler._read_upload_rowsr!   rb   normalized_rowDict[str, str]namesc                G  s,   |D ]}|  |}||v r||   S q|S rX   )r_   )r0   r   rb   r   namekeyr1   r1   r2   _row_get  s   
zSentimentConfigHandler._row_getrC   .Tuple[Optional[Dict[str, Any]], Optional[str]]c                   s
   fdd|  D } j|dddd }|dvrd} j|dd	d
d }|dv}|| |dd |dd |dd |dddtd j |ddddpUdtd j |ddddpedtd j |ddddpud j|ddd dpd d!
d fS )"Nc                   s"   i | ]\}}  | |qS r1   )r_   ra   )rZ   kr   rs   r1   r2   rz     s   " z9SentimentConfigHandler._row_to_config.<locals>.<dictcomp>zDetection Moder   r
   r   >   rN   r
   rO   zCustomer Onlyr   yes>   0noofffalsezPositive Keywordsr   zNegative Keywordsr   zNeutral Keywordsr   zPrompt Rubricr   RubricrJ   zPositive Thresholdr   r   zNegative Thresholdr   zMax Keyword Hitsr   r   Statusr   r   r   )itemsr   rR   rS   rh   )r0   rC   
normalizedrU   customer_only_rawr   r1   rs   r2   _row_to_config  sl   

*z%SentimentConfigHandler._row_to_configc                 C  sd   t | }|std| ||}|std| |d \}}|r't|| ||}d|dS )NzUploaded file is emptyz,No configuration rows found in uploaded filer   rJ   )updated	config_id)r?   rQ   rf   r   r   rK   )r0   r>   ri   rj   r   config_dataerrorr   r1   r1   r2   import_config_fileB  s   
z)SentimentConfigHandler.import_config_file)r9   r:   )r>   r?   r9   r@   )r>   r?   r9   r   )r>   r?   r9   rI   )r>   r?   rM   r   r9   rI   )rW   r?   r9   r?   )rW   r   r9   r?   rX   )rW   r   rb   rc   r9   rc   )ri   r?   rj   rk   r9   rl   )r   r   r   r?   rb   r?   r9   r?   )rC   r   r9   r   )r>   r?   ri   r?   rj   rk   r9   r   )__name__
__module____qualname__r3   r   r8   r=   rD   rH   rL   rK   staticmethodr_   ra   rh   r   r   r   r   r1   r1   r1   r2   r   '   s&    

	



O
	+
7r   )__doc__
__future__r   r   r   r   
contextlibr   typingr   r   r   r   r   r4   pymysql.cursorsr	   r   __annotations__r   r1   r1   r1   r2   <module>   s*    