o
    nֶh                     @   sr   d Z ddlZddlZddlZddlZddlmZmZ ddlmZm	Z	m
Z
 ddlZeeZG dd dZe ZdS )z6
File-based caching system for course recommendations
    N)datetime	timedelta)DictOptionalListc                   @   s   e Zd ZdZddedefddZdd	ed
ededefddZdedefddZdd	ed
edede	e
e  fddZdd	ed
ede
e dedef
ddZdefddZdefddZdefddZdS ) FileCourseCachez+File-based cache for course recommendationscourse_cache   	cache_dircache_duration_hoursc                 C   sF   || _ t|d| _tj| j s!t| j  td| j   dS dS )z
        Initialize the file-based cache system
        
        Args:
            cache_dir: Directory to store cache files
            cache_duration_hours: How long to keep cache (default 7 days)
        )hourszCreated cache directory: N)	r
   r   cache_durationospathexistsmakedirsloggerinfo)selfr
   r    r   K/var/www/eduai.edurigo.com/doc_train/edurigo_ai/TNA/testing/course_cache.py__init__   s   zFileCourseCache.__init__onlinedomainfield_promptcourse_typereturnc                 C   s&   | d| d| }t |  S )z/Generate cache key from domain and field prompt_)hashlibmd5encode	hexdigest)r   r   r   r   
cache_datar   r   r   _generate_cache_key!   s   z#FileCourseCache._generate_cache_key	cache_keyc                 C   s   t j| jd| dS )zGet full path for cache filecourses_.json)r   r   joinr
   )r   r$   r   r   r   _get_cache_filename&   s   z#FileCourseCache._get_cache_filenamec           
   
   C   s
  zi|  |||}| |}tj|sW dS ttj|}t | | j	kr8t
| td|  W dS t|ddd}t|}W d   n1 sOw   Y  td| d| d| d	 |d
g W S  ty }	 ztd|	  W Y d}	~	dS d}	~	ww )aJ  
        Get cached course recommendations
        
        Args:
            domain: The domain (e.g., "Technology")
            field_prompt: The field/skill prompt
            course_type: Type of courses ("online" or "offline")
            
        Returns:
            Cached course data or None if not found/expired
        NzCache expired and removed: rutf-8encodingzCache hit for  -  ()courseszError reading cache: )r#   r(   r   r   r   r   fromtimestampgetmtimenowr   remover   r   openjsonloadget	Exceptionerror)
r   r   r   r   r$   
cache_file	file_timefr"   er   r   r   get_cached_courses*   s(   

z"FileCourseCache.get_cached_coursesr0   c           
      C   s   zO|  |||}| |}|||t  |d}t|ddd}tj||ddd W d   n1 s4w   Y  t	d	t
| d
| d| d| d	 W dS  tyj }	 ztd|	  W Y d}	~	dS d}	~	ww )a}  
        Cache course recommendations to file
        
        Args:
            domain: The domain (e.g., "Technology")
            field_prompt: The field/skill prompt
            courses: List of course recommendations
            course_type: Type of courses ("online" or "offline")
            
        Returns:
            True if caching successful, False otherwise
        )r   r   r   	cached_atr0   wr*   r+      F)indentensure_asciiNzCached z courses for r-   r.   r/   TzError caching courses: )r#   r(   r   r3   	isoformatr5   r6   dumpr   r   lenr9   r:   )
r   r   r   r0   r   r$   r;   r"   r=   r>   r   r   r   cache_coursesP   s&   

(zFileCourseCache.cache_coursesc              
   C   s   z&t | jD ]}|dr|drt t j| j| qt	d W dS  t
yA } ztd|  W Y d}~dS d}~ww )zClear all cache filesr%   r&   zCache cleared successfullyTzError clearing cache: NF)r   listdirr
   
startswithendswithr4   r   r'   r   r   r9   r:   )r   filenamer>   r   r   r   clear_caches   s   
zFileCourseCache.clear_cachec              
   C   s.  zvdd t | jD }d}d}d}|D ]R}t j| j|}tt j|}t | | j	krb|d7 }z(t
|ddd}t|}	|t|	dg 7 }W d	   n1 sVw   Y  W q   Y q|d7 }qt||||| j	 d
 dW S  ty }
 ztd|
  dt|
iW  Y d	}
~
S d	}
~
ww )zGet cache statisticsc                 S   $   g | ]}| d r|dr|qS r%   r&   rJ   rK   .0r=   r   r   r   
<listcomp>      $ z3FileCourseCache.get_cache_stats.<locals>.<listcomp>r      r)   r*   r+   r0   Ni  )total_cache_filesvalid_cachesexpired_cachestotal_cached_coursesr   zError getting cache stats: r:   )r   rI   r
   r   r'   r   r1   r2   r3   r   r5   r6   r7   rG   r8   total_secondsr9   r   r:   str)r   cache_filesrW   rX   total_coursesr;   	full_pathr<   r=   r"   r>   r   r   r   get_cache_stats   s<   

zFileCourseCache.get_cache_statsc              
   C   s   zEdd t | jD }d}|D ]%}t j| j|}tt j|}t | | j	kr5t 
| |d7 }q|dkrCtd| d |W S  ty` } ztd|  W Y d}~dS d}~ww )	zRemove expired cache filesc                 S   rN   rO   rP   rQ   r   r   r   rS      rT   z9FileCourseCache.cleanup_expired_cache.<locals>.<listcomp>r   rU   zCleaned up z expired cache fileszError cleaning up cache: N)r   rI   r
   r   r'   r   r1   r2   r3   r   r4   r   r   r9   r:   )r   r\   removed_countr;   r^   r<   r>   r   r   r   cleanup_expired_cache   s$   
z%FileCourseCache.cleanup_expired_cacheN)r   r	   )r   )__name__
__module____qualname____doc__r[   intr   r#   r(   r   r   r   r?   boolrH   rM   r_   ra   r   r   r   r   r      s    $$&#%r   )re   r6   r   r   timer   r   typingr   r   r   logging	getLoggerrb   r   r   r   r   r   r   r   <module>   s    
 
1