
    Șj*                         d 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	m
Z
mZ  ej                  e      Z G d d      Zy)u   이미지 생성 체크포인트 매니저 — 파일 + DB 이중 추적.

각 참조/씬 이미지 생성 결과를 JSON 파일에 원자적으로 저장하여,
서버 재시작/에러 시 중단된 부분부터 재개할 수 있도록 한다.
    N)Path)AnyDictListOptionalc                      e Zd ZdZdedefdZddZddZd	ed
e	ee
f   ddfdZd	ededdfdZd	ede	ee
f   fdZd	edefdZdefdZde	eef   fdZdefdZedefd       Zedefd       ZddZde	ee
f   fdZy)ImageCheckpointManageru  이미지 생성 단계별 체크포인트 관리.

    checkpoint file structure:
    {
        "stage": "reference" | "scene",
        "completed": { item_id: { result_data } },
        "failed": { item_id: error_message },
        "updated_at": "ISO timestamp"
    }
    checkpoint_dirstagec                 r    || _         || _        || dz  | _        |i i dd| _        | j	                          y )Nz_checkpoint.json r   	completedfailed
updated_at)_dir_stage_path_data_load)selfr
   r   s      R/Users/manta/Documents/Projects/TheRoad-I1/backend/app/modules/image_checkpoint.py__init__zImageCheckpointManager.__init__   sD    "	#/?&@@
	&

 	

    returnNc                 J   | j                   j                         r	 | j                   j                  d      }t        j                  |      }t        |t              r|j                  d      | j                  k(  rp|| _	        t        j                  d| j                  t        | j                  j                  di             t        | j                  j                  di                    yyyy# t        $ r+}t        j                  d| j                   |       Y d}~yd}~ww xY w)	u   기존 체크포인트 로드.utf-8encodingr   u1   Checkpoint loaded: %s — %d completed, %d failedr   r   z/Checkpoint load failed (%s), starting fresh: %sN)r   exists	read_textjsonloads
isinstancedictgetr   r   loggerinfolen	Exceptionwarning)r   rawdataexcs       r   r   zImageCheckpointManager._load)   s    ::cjj**G*<zz#dD)dhhw.?4;;.N!%DJKKKDJJNN;;<DJJNN8R89	 /O)	   cPRVR\R\^abbcs   CC. .	D"7!DD"c                    | j                   j                  dd       ddlm}m} |j	                  |j
                        j                         | j                  d<   | j                  j                  d      }	 |j                  t        j                  | j                  dd	      d
       t        j                  t        |      t        | j                               y# t         $ r }t"        j%                  d|       Y d}~yd}~ww xY w)u)   원자적 파일 저장 (tmp → rename).T)parentsexist_okr   )datetimetimezoner   z.tmpF   )ensure_asciiindentr   r   zCheckpoint save failed: %sN)r   mkdirr2   r3   nowutc	isoformatr   r   with_suffix
write_textr"   dumpsosreplacestrr*   r'   error)r   r2   r3   tmp_pathr.   s        r   _savezImageCheckpointManager._save:   s    		t4/#+<<#=#G#G#I

< ::))&1	<

4::E!D     JJs8}c$**o6 	<LL5s;;	<s   8A%C 	D'DDitem_idresultc                     || j                   j                  di       |<   | j                   j                  di       j                  |d       | j	                          y)u*   항목 완료 기록. failed에서 제거.r   r   N)r   
setdefaultr&   poprC   )r   rD   rE   s      r   mark_completedz%ImageCheckpointManager.mark_completedI   sE    :@

k2.w7

x$(($7

r   rA   c                 b    || j                   j                  di       |<   | j                          y)u   항목 실패 기록.r   N)r   rG   rC   )r   rD   rA   s      r   mark_failedz"ImageCheckpointManager.mark_failedO   s&    7<

h+G4

r   c                     | j                   j                  di       j                  |      }t        |t              rt        |      S i S )u]  완료 기록 한 건 — 없으면 빈 dict.

        ★쓰기만 있고 **읽는 자리가 없었다** (2026-09-20). 그래서 「이미
         맞으면 안 쓴다」를 판단할 수 없어, 메타를 맞추려면 매 방문마다
         다시 써야 했다. 무변경 방문은 **기록도 남기지 않는 것**이 계약이다.
        r   )r   r&   r$   r%   )r   rD   rows      r   get_completedz$ImageCheckpointManager.get_completedT   s;     jjnn["-11':&sD1tCy9r9r   c                 >    || j                   j                  di       v S Nr   )r   r&   )r   rD   s     r   is_completedz#ImageCheckpointManager.is_completed^   s    $**..b999r   c                 h    t        | j                  j                  di       j                               S rP   setr   r&   keysr   s    r   get_completed_idsz(ImageCheckpointManager.get_completed_idsa   s%    4::>>+r2779::r   c                 L    t        | j                  j                  di             S Nr   )r%   r   r&   rV   s    r   
get_failedz!ImageCheckpointManager.get_failedd   s    DJJNN8R011r   c                 h    t        | j                  j                  di       j                               S rY   rS   rV   s    r   get_failed_idsz%ImageCheckpointManager.get_failed_idsg   s%    4::>>(B/44677r   c                 L    t        | j                  j                  di             S rP   r)   r   r&   rV   s    r   completed_countz&ImageCheckpointManager.completed_countj   s    4::>>+r233r   c                 L    t        | j                  j                  di             S rY   r^   rV   s    r   failed_countz#ImageCheckpointManager.failed_countn   s    4::>>(B/00r   c                     | j                   i i dd| _        | j                  j                         r| j                  j	                          yy)u   체크포인트 초기화.r   r   N)r   r   r   r    unlinkrV   s    r   clearzImageCheckpointManager.clearr   sD     [[	

 ::JJ r   c                 h    | j                   | j                  | j                  | j                         dS )u   현재 상태 요약.)r   r   r   failed_items)r   r_   ra   rZ   rV   s    r   summaryzImageCheckpointManager.summary}   s1     [[--'' OO-	
 	
r   )r   N)__name__
__module____qualname____doc__r   r@   r   r   rC   r   r   rI   rK   rN   boolrQ   rT   rW   rZ   r\   propertyintr_   ra   rd   rg    r   r   r	   r	      s
   	
t 
C 
c"<c 4S> d 3 s t 
:S :T#s(^ ::C :D :;3 ;2DcN 28 8 4 4 4 1c 1 1	 
c3h 
r   r	   )rk   r"   loggingr>   timepathlibr   typingr   r   r   r   	getLoggerrh   r'   r	   ro   r   r   <module>ru      s?      	   , ,			8	$s
 s
r   