Ë
    Îêj‰&  ã                  óø   — d 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ZddlZddl	m
Z
 ddlmZmZ ddlmZ ddlmZ  ej$                  e«      Z ed¬	«       G d
„ d«      «       Z G d„ d«      Z G d„ d«      Zg d¢Zy)uá  Caching vrstva pro knowledge plane (FÃ¡ze C2).

Poskytuje:
1. `EmbeddingCache` â€” content-addressable cache embedingÅ¯ klÃ­Ä�enÃ¡ SHA-256(text + model),
   persistentnÃ­ pÅ™es SQLite. ZabraÅˆuje re-computaci embedingÅ¯ pÅ™i opakovanÃ©m ingestu
   stejnÃ©ho obsahu (ByteRover 5-tier retrieval Tier 0).
2. `SearchResultCache` â€” in-memory LRU cache vÃ½sledkÅ¯ sÃ©mantickÃ©ho vyhledÃ¡vÃ¡nÃ­ klÃ­Ä�enÃ¡
   hashem dotazu + parametrÅ¯.
3. `DocumentFingerprint` â€” SHA-256 otisk dokumentu pro deduplikaci a detekci zmÄ›n.

Vzory z vÃ½zkumu:
- Content-addressable embedding cache (ragit LRU cache, Cognee embedding cache)
- SQLite-based persistent cache (LLM cache vzory z LangChain)
- Document fingerprinting pro dedup (Cognee minimalhash, MinHash dedup)

PouÅ¾itÃ­:
    cache = EmbeddingCache(db_path="/path/to/embedding_cache.sqlite")
    vector = cache.get(text_hash, model)
    if vector is None:
        vector = embedding_service.embed_text(text)
        cache.set(text_hash, model, vector)
é    )ÚannotationsN)ÚOrderedDict)Ú	dataclassÚfield)ÚPath)ÚAnyT)Úfrozenc                  ó\   — e Zd ZU dZded<   ded<   ded<   edd„«       Zedd	„«       Zdd
„Zy)ÚDocumentFingerprintu0   Otisk dokumentu pro deduplikaci a detekci zmÄ›n.ÚstrÚcontent_sha256ÚintÚ
size_bytesÚfloatÚmtimec                ó¼   — |j                  «       } | t        j                  |«      j                  «       t	        |«      |j                  «       j                  ¬«      S )N©r   r   r   )Ú
read_bytesÚhashlibÚsha256Ú	hexdigestÚlenÚstatÚst_mtime)ÚclsÚpathÚcontents      úJ/home/oem/CyberBrain26-unified/src/cyberbrain26/knowledge_plane/caching.pyÚ	from_pathzDocumentFingerprint.from_path0   sF   € à—/‘/Ó#ˆÙÜ"Ÿ>™>¨'Ó2×<Ñ<Ó>Ü˜7“|Ø—)‘)“+×&Ñ&ô
ð 	
ó    c                óÒ   — t        |t        «      r|j                  d«      } | t        j                  |«      j                  «       t        |«      t        j                  «       ¬«      S )Nzutf-8r   )Ú
isinstancer   Úencoder   r   r   r   Útime)r   r   s     r   Úfrom_contentz DocumentFingerprint.from_content9   sL   € ä�gœsÔ#Ø—n‘n WÓ-ˆGÙÜ"Ÿ>™>¨'Ó2×<Ñ<Ó>Ü˜7“|Ü—)‘)“+ô
ð 	
r    c                ó†   — | j                   › d|› �}t        j                  |j                  «       «      j	                  «       S )u>   StabilnÃ­ klÃ­Ä� pro embedding cache: sha256(content + model).ú:)r   r   r   r#   r   )ÚselfÚmodelÚraws      r   Ú	cache_keyzDocumentFingerprint.cache_keyC   s7   € à×$Ñ$Ð% Q u gÐ.ˆÜ�~‰~˜cŸj™j›lÓ+×5Ñ5Ó7Ð7r    N)r   r   Úreturnr   )r   zbytes | strr,   r   )r)   r   r,   r   )	Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__Úclassmethodr   r%   r+   © r    r   r   r   (   s@   … á:àÓØƒOØƒLàò
ó ð
ð ò
ó ð
ô8r    r   c                  óR   — e Zd ZdZddd„Zdd„Zdd„Zdd„Zdd„Zdd„Z	dd	„Z
dd
„Zy)ÚEmbeddingCacheuÙ   PersistentnÃ­ content-addressable cache embedingÅ¯ pÅ™es SQLite.

    KlÃ­Ä�: SHA-256(content_sha256 + model_name). Hodnota: serializovanÃ½ vektor
    jako JSON + metadata (model, dimenze, created_at, hit_count).
    Nc                óÆ  — t        |xs t        j                  «       dz  dz  «      | _        | j                  j                  j	                  dd¬«       t        j                  «       | _        t        j                  t        | j                  «      d¬«      | _        | j                  j                  d«       | j                  j                  d«       | j                  «        y )	Nz.cyberbrain26zembedding_cache.sqliteT)ÚparentsÚexist_okF)Úcheck_same_threadzPRAGMA journal_mode=WALzPRAGMA synchronous=NORMAL)r   ÚhomeÚdb_pathÚparentÚmkdirÚ	threadingÚRLockÚ_lockÚsqlite3Úconnectr   Ú_connÚexecuteÚ_init_schema)r(   r;   s     r   Ú__init__zEmbeddingCache.__init__P   sœ   € Ü˜GÒ_¤t§y¡y£{°_Ñ'DÐG_Ñ'_Ó`ˆŒØ�‰×Ñ×!Ñ!¨$¸Ð!Ô>Ü—_‘_Ó&ˆŒ
Ü—_‘_¤S¨¯©Ó%6È%ÔPˆŒ
Ø�
‰
×ÑÐ4Ô5Ø�
‰
×ÑÐ6Ô7Ø×ÑÕr    c                ó¤   — | j                   j                  d«       | j                   j                  d«       | j                   j                  «        y )Na~  
            CREATE TABLE IF NOT EXISTS embedding_cache (
                cache_key TEXT PRIMARY KEY,
                model TEXT NOT NULL,
                vector_dim INTEGER NOT NULL,
                vector_json TEXT NOT NULL,
                created_at REAL NOT NULL,
                hit_count INTEGER NOT NULL DEFAULT 0,
                last_hit_at REAL
            )
            zNCREATE INDEX IF NOT EXISTS idx_embedding_cache_model ON embedding_cache(model))rC   rD   Úcommit©r(   s    r   rE   zEmbeddingCache._init_schemaY   sB   € Ø�
‰
×Ñð
ô	
ð 	�
‰
×ÑØ\ô	
ð 	�
‰
×ÑÕr    c                óV  — t        j                  |› d|› �j                  «       «      j                  «       }| j                  5  | j
                  j                  d|f«      j                  «       }|€
	 ddd«       y|\  }}}}	||k7  r
	 ddd«       yt        j                  |«      }
t        j                  «       }| j
                  j                  d|dz   ||f«       | j
                  j                  «        t        j                  d|dd ||dz   «       |
cddd«       S # 1 sw Y   yxY w)u3   VrÃ¡tÃ­ embeding z cache nebo None pÅ™i cache miss.r'   z_SELECT vector_json, vector_dim, hit_count, last_hit_at FROM embedding_cache WHERE cache_key = ?NzMUPDATE embedding_cache SET hit_count = ?, last_hit_at = ? WHERE cache_key = ?é   z,Embedding cache hit: key=%s model=%s hits=%dé   )r   r   r#   r   r@   rC   rD   ÚfetchoneÚjsonÚloadsr$   rH   ÚloggerÚdebug)r(   Úcontent_hashr)   Ú
vector_dimr+   ÚrowÚvector_jsonÚ
stored_dimÚ	hit_countÚlast_hit_atÚvectorÚnows               r   ÚgetzEmbeddingCache.getl   s!  € ä—N‘N l ^°1°U°GÐ#<×#CÑ#CÓ#EÓF×PÑPÓRˆ	Ø�Z‰Zñ 	Ø—*‘*×$Ñ$ØqØ�ó÷ ‰h‹jð ð ˆ{Ø÷	ð 	ð ?BÑ;ˆK˜ Y°Ø˜ZÒ'à÷	ð 	ô —Z‘Z Ó,ˆFÜ—)‘)“+ˆCØ�J‰J×ÑØ_Ø˜Q‘  YÐ/ôð �J‰J×ÑÔÜ�L‰LÐGÈÐSVÐTVÈÐY^Ð`iÐlmÑ`mÔnØ÷'	÷ 	ò 	ús   Á/DÁ;DÂBDÄD(c           	     óÔ  — t        j                  |› d|› �j                  «       «      j                  «       }t	        j
                  |«      }t        j                  «       }| j                  5  | j                  j                  d||t        |«      ||f«       | j                  j                  «        ddd«       t        j                  d|dd |t        |«      «       y# 1 sw Y   Œ.xY w)u   UloÅ¾Ã­ embeding do cache.r'   zØ
                INSERT OR REPLACE INTO embedding_cache
                (cache_key, model, vector_dim, vector_json, created_at, hit_count, last_hit_at)
                VALUES (?, ?, ?, ?, ?, 0, NULL)
                Nz+Embedding cache set: key=%s model=%s dim=%drL   )r   r   r#   r   rN   Údumpsr$   r@   rC   rD   r   rH   rP   rQ   )r(   rR   r)   rY   r+   rU   rZ   s          r   ÚsetzEmbeddingCache.set„   sÂ   € ä—N‘N l ^°1°U°GÐ#<×#CÑ#CÓ#EÓF×PÑPÓRˆ	Ü—j‘j Ó(ˆÜ�i‰i‹kˆØ�Z‰Zñ 		 Ø�J‰J×Ñðð
 ˜E¤3 v£;°¸SÐAôð �J‰J×ÑÔ÷		 ô 	�‰ÐBÀIÈcÈrÀNÐTYÔ[^Ð_eÓ[fÕg÷		 ð 		 ús   Á,ACÃC'c                ó8  — t        j                  |› d|› �j                  «       «      j                  «       }| j                  5  | j
                  j                  d|f«      }| j
                  j                  «        |j                  cddd«       S # 1 sw Y   yxY w)uV   Invaliduje cache poloÅ¾ku pro danÃ½ obsah a model. VrÃ¡tÃ­ poÄ�et smazanÃ½ch Å™Ã¡dkÅ¯.r'   z/DELETE FROM embedding_cache WHERE cache_key = ?N)	r   r   r#   r   r@   rC   rD   rH   Úrowcount)r(   rR   r)   r+   Úcursors        r   Ú
invalidatezEmbeddingCache.invalidate•   s}   € ä—N‘N l ^°1°U°GÐ#<×#CÑ#CÓ#EÓF×PÑPÓRˆ	Ø�Z‰Zñ 	#Ø—Z‘Z×'Ñ'ØAÀIÀ<óˆFð �J‰J×ÑÔØ—?‘?÷	#÷ 	#ò 	#ús   ÁABÂBc                óÈ   — | j                   5  | j                  j                  d«      }| j                  j                  «        |j                  cddd«       S # 1 sw Y   yxY w)u8   VymaÅ¾e celou cache. VrÃ¡tÃ­ poÄ�et smazanÃ½ch Å™Ã¡dkÅ¯.zDELETE FROM embedding_cacheN)r@   rC   rD   rH   r`   )r(   ra   s     r   ÚclearzEmbeddingCache.clearŸ   sJ   € à�Z‰Zñ 	#Ø—Z‘Z×'Ñ'Ð(EÓFˆFØ�J‰J×ÑÔØ—?‘?÷	#÷ 	#ò 	#ús   �AAÁA!c                óª  — | j                   5  | j                  j                  d«      j                  «       d   }| j                  j                  d«      j                  «       d   }| j                  j                  «       r$| j                  j                  «       j                  nd}|||t        | j                  «      dœcddd«       S # 1 sw Y   yxY w)u   VrÃ¡tÃ­ statistiky cache.z$SELECT COUNT(*) FROM embedding_cacher   z7SELECT COALESCE(SUM(hit_count), 0) FROM embedding_cache)Útotal_entriesÚ
total_hitsÚdb_size_bytesr;   N)	r@   rC   rD   rM   r;   Úexistsr   Úst_sizer   )r(   Ú
total_rowsrg   Údb_sizes       r   ÚstatszEmbeddingCache.stats¦   s°   € à�Z‰Zñ 	ØŸ™×+Ñ+Ø6óç‰h‹j˜ñˆJð Ÿ™×+Ñ+ØIóç‰h‹j˜ñˆJð 6:·\±\×5HÑ5HÔ5J�d—l‘l×'Ñ'Ó)×1Ò1ÐPQˆGà!+Ø(Ø!(Ü˜tŸ|™|Ó,ñ	÷	÷ 	ò 	ús   �B2C	Ã	Cc                óz   — | j                   5  | j                  j                  «        d d d «       y # 1 sw Y   y xY w©N)r@   rC   ÚcloserI   s    r   rp   zEmbeddingCache.close·   s.   € Ø�Z‰Zñ 	Ø�J‰J×ÑÔ÷	÷ 	ñ 	ús   �1±:ro   )r;   zstr | Path | Noner,   ÚNone)r,   rq   )rR   r   r)   r   rS   r   r,   zlist[float] | None)rR   r   r)   r   rY   zlist[float]r,   rq   )rR   r   r)   r   r,   r   ©r,   r   ©r,   zdict[str, Any])r-   r.   r/   r0   rF   rE   r[   r^   rb   rd   rm   rp   r3   r    r   r5   r5   I   s0   „ ñôóó&ó0hó"#ó#óô"r    r5   c                  óˆ   — e Zd ZdZd	d
d„Z	 	 	 	 	 	 	 	 	 	 dd„Z	 d	 	 	 	 	 	 	 	 	 dd„Z	 	 d	 	 	 	 	 	 	 	 	 	 	 dd„Zdd„Zdd„Z	y)ÚSearchResultCacheuÏ   In-memory LRU cache pro vÃ½sledky sÃ©mantickÃ©ho vyhledÃ¡vÃ¡nÃ­.

    KlÃ­Ä�: SHA-256(dotazu + limit + topic + tag). Hodnota: seznam vÃ½sledkÅ¯ + timestamp.
    LRU eviction pÅ™i pÅ™ekroÄ�enÃ­ max_size.
    c                óŒ   — || _         || _        t        «       | _        t	        j
                  «       | _        d| _        d| _        y )Nr   )	Úmax_sizeÚttl_secondsr   Ú_cacher>   r?   r@   Ú_hitsÚ_misses)r(   rw   rx   s      r   rF   zSearchResultCache.__init__Ã   s6   € Ø ˆŒØ&ˆÔÜLWËMˆŒÜ—_‘_Ó&ˆŒ
ØˆŒ
Øˆ�r    c                óŽ   — |› d|› d|xs d› d|xs d› �}t        j                  |j                  «       «      j                  «       S )Nr'   Ú )r   r   r#   r   )r(   ÚqueryÚlimitÚtopicÚtagr*   s         r   Ú	_make_keyzSearchResultCache._make_keyË   sF   € ð ��q˜˜˜q ¢¨" ¨Q¨sªy°b¨kÐ:ˆÜ�~‰~˜cŸj™j›lÓ+×5Ñ5Ó7Ð7r    Nc                óð  — | j                  ||||«      }| j                  5  || j                  vr| xj                  dz  c_        	 d d d «       y | j                  |   \  }}t	        j                  «       |z
  | j
                  kD  r,| j                  |= | xj                  dz  c_        	 d d d «       y | j                  j                  |«       | xj                  dz  c_        |cd d d «       S # 1 sw Y   y xY w)NrK   )r‚   r@   ry   r{   r$   rx   Úmove_to_endrz   )r(   r~   r   r€   r�   ÚkeyÚresultsÚ	cached_ats           r   r[   zSearchResultCache.getÑ   sÔ   € ð �n‰n˜U E¨5°#Ó6ˆØ�Z‰Zñ 	Ø˜$Ÿ+™+Ñ%Ø—’ Ñ!•Ø÷	ð 	ð "&§¡¨SÑ!1ÑˆG�YÜ�y‰y‹{˜YÑ&¨×)9Ñ)9Ò9Ø—K‘K Ð$Ø—’ Ñ!•Ø÷	ð 	ð �K‰K×#Ñ# CÔ(Ø�JŠJ˜!‰O�JØ÷	÷ 	ò 	ús   ¡%C,ÁAC,Â11C,Ã,C5c                óÈ  — | j                  ||||«      }| j                  5  || j                  v r| j                  j                  |«       |t	        j                  «       f| j                  |<   t        | j                  «      | j                  kD  r?| j                  j                  d¬«       t        | j                  «      | j                  kD  rŒ?d d d «       y # 1 sw Y   y xY w)NF)Úlast)r‚   r@   ry   r„   r$   r   rw   Úpopitem)r(   r~   r   r†   r€   r�   r…   s          r   r^   zSearchResultCache.setã   s¬   € ð �n‰n˜U E¨5°#Ó6ˆØ�Z‰Zñ 	0Ø�d—k‘kÑ!Ø—‘×'Ñ'¨Ô,Ø '¬¯©«Ð5ˆD�K‰K˜ÑÜ�d—k‘kÓ" T§]¡]Ò2Ø—‘×#Ñ#¨Ð#Ô/ô �d—k‘kÓ" T§]¡]Ó2÷		0÷ 	0ñ 	0ús   ¡B-CÃC!c                ó¨   — | j                   5  t        | j                  «      }| j                  j                  «        |cddd«       S # 1 sw Y   yxY w)u8   VymaÅ¾e celou cache. VrÃ¡tÃ­ poÄ�et smazanÃ½ch poloÅ¾ek.N)r@   r   ry   rd   )r(   Úcounts     r   rb   zSearchResultCache.invalidateó   s?   € à�Z‰Zñ 	Ü˜Ÿ™Ó$ˆEØ�K‰K×ÑÔØ÷	÷ 	ò 	ús   �1AÁAc                ó,  — | j                   5  | j                  | j                  z   }|dkD  r| j                  |z  nd}| j                  | j                  |t        | j                  «      | j
                  | j                  dœcd d d «       S # 1 sw Y   y xY w)Nr   g        )ÚhitsÚmissesÚhit_rateÚsizerw   rx   )r@   rz   r{   r   ry   rw   rx   )r(   Útotalr�   s      r   rm   zSearchResultCache.statsú   sx   € Ø�Z‰Zñ 
	Ø—J‘J §¡Ñ-ˆEØ-2°QªY�t—z‘z EÒ)¸CˆHàŸ
™
ØŸ,™,Ø$Ü˜DŸK™KÓ(Ø ŸM™MØ#×/Ñ/ñ÷
	÷ 
	ò 
	ús   �A3B
Â
B)iè  g     Àr@)rw   r   rx   r   r,   rq   )
r~   r   r   r   r€   ú
str | Noner�   r“   r,   r   )NN)
r~   r   r   r   r€   r“   r�   r“   r,   zlist[dict[str, Any]] | None)r~   r   r   r   r†   zlist[dict[str, Any]]r€   r“   r�   r“   r,   rq   rr   rs   )
r-   r.   r/   r0   rF   r‚   r[   r^   rb   rm   r3   r    r   ru   ru   ¼   s¾   „ ñôð8Øð8Ø!$ð8Ø-7ð8Ø>Hð8à	ó8ð SWðØðØ!$ðØ-7ðØEOðà	$óð. !Øð0àð0ð ð0ð &ð	0ð
 ð0ð ð0ð 
ó0ó ôr    ru   )r   r5   ru   )r0   Ú
__future__r   r   rN   ÚloggingrA   r>   r$   Úcollectionsr   Údataclassesr   r   Úpathlibr   Útypingr   Ú	getLoggerr-   rP   r   r5   ru   Ú__all__r3   r    r   ú<module>rœ      s   ðñõ. #ã Û Û Û Û Û Ý #ß (Ý Ý à	ˆ×	Ñ	˜8Ó	$€ñ �$Ô÷8ð 8ó ð8÷@pñ p÷fIñ IòX�r    