
    i&                         d 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mZ ddlm	Z	 ddl
mZmZmZ ddlmZ ddlmZmZ ddlmZ  ej,                  e      Zd	Zefd
ededefdZ G d d      Z G d d      Zy)uQ   파이프라인 작업의 프로비저닝을 기록하는 헬퍼 — Opik 호환.    N)datetimetimezone)Path)AnyDictOptional)Session)MODULE_VERSIONSget_module_info)OperationLog  datamax_lenreturnc                 p    t        j                  | dt              }t        |      |kD  r|d|dz
   dz   S |S )z0Serialize dict to JSON, truncating if necessary.F)ensure_asciidefaultN   z...)jsondumpsstrlen)r   r   raws      L/Users/manta/Documents/Projects/TheRoad-I1/backend/app/modules/provenance.py_truncate_jsonr      s;    
**Ts
;C
3x'=Wq[!E))J    c                      e Zd ZdZ	 	 	 	 	 ddddedededee   d	ee   d
ee   dee   ddfdZedefd       Zde	ddfdZ
de	ddfdZ	 	 	 d dedededdfdZde	ddfdZd!deddfdZdeddfdZd"dZd#dZdefdZy)$OperationContextz3Context manager for recording operation provenance.NrecorderProvenanceRecorderoperation_typemodule_name
project_id
episode_idprompt_nameprompt_versionprompt_hashr   c	                 t   || _         t        t        j                               | _        || _        || _        t        j                  |d      | _	        || _
        || _        || _        || _        || _        d | _        d | _        d| _        d| _        t'        j&                         | _        d | _        d | _        y )Nz0.0.0z{})	_recorderr   uuiduuid4_op_id_operation_type_module_namer
   get_module_version_project_id_episode_id_prompt_name_prompt_version_prompt_hash_input_summary_output_summary_token_usage	_metadatatime_start_time_status_error_message)	selfr   r!   r"   r#   r$   r%   r&   r'   s	            r   __init__zOperationContext.__init__!   s     "$**,'-'.22;H%%'-'-1.2!%"99;&*-1r   c                     | j                   S N)r,   r>   s    r   operation_idzOperationContext.operation_id>   s    {{r   summaryc                 $    t        |      | _        y)z/Record input summary (truncated to max length).N)r   r6   r>   rD   s     r   	set_inputzOperationContext.set_inputB   s    ,W5r   c                 $    t        |      | _        y)z0Record output summary (truncated to max length).N)r   r7   rF   s     r   
set_outputzOperationContext.set_outputF   s    -g6r   input_tokensoutput_tokenscost_usdc                 @    t        j                  |||d      | _        y)zRecord token usage information.)rJ   rK   rL   N)r   r   r8   )r>   rJ   rK   rL   s       r   set_token_usagez OperationContext.set_token_usageJ   s#     !JJ ,!.$
r   metadatac                 $    t        |      | _        y)zRecord extra metadata.N)r   r9   )r>   rO   s     r   set_metadatazOperationContext.set_metadataY   s    '1r   statusc                 2    || _         | j                          y)z-Mark operation as finished with given status.N)r<   _save)r>   rR   s     r   finishzOperationContext.finish]   s    

r   error_messagec                 X    d| _         t        |      dd | _        | j                          y)zMark operation as failed.errorNr   )r<   r   r=   rT   )r>   rV   s     r   failzOperationContext.failb   s&    !-0$7

r   c                 l   t        t        j                         | j                  z
  dz        }t        j                  t
        j                        j                         }t        di d| j                  d| j                  d| j                  d| j                  d| j                  d| j                  d| j                  d	| j                   d
| j"                  d| j$                  d| j&                  d| j(                  xs dd| j*                  d|d| j,                  d| j.                  d|}| j0                  j2                  j5                  |       | j0                  j2                  j7                          t8        j;                  d| j                  | j                  | j(                  |       y)z Persist the operation log entry.i  idr#   r!   r$   r"   module_versionr%   r&   r'   input_summaryoutput_summaryrR   rX   rV   duration_mstoken_usagemetadata_json
created_atz>Operation logged: type=%s, module=%s, status=%s, duration=%dmsN )intr:   r;   r   nowr   utc	isoformatr   r,   r1   r-   r2   r.   r0   r3   r4   r5   r6   r7   r<   r=   r8   r9   r)   _dbaddflushloggerinfo)r>   
elapsed_msre   	log_entrys       r   rT   zOperationContext._saveh   s   $))+(8(88D@A
ll8<<(224  
{{
''
  //
 ''	

 ))
  //
 ))
  //
 ))
 --
  //
 <<*7
 --
 #
 ))
  ..!
" #
	& 	y)  "L  LL	
r   c                     | S rA   rc   rB   s    r   	__enter__zOperationContext.__enter__   s    r   c                 x    | j                   y|| j                  t        |             y| j                          y)NF)r<   rY   r   rU   )r>   exc_typeexc_valexc_tbs       r   __exit__zOperationContext.__exit__   s4    <<#IIc'l#r   ) NNNN)r   r           )success)r   N)r   r   )__name__
__module____qualname____doc__r   r   r?   propertyrC   dictrG   rI   rd   floatrN   rQ   rU   rY   rT   rp   boolru   rc   r   r   r   r      sJ   = $(%)(,%)2&2 2 	2
 2 SM2 c]2 !2 c]2 
2: c  6 6$ 67$ 74 7 	

 
 	

 

2T 2d 2S  
# $ !
FT r   r   c                       e Zd ZdZddededdfdZ	 	 ddeded	ee   d
ee   def
dZ	e
d
edee   fd       Z	 	 	 	 ddee   d	ee   dededef
dZdedee   fdZdefdZy)r    uA   파이프라인 작업의 프로비저닝을 기록하는 헬퍼.
db_sessionr#   r   Nc                      || _         || _        y rA   )rh   r1   )r>   r   r#   s      r   r?   zProvenanceRecorder.__init__   s    %r   r!   r"   r$   prompt_pathc           
         d}d}d}|r| j                  |      }t        |      }|j                         rZ|j                  }	t	        |	      D ]@  \  }
}|j                  d      s|dd j                         s,|}|
dkD  r|	|
dz
      d| } n |s9t        |      }|j                  d      r|d   }d|v r|j                  d      d   }t        | ||| j                  ||||      S )	uo  작업 시작. context manager로 사용.

        Args:
            operation_type: e.g., entity_extraction, scene_still_extraction
            module_name: key from MODULE_VERSIONS
            episode_id: optional episode ID
            prompt_path: optional path to a prompt file for hashing

        Returns:
            OperationContext context manager.
        Nv   r   /prompt_dependency)r   r!   r"   r#   r$   r%   r&   r'   )compute_prompt_hashr   existsparts	enumerate
startswithisdigitr   r/   splitr   r1   )r>   r!   r"   r$   r   r%   r&   r'   pr   ipartrl   s                r   start_operationz"ProvenanceRecorder.start_operation   s
   $ 22;?K [!Axxz(/GAts+QR0@0@0B)-q5-21Q3ZL$*@K  0 ";/Dxx+,"#67+%%0%6%6s%;B%?N)#''!#)#	
 		
r   c                     t        |       }|j                         sy|j                  d      }t        j                  |j                  d            j                         S )u,   프롬프트 파일의 SHA256 해시 계산.Nzutf-8)encoding)r   r   	read_texthashlibsha256encode	hexdigest)r   r   contents      r   r   z&ProvenanceRecorder.compute_prompt_hash   sK     xxz++w+/~~gnnW56@@BBr   offsetlimitc                    | j                   j                  t              }| j                  r,|j	                  t        j
                  | j                  k(        }|r"|j	                  t        j                  |k(        }|r"|j	                  t        j                  |k(        }|j                  t        j                  j                               }|j                  |      j                  |      j                         S )z)Get operation logs with optional filters.)rh   queryr   r1   filterr#   r!   r$   order_byrb   descr   r   all)r>   r!   r$   r   r   r   s         r   get_operationsz!ProvenanceRecorder.get_operations   s     |,LL!8!8D<L<L!LMELL!<!<!NOELL!8!8J!FGE|66;;=>||F#))%04466r   op_idc                     | j                   j                  t              j                  t        j                  |k(        j                         S )zGet a single operation by ID.)rh   r   r   r   r[   first)r>   r   s     r   get_operationz ProvenanceRecorder.get_operation   s3     HHNN<(VLOOu,-UW	
r   c                    | j                   j                  t              }| j                  r,|j	                  t        j
                  | j                  k(        }|j                         }i }|D ]  }|j                  }||vr|ddddd||<   ||   dxx   dz  cc<   |j                  dk(  r||   dxx   dz  cc<   n|j                  dk(  r||   dxx   dz  cc<   |j                  sz||   dxx   |j                  z  cc<    g }|j                         D ]A  }|d   r|d   |d   z  nd}|j                  |d	   |d   |d   |d   t        |d      d
       C |S )z(Get aggregated stats per operation type.r   )r!   totalrx   rX   total_duration_msr   r   rx   rX   r   rw   r!   )r!   r   rx   rX   avg_duration_ms)rh   r   r   r1   r   r#   r   r!   rR   r_   valuesappendround)	r>   r   all_opsstatsopkeyresultsavgs	            r   get_summaryzProvenanceRecorder.get_summary   sk   |,LL!8!8D<L<L!LME))++-B##C%&) )*c
 #Jw1$yyI%c
9%*%g%c
7#q(#~~c
./2>>A/! $ A9:7!'(1W:5CMM"#$4"57Y<7#(a=    r   )rv   )NN)NNr   2   )ry   rz   r{   r|   
OrmSessionr   r?   r   r   r   staticmethodr   rd   listr   r   r   r   rc   r   r   r    r       s    K&: &3 & & %)%)7
7
 7
 SM	7

 c]7
 
7
r C C# C C )-$(7 7 SM7 	7
 7 
7$
3 
8L+A 
#T #r   r    ) r|   r   r   loggingr:   r*   r   r   pathlibr   typingr   r   r   sqlalchemy.ormr	   r   app.core.version_registryr
   r   app.models.projectr   	getLoggerry   rk   _MAX_SUMMARY_LENr~   rd   r   r   r   r    rc   r   r   <module>r      s|    W      '  & & 0 F +			8	$  /?   3 x xvF Fr   