+
    UTj                         R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RI	H
t
 ^ RIHt ]P                  ! ]4      tRtRtR R	 ltR
R/R R lltR# )uA  Anthropic kullanım istatistiklerini structured JSON-lines log'a yazan modül.

Mimari:
    Her `messages.create` / `messages.stream` çağrısından sonra `record_usage`
    çağrılır. JSONL formatında /var/log/patentyazar-llm-usage.log (production)
    veya /tmp/llm-usage.log (development) dosyasına atomic append yapar.

Laravel tarafında `php artisan llm:ingest-usage` cron komutu bu dosyayı okur,
`llm_usage_records` tablosuna ekler ve dosyayı truncate eder.

Bu yüzden file-based loglama tercih ettik (Redis pub-sub veya başka bir kanal
yerine):
  - Python ve Laravel ayrı süreçlerde, file ortak alan
  - Apache + systemd standart, bir yere bağımlılık eklemek istemiyoruz
  - Append atomic (POSIX < PIPE_BUF, log satırları küçük)
  - Cron-based ingest 5 dakikada bir → admin paneli için zaten yeterli
)annotationsN)Path)Any)get_settingsz"/var/log/patentyazar-llm-usage.logz/tmp/llm-usage.logc                   V ^8  d   QhRR/# )   returnstr )formats   "\/Users/zincirx/Documents/projelerim/patentyazar/backend-python/app/services/llm/usage_log.py__annotate__r   &   s      3     c                    \        4       p \        V RR4      pV'       d   V# \        \        4      pVP	                  4       '       d9   \
        P                  ! V\
        P                  4      '       d   \        #  \        # \
        P                  ! VP                  \
        P                  4      '       d   \        # \        # )zIConfigured log path; production'da /var/log/ user yazabiliyor mu kontrol.llm_usage_log_pathN)
r   getattrr   _DEFAULT_LOG_PATHexistsosaccessW_OKparent_DEV_LOG_PATH)settings	candidatelog_files      r   	_log_pathr   &   s    ~H"6=I %&H99Xrww''$$ (  
8??BGG	,	,  r   extrac          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
r   modelr	   usager   endpointr   zdict[str, Any] | Noner   Noner
   )r   s   "r   r   r   ?   s<     :? :?:? :? 	:?
 !:? 
:?r   c                  a  Sf   R# R V3R llpR\        \        P                  ! 4       R,          4      RV RVRV! R4      R	V! R	4      R
V! R
4      RV! R4      /pV'       d   W5R&   \        P                  ! VRRR7      R,           p\	        \        4       RRR7      ;_uu_ 4       pVP                  V4       RRR4       R#   + '       g   i     R# ; i  \         d    \        P                  R4        R# i ; i)u  Anthropic response'undaki `usage` objesini log'a yazar.

`usage` Anthropic SDK'nın `Usage` modeli olabilir veya stream end_event'inden
gelmiş bir dict olabilir. İki tipten de aşağıdaki alanları çeker:

  input_tokens                     — non-cached input
  output_tokens                    — completion
  cache_creation_input_tokens      — yeni cache write (5min veya 1h)
  cache_read_input_tokens          — cache hit (en ucuz)

Bu alanların hepsi int. Eksik olan 0 sayılır.

`endpoint` log'lama için string identifier — örn. "drafting.stream",
"intake.suggest", "prior_art.analyze". Admin paneli endpoint bazında
grupluyor.

Hatalar yutulur — logging code uygulama akışını hiçbir zaman bozmamalı.
Nc                    V ^8  d   QhRRRR/# )r   keyr	   r   intr
   )r   s   "r   r   "record_usage.<locals>.__annotate__\   s     	 	c 	c 	r   c                   < \        SV 4      '       d    \        \        SV 4      ;'       g    ^ 4      # \        S\        4      '       d&   \        SP                  V ^ 4      ;'       g    ^ 4      # ^ # )    )hasattrr&   r   
isinstancedictget)r%   r    s   &r   _getrecord_usage.<locals>._get\   sX    uc""75#.33!44%&&599S!,1122r   tsi  r   r!   input_tokensoutput_tokenscache_creation_input_tokenscache_read_input_tokensr   F)ensure_ascii
separators
azutf-8)encodingz!LLM usage log failed (suppressed)),:)
r&   timejsondumpsopenr   write	Exception_logger	exception)r   r    r!   r   r.   recordlinefs   $d$$    r   record_usagerG   ?   s    2!?=	 	 #diikD()UD0T/2)40M+N%t,E'F"
 #7Ozz&uLtS )+sW55GGDM 6555  ? 	=>?s5   C BC 'C9C C	C C  C;:C;)__doc__
__future__r   r=   loggingr   r<   pathlibr   typingr   
app.configr   	getLogger__name__rB   r   r   r   rG   r
   r   r   <module>rP      sZ   $ #   	    #


H
% 9 $2:?
 $(:? :?r   