
    Fin                    J   U d Z ddlm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 ddlZddlmZ 	 ddlZddlmZ d	Z e
d      ZdZded<   dZded<   dZded<   dZded<   dZded<   dZded<   dZded<   ddidddd d!dd"d#d$id%d&id'Zd(ed)<   d*d+giZ d,ed-<   dEd.Z!e G d/ d0             Z"dFd1Z#dGd2Z$dHd3Z%dId4Z&dJd5Z'dKd6Z(dLd7Z)dMd8Z*dNd9Z+dOd:Z,dPd;Z-dQd<Z.	 	 	 	 	 	 dRd=Z/	 	 	 	 	 	 dSd>Z0dTd?Z1dTd@Z2dUdAZ3dVdBZ4dLdCZ5	 	 	 	 	 	 	 	 	 	 dWdDZ6y# e$ r d
ZY w xY w)Xu1  quality_evaluator.py — IDS Phase 1 이미지 품질 평가 모듈.

목적:
  task-2389(한글 깨짐), task-2401(silent corruption: 5장 단조 그라데이션+박스+텍스트 1종 패턴)
  재발 영구 차단. 시각 다양성·브랜드 색상·hybrid 패턴·폰트 크기·OCR 신뢰도를
  코드 수치로 검증하여 인간 평가 없이 PASS/FAIL 판정.

회장 3원칙:
  - 더 가볍게: 외부 API 호출 0, 로컬 분석만
  - 더 정확하게: 코드 수치 기반 판정
  - 더 퀄리티 높게: retry-until-pass 연동 (retry_loop.py)
    )annotationsN)	dataclassfield)Path)Any)Image)OutputTFz./home/jay/workspace/memory/specs/dq-rules.jsong      9@floatVISUAL_STD_THRESHOLDi  intVISUAL_UNIQUE_COLOR_THRESHOLDSPATIAL_COHERENCE_DIFF_MAXg      >@BRAND_DELTA_E_THRESHOLD皙?BRAND_AREA_RATIO_MINg     Q@OCR_CONFIDENCE_THRESHOLDg      ?OCR_KOREAN_RATIO_MINedge_density_min皙?g     @皙?)unique_colors_minsaturation_minQ?{Gz?)r   edge_density_maxsaturation_std_minsmoothness_max      @noise_ratio_min333333?h1_photo_cardh2_illustration_cardh3_gpt_style_cardh4_gradient_cardh5_user_photo_cardzdict[str, dict[str, float]]PATTERN_THRESHOLDS
font_sizesabsolute_minzdict[str, list[str]]_DQ_RULES_REQUIRED_KEYSc           	         t         j                         D ]8  \  }}|| vrt        d| d      |D ]  }|| |   vst        d| d| d       : y)u   dq-rules.json이 evaluator가 기대하는 최소 스키마를 만족하는지 검증한다.

    누락 시 즉시 RuntimeError 발생 (silent pass 영구 차단).
    z7dq-rules.json schema violation: missing top-level key ''z-dq-rules.json schema violation: missing key '.N)r*   itemsRuntimeError)rulestop_keyrequired_subkeyssubs       G/home/jay/workspace/skills/satori-cardnews/scripts/quality_evaluator.py_validate_dq_rules_schemar5   B   s    
 &=%B%B%D 	!!%I'RST  $ 	C%.("CG9AcURST 		    c                  z    e Zd ZU dZded<   ded<    ee      Zded<    ee      Z	d	ed
<    ee      Z
d	ed<   y)
EvalResultu   evaluate_image 반환 결과.boolpassedr   score)default_factoryz	list[str]fail_reasonsdict[str, Any]retry_hintsdetailsN)__name__
__module____qualname____doc____annotations__r   listr=   dictr?   r@    r6   r4   r8   r8   W   s<    'LJ#D9L)9"'"=K=#D9G^9r6   r8   c                6    | dz  }|dk  r|dz  S |dz   dz  dz  S )uB   sRGB 감마 보정 채널(0~255)을 선형 값으로 변환한다.     o@g?ܵ?gףp=
)@g)\(?gzG?g333333@rH   )ccvs     r4   _srgb_to_linearrM   g   s0    	
UB	W}Ez%Z5 S((r6   c                r    | dz  |dz  z   |dz  z   }| dz  |dz  z   |dz  z   }| dz  |dz  z   |d	z  z   }|||fS )
u-   선형 sRGB를 CIE XYZ (D65)로 변환한다.gAAe?g2݆?gjt?gk8?g2݆?gz?gD̓?g]?g&$h?rH   )rgbxyzs         r4   _linear_to_xyzrU   o   s^    	II%I5A	II%I5A	II%I5Aa7Nr6   c                    d\  }}}dd} || |z        } |||z        } |||z        }	d|z  dz
  }
d||z
  z  }d||	z
  z  }|
||fS )u=   CIE XYZ를 CIE Lab으로 변환한다 (D65 기준 백색점).)g'@j?      ?gyuk?c                &    | dkD  r| dz  S d| z  dz   S )Ng2#?gUUUUUU?gS%@g{a?rH   )ts    r4   fz_xyz_to_lab.<locals>.f{   s#    x<##qy<''r6   g      ]@g      0@g     @@g      i@)rY   r
   returnr
   rH   )rR   rS   rT   xnynznrZ   fxfyfzLab_vals                r4   _xyz_to_labre   w   sq    *JBB(
 
1r6B	
1r6B	
1r6B
TAbAR"WEa;r6   c                    | j                  d      }t        |dd d      }t        |dd d      }t        |dd d      }t        |      }t        |      }t        |      }t        |||      \  }}	}
t	        ||	|
      S )u3   HEX 색상 문자열을 CIE Lab으로 변환한다.#r               )lstripr   rM   rU   re   )	hex_colorhxrO   rP   rQ   lrlglbrR   rS   rT   s              r4   _hex_to_labrr      s    			#	BBqGRABqGRABqGRA		B		B		BRR(GAq!q!Qr6   c                    t        |       }t        |      }t        |      }t        |||      \  }}}t        |||      S )u,   RGB 정수값을 CIE Lab으로 변환한다.)rM   rU   re   )	rO   rP   rQ   ro   rp   rq   rR   rS   rT   s	            r4   _rgb_to_labrt      sC    		B		B		BRR(GAq!q!Qr6   c                    t        j                  | d   |d   z
  dz  | d   |d   z
  dz  z   | d   |d   z
  dz  z         S )u:   두 Lab 색상 사이의 CIE76 ΔE 거리를 계산한다.r   rh      )mathsqrt)lab1lab2s     r4   _delta_er{      s\    99	a47	q 7T!W
"	#7T!W
"	# r6   c                   t        j                  | j                  d      t         j                        }t	        t        j
                  |dddddf               }t	        t        j
                  |dddddf               }t	        t        j
                  |dddddf               }||z   |z   dz  }|j                  \  }}}t        d||z  dz        }	|dd|	dd|	ddf   j                  d	d
      j                  t         j                        }
t        t        t        t        t        |
j!                                                 }t	        t        j"                  t        j$                  |d            j'                               }t	        t        j"                  t        j$                  |d            j'                               }||z   dz  }g }|t(        k  r|j+                  d|ddt(                |t,        k  r|j+                  d| dt,                |t.        kD  r|j+                  d|ddt.                t        |      dk(  }|rdnit        dt        dt1        |t(        z  d      z  dz  dt1        |t,        z  d      z  dz  z   dt1        t.        t        |d      z  d      z  dz  z               }||t3        |d      |t3        |d      |rdj5                  |      ndddt7        j8                  dd      ddS )uD  RGB 히스토그램 + 공간 일관성으로 단조/노이즈 corruption 1종 패턴을 검출한다.

    검출 대상:
      - 단조 그라데이션/박스 (std/unique colors 부족)
      - TV-static 같은 unstructured noise (spatial coherence 부재)
        — 로키 G2 적대적 평가 CRITICAL #C-NEW 해소
    RGBdtypeNr   rv   rh   g      @iP     axis       @u.   단조 그라데이션 의심: RGB std 평균 .2f < u'   색상 다양성 부족: unique colors uH   공간 일관성 부족 (TV-static 의심): 인접 픽셀 차이 평균 z >    rW   r   g333333?rj   ; T        )force_pattern_diversityforce_spatial_coherencesuggested_seed)r:   r;   std_meanunique_colorsspatial_diffreason
retry_hint)nparrayconvertfloat32r
   stdshapemaxreshapeastypeuint8r   lensetmaptupletolistabsdiffmeanr   appendr   r   minroundjoinrandomrandint)imgarrstd_rstd_gstd_br   hw_stepflatr   diff_hdiff_vr   reasonsr:   r;   s                     r4   check_visual_diversityr      s    ((3;;u%RZZ
8C "&&Q1W&'E"&&Q1W&'E"&&Q1W&'E%,H iiGAq!q1q5U"#Dvvvvq !))"a077ADCE4;;= 9:;<M 266"''#A./4467F266"''#A./4467FVOs*LG&&<XcN#NbMcd	
 445m_CHeGfg	
 00++7*<C@Z?[]	

 \QFBc	BX 44c::S@3}'DDcJJSPQ31Cc4JJCPPSVVW 	XE (A&&lA.(/$))G$T'+'+$nnQ6
 r6   c                    |j                  dd      }g }g }d}	 | j                  d      }|j                  dt        j                  j
                        }|j                         xs g }t        t        dt        |      dz              D ].  }	|j                  ||	dz     ||	dz  dz      ||	dz  dz      f       0 t        j                  |      }
t        |
j                        }t        t        |            D ]2  }	|j                  t        t        j                  |
|	k(                     4 	 	 t-        |      }g }|D ]4  }	 t/        |d   |d   |d         }|j                  t1        ||             6 d}t3        ||      D ]  \  }}|t4        k  s||z  } |dkD  r||z  nd}|rt7        t        |            nd}|t4        k  }|t8        k\  }|xr |}|rdn;t%        dt        dt%        dd|dz  z
        z  t        |t8        z  d      z              }g }|s |j                  d|ddt4         d| d       |s|j                  d|ddt8         d       |rdj;                  |      nd} ||t=        |d      t=        |d      || |t8        dd S # t         $ r t        j                  | j                  d            }|j"                  \  }}}t%        d||z  d	z        }|j'                  d
d      dd|   }|j)                  d      j+                  t              }t        |d         t        |d         t        |d         fg}||z  g}||z  }Y )w xY w# t         $ r d}Y /w xY w# t         $ r |j                  d       Y Lw xY w)!u=  design_md primary 색과 이미지 dominant colors의 Lab ΔE + 면적 비율을 검증한다.

    면적 비율 검증 (로키 G2 적대적 평가 MEDIUM #4-EDGE 해소):
      brand 색이 1% 영역만 차지해도 PASS되는 우회를 차단.
      매칭 색상 영역 ≥ 10% (BRAND_AREA_RATIO_MIN) 요구.
    primaryz#000000rv   r}      )colorsmethodr   rh   i'  r   Nr   r   )        r   r   g     8@r      rW   g      N@u$   브랜드 색상 불일치: min ΔE r   u    ≥ z
 (primary=)u2   브랜드 색 영역 부족: 매칭 영역 비율 .4fr   u(    (1% 영역만으로 PASS 우회 차단)r   rj   )force_brand_colormin_color_area_ratio)r:   r;   min_delta_ematching_area_ratioprimary_hexr   r   )getr   quantizer   Quantize
FASTOCTREE
getpaletteranger   r   r   r   r   r   sizesum	Exceptionr   r   r   r   r   rr   rt   r{   zipr   r
   r   r   r   )!r   	design_mdr   dominant_colorscolor_countstotal_pixelsrgb_img	quantizedpaletteiidx_arrarr_fbh_fbw_fbr   step_fbr   
mean_colorprimary_labdelta_esrgb	color_labmatching_areadecntr   r   
delta_e_okarea_okr:   r;   r   r   s!                                    r4   check_brand_color_matchr      s    !}}Y	:K 35O LL#++e$$$Aenn6O6O$P	&&(.Bs1c'la/01 	]A""GAENGAEAI4FPQTUPUXYPYHZ#[\	] ((9%7<<(s?+, 	;ABFF7a<$8 9:	;&!+.
 H #	##CFCFCF;IOOH[)<=# Mx. !C''S M! ;G:J-,6PS*2%H&K66J!%99G#GFBc!Sc#s[4=O7O.P)P+./BEY/Y[^+_*` &a bE G2;s2C5I`HaQ(	
 @ATUX@Y&''OQ	
 $+TYYwF [!,$%8!<"!,$8
 m  	##++e,-dAa$+%/0~~b!$YwY/YYAY&--c2

1.JqM0BC
STDVWXt}d{	#  &%&  	#OOE"	#s7   DJ 1M 1M/CMMM,+M,/NNc                f   ddl m} t        j                  g dg dg dgt        j                        }|j
                  } || d      }||z  j                  d      }||z  j                  d      }t        j                  |d	z  |d	z  z         }t        t        j                  |d
kD              S )uB   Sobel 엣지 밀도를 계산한다 (흑백 float32 numpy 배열).r   )sliding_window_view)r   r   rv   )r   rh   r~   )r   r   )r   r   r   rh      )
numpy.lib.stride_tricksr   r   r   r   Tr   rx   r
   r   )arr_grayr   sobel_xsobel_ywindowsgxgy	magnitudes           r4   _sobel_edge_densityr   S  s    ;hh
J
;2::NGiiG!(F3G
G
	 	 h	 	/B
G
	 	 h	 	/Ba"')*IR())r6   c                .   t        j                  | j                  d      t         j                        dz  }|j	                  d      }|j                  d      }||z
  }t        j                  |dkD  ||z  d      }t        |j                               S )u?   이미지 평균 채도를 HSV 기준으로 계산한다 (0~1).r}   r~   rJ   rh   r   r   r   )	r   r   r   r   r   r   wherer
   r   )r   r   max_cmin_cr   sats         r4   _mean_saturationr   a  sv    
((3;;u%RZZ
85
@CGGGOEGGGOE5=D
((519dUlC
0Cr6   c                "   | j                   \  }}}t        d||z  dz        }| j                  dd      dd|   j                  t        j
                        }t        t        t        t        t        |j                                                 S )uE   이미지 배열의 unique color 수를 샘플링으로 반환한다.rv   i r   r   N)r   r   r   r   r   r   r   r   r   r   r   r   )r   r   r   r   r   r   s         r4   _unique_color_count_sampledr   k  sp    iiGAq!q1q5V#$D;;r1ff%,,RXX6Ds3s5$++-01233r6   c                B    t        |       }|dkD  }|rdnd|dd}|||fS )uE   H1 포토 카드: Sobel edge density > 0.05 → 사진 영역 인정.r   Nu&   H1 사진 영역 부족: edge_density r   u	    ≤ 0.05)r   )r   densityr:   r   s       r4   _check_h1_photo_cardr   s  s9    !(+Gt^FT#I'RUV_!`F7F""r6   c                    t        |       }t        |      }|dkD  xr |dkD  }g }|dk  r|j                  d| d       |dk  r|j                  d|dd       |t        |      |rdj	                  |      fS d	fS )
uE   H2 일러스트 카드: unique colors > 5000 AND 평균 채도 > 0.4.i  r   zunique colors u	    ≤ 5000u   평균 채도 r   u    ≤ 0.4r   N)r   r   r   r
   r   )r   r   uniquer   r:   r   s         r4   _check_h2_illustration_cardr  {  s     )-F
3
Cd](sSyFG~xy9:
czCy9:5=499W#5KKdKKr6   c                $   t        |       }t        j                  |j                  d      t        j                        dz  }|j                  d      }|j                  d      }||z
  }t        j                  |dkD  ||z  d      }t        |j                               }d|cxk  xr d	k  nc xr |d
kD  }	g }
d|cxk  rd	k  sn |
j                  d|dd       |d
k  r|
j                  d|dd       |	||
rdj                  |
      fS dfS )uO   H3 GPT 스타일 카드: edge density 0.03~0.08 AND 채도 다양성 std > 0.1.r}   r~   rJ   rh   r   r   r   r   r   r   zedge_density r   u#    중간 범위(0.03~0.08) 벗어남u   채도 다양성 부족: std u    ≤ 0.1r   N)r   r   r   r   r   r   r   r   r
   r   r   r   )r   r   r   r   r   r   r   r   sat_stdr:   r   s              r4   _check_h3_gpt_style_cardr    s    "(+G
((3;;u%RZZ
85
@CGGGOEGGGOE5=D
((519dUlC
0CCGGIGg%%87S=FGG#t#wsm3VWX#~6wsm8LM77TYYw/EEEEr6   c                ~   | j                  t        j                        }t        t        j                  t        j
                  |d            j                               }t        t        j                  t        j
                  |d            j                               }||z   dz  }|dk  }|rdnd|dd	}|||fS )
uZ   H4 그래디언트 카드: 인접 픽셀 차이 평균 < 5 (부드러운 그라디언트).rv   r   r   r   r   Nu0   그래디언트 부드러움 부족: smoothness r   u    ≥ 5.0)r   r   r   r
   r   r   r   )r   arr_fr   r   
smoothnessr:   r   s          r4   _check_h4_gradient_cardr
    s    JJrzz"E266"''%a016689F266"''%a016689F6/S(J#FT#ST^_bScck!lF:v%%r6   c                   | j                  t        j                        }t        j                  t        j                  |d            }t        j                  t        j                  |d            }t        t        j                  |dkD  |dk  z              }t        t        j                  |dkD  |dk  z              }||z   dz  }|dkD  }|rdnd|d	d
}|||fS )uH   H5 사용자 사진 카드: 자연 사진 JPEG-like noise 비율 > 0.15.rv   r   r      r   r    Nu3   자연 사진 노이즈 패턴 부족: noise_ratio r   u	    ≤ 0.15)r   r   r   r   r   r
   r   )	r   r  r   r   noise_hnoise_vnoise_ratior:   r   s	            r4   _check_h5_user_photo_cardr    s    JJrzz"EVVBGGE*+FVVBGGE*+FBGGVaZFRK89:GBGGVaZFRK89:GW$+K4FT#VWbcfVggp!qF;&&r6   c           
         t        j                   j                  d      t         j                        t        j                   j                  d      t         j                        fd fd fdfdfdd	}||vrd
d|dd| i dS  ||          \  }}}|rdnd}|||t        t        |      d      ||t        j                  dd      ddS )uK   hybrid_pattern 별 시각 특징이 기준을 충족하는지 검증한다.r}   r~   rb   c                     t               S N)r   )r   s   r4   <lambda>z&check_hybrid_pattern.<locals>.<lambda>  s    !5h!? r6   c                     t               S r  )r  )r   r   s   r4   r  z&check_hybrid_pattern.<locals>.<lambda>  s    (CC(M r6   c                     t               S r  )r  )r   r   s   r4   r  z&check_hybrid_pattern.<locals>.<lambda>  s    %=h%L r6   c                     t               S r  )r
  r   s   r4   r  z&check_hybrid_pattern.<locals>.<lambda>  s    $;C$@ r6   c                     t               S r  )r  r  s   r4   r  z&check_hybrid_pattern.<locals>.<lambda>  s    &?&D r6   r!   Fr   r   u   알 수 없는 hybrid_pattern: )r:   r;   patternfeature_valuer   r   r   rk   r   )force_pattern_signaturepattern_specific_seed)	r   r   r   r   r   r   r
   r   r   )	r   hybrid_patterndispatchr:   r  r   r;   r   r   s	   `      @@r4   check_hybrid_patternr     s    
((3;;u%RXX
6CxxC(

;H @ ML@D H X%% 77GH
 	
 %=H^$<$>!FM6BaE !u]3Q7'5%+^^Au%=

 
r6   c           	        t         s
ddddddi dS 	 t        j                  t        j	                  d            }t        |       t        |d   d	         }|d   dz  }t        ||z        }	 t        j                  | dt        j                        }t        |d   |d         D 	cg c]>  \  }}	t        |t              r)|j!                         rt        |	      dkD  rt        |	      @ }
}}	|
sddd|dd|idS t#        |
      }||k\  }|rdnd}|rdnd| d| d}|||||d|idS # t        $ r}t        d
| d      |d}~ww xY wc c}	}w # t        $ r}dddd|d| i dcY d}~S d}~ww xY w)u   dq-rules.json absolute_min 기준으로 텍스트 최소 높이를 검증한다.

    pytesseract 미설치 시 BLOCKED 상태 반환 (silent pass 차단).
    Tr   r   R   BLOCKED: pytesseract 미설치 — 시스템에 tesseract + kor.traineddata 필요)r:   blockedr;   min_text_height	thresholdr   r   zutf-8)encodingr(   r)   u.   dq-rules.json 로드/스키마 검증 실패: u4   . 단일 소스 파일 무결성을 확인하세요.Ng     @korlangoutput_typetextheightu/   BLOCKED: OCR 실행 오류 (운영팀 알림): Fu'   텍스트 미감지 (OCR 결과 없음)min_font_px)r:   r;   r$  r%  r   r   r  u.   폰트 크기 미달: 최소 텍스트 높이 zpx < px)_TESSERACT_AVAILABLEjsonloads_DQ_RULES_PATH	read_textr5   r   r   r/   pytesseractimage_to_dataTesseractOutputDICTr   
isinstancestrstripr   )r   target_sizer0   r)   excscaler%  datar+  r   heightsr$  r:   r;   r   s                  r4   check_font_sizer@    s   
   !j
 	
	

>33W3EF!%(l 3N CD NV#EL5()I
((5oFZFZ[ tF|T(^<
a$$#a&1* F
 
"  "?()4
 	
 'lO	)FBaE  	=o=NeT]S^^`a  *$i0 e  <SE BA B
 	

  

 !"GuM
 	


sI   AD* .;E )AE,E *	E3EEE 	E1E,&E1,E1c           
         t         s
ddddddi dS 	 t        j                  | dt        j                        }t        |d	   |d
         D cg c]>  \  }}t        |t              r)|j                         rt        |      dk\  rt        |      @ }}}dj                  d |d	   D              }|sddd|dddddS t        t        |      t        |      z        }t        d |D              }t        d |D              }	|	dkD  r||	z  nd}
|t        k\  }|
t         k\  }|xr |}|rdn2t#        dt        d|t        z  z  t%        |
t         z  d      z              }g }|s|j'                  d|ddt         d       |s|j'                  d|
ddt         d d!       |rd"j                  |      nd}||t)        |d#      t)        |
d$      |dd% |dddd&S c c}}w # t        $ r}ddddd| ddddcY d}~S d}~ww xY w)'u   pytesseract 한글 OCR 신뢰도 평균 ≥ 70% 를 검증한다.

    pytesseract 미설치 시 BLOCKED 상태 반환 (silent pass 차단).
    Tr   g       r"  )r:   r#  r;   avg_confidenceextracted_textr   r   r'  r(  r+  conf c              3  d   K   | ](  }t        |t              s|j                         s%| * y wr  )r8  r9  r:  ).0rY   s     r4   	<genexpr>z'check_ocr_confidence.<locals>.<genexpr>R  s&      "
z!S'9aggiA"
s   000Fr   u   OCR 실행 오류: zPretendard,NotoSansCJK)force_korean_fontfallback_check)r:   r;   rC  rD  r   r   Nu+   한글 텍스트 미감지: OCR 신뢰도 0c              3  >   K   | ]  }d |cxk  rdk  sn nd  ywu   가u   힣rv   NrH   rH  rK   s     r4   rI  z'check_ocr_confidence.<locals>.<genexpr>t  s     HQEQ4G%4GqHs   
c              3  ^   K   | ]%  }|j                         sd |cxk  rdk  sn nd ' ywrM  )isalnumrN  s     r4   rI  z'check_ocr_confidence.<locals>.<genexpr>u  s%     VA199;%1BUPUBUaVs    -
-r  rW   u$   한글 OCR 신뢰도 미달: 평균 z.1fz% < %u    한글 텍스트 비율 부족: z.2%r   z.0%u    (한글 깨짐 회귀 차단)r   rh   rj      )r:   r;   rC  korean_ratiorD  r   r   )r/  r4  r5  r6  r7  r   r8  r9  r:  r   r   r   r
   r   r   r   r   r   r   r   r   )r   r>  r+  rE  confidencesrD  r<  rC  korean_charstotal_alnumrS  confidence_ok	korean_okr:   r;   r   r   s                    r4   check_ocr_confidencerY  :  s~   
   " j
 	

((5oFZFZ[ "$v,V=
d$$#d)q. I
 

  "
F|"
 
  !,C%="&

 
	
 3{+c+.>>?N
 H.HHLVVVK3>?L;.L"&>>M 44I(yFBc	B.#;;<,!55s;< 	=E G2>#2FdKcJddef	
 .|C.@DXY\C],.	
 $+TYYwF 2lA.(#.!9"
 A
  
! +C51%="&

 
	

s0   ;G AGG G 	G=$G82G=8G=c           
        t        j                  |       j                  d      }i }t        |      |d<   t	        ||      |d<   t        ||      |d<   t        ||      |d<   t        |      |d<   t        d |j                         D              }g }g }i }	|j                         D ]  \  }
}|j                  d      r(|j                  d	|
 d
|j                  dd              ?|d   rE|j                  d      r|j                  d	|
 d
|d           |j                  di       }|	j                  |        t        |      dk(  xr t        |      dk(  }|r|j                  |       t!        |t#        d|      ||	|      S )uU   PNG 이미지를 5가지 품질 기준으로 평가하고 EvalResult를 반환한다.r}   visual_diversitybrand_color_matchr  	font_sizeocr_confidencec              3  &   K   | ]	  }|d      yw)r;   NrH   )rH  rO   s     r4   rI  z!evaluate_image.<locals>.<genexpr>  s     ;Qaj;s   r#  [z] r   BLOCKEDr:   r   r   d   )r:   r;   r=   r?   r@   )r   openr   r   r   r   r@  rY  r   valuesr.   r   r   updater   extendr8   r   )png_pathr   r  r;  r   resultstotal_scorer=   blocked_reasonsmerged_hintskeyrO   hintr:   s                 r4   evaluate_imagern    s    **X

&
&u
-C)+G #9"=G $;3	#JG  !5S. IG +3<GK !5S 9G ;'..*:;;K L!#O#%L--/ 	&Q55""Qse2aeeHi.H-I#JK{uuX##auBq{m$<=55r*D%	& !#AO(<(AF O,#{#!  r6   )r0   r>   r[   None)rK   r
   r[   r
   )rO   r
   rP   r
   rQ   r
   r[   tuple[float, float, float])rR   r
   rS   r
   rT   r
   r[   rp  )rm   r9  r[   rp  )rO   r   rP   r   rQ   r   r[   rp  )ry   rp  rz   rp  r[   r
   )r   Image.Imager[   r>   )r   rq  r   r>   r[   r>   )r   
np.ndarrayr[   r
   )r   rq  r[   r
   )r   rr  r[   r   )r   rr  r[   tuple[bool, float, str | None])r   rr  r   rq  r[   rs  )r   rr  r   rq  r[   rs  )r   rr  r[   rs  )r   rq  r  r9  r[   r>   )r   rq  r;  tuple[int, int]r[   r>   )
rg  r   r   r>   r  r9  r;  rt  r[   r8   )7rD   
__future__r   r0  rw   r   dataclassesr   r   pathlibr   typingr   numpyr   PILr   r4  r	   r6  r/  ImportErrorr2  r   rE   r   r   r   r   r   r   r'   r*   r5   r8   rM   rU   re   rr   rt   r{   r   r   r   r   r   r   r  r  r
  r  r   r@  rY  rn  rH   r6   r4   <module>r|     s   #    (    !5
 FG # e "%) s ) %) E (!%  %" e ""& % &! e ! 0628DQ154gkl-s3.53 /  >"1 - 
* : : :)&
  ?LY@*4#L	L%L#LFF*F#F*&'$VPn^J888 8 !	8
 8A  ! !s   D D"!D"