
    "_jz                    ~   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	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Zddlm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ZddlZddlZ ee      j?                         j@                  d   Z!ejD                  jG                  d	      r1 eejD                  d	         jI                         j?                         ne!d
z  dz  Z% ee      j?                         jM                  d      Z' ee      j?                         jM                  d      Z(h dZ)e G d d             Z*e G d d             Z+e G d d             Z, G d d      Z-d<dZ.d=dZ/d>dZ0d?dZ1d@dZ2dAdZ3	 dB	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dCdZ4dDdZ5dEdZ6dFd Z7dGd!Z8dHd"Z9dId#Z:dJd$Z;dKd%Z<dLd&Z=dMd'Z>dNd(Z?dOd)Z@dPd*ZAdQdRd+ZBdSd,ZCdTd-ZDdUd.ZEdVd/ZFdWd0ZGdXd1ZHdXd2ZIdYd3ZJdZd4ZK	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d[d5ZLd\d6ZMd]d7ZNd^d8ZOd_d9ZPdUd:ZQeRd;k(  r ej                   e.              yy)`zFolder batch processor for ramen soup video evaluation.

Pipeline:
  input folder CSV/videos -> best frame -> BytePlus Responses API -> SQLite -> JSONL/CSV dataset.
    )annotationsN)	dataclass)datetimetimezone)Path)Any   RAMEN_POLICY_PATHpromptzsoup_eval_prompt_policy.mdzconfig.yamlzconfig.example.yaml>   .avi.m4v.mkv.mov.mp4c                  6    e Zd ZU ded<   ded<   ded<   ded<   y	)
	InputItemr   
video_pathzPath | Nonecsv_pathz
int | None	row_indexdict[str, Any]metadataN__name__
__module____qualname____annotations__     F/var/www/ramen.bs-engineer-server.com/local_batch_api/batch_process.pyr   r   0   s    r   r   c                  6    e Zd ZU ded<   ded<   ded<   ded<   y	)
ExtractedItemr   itemstr
video_hashr   
frame_pathr   frame_metricsNr   r   r   r   r!   r!   8   s    
OO!!r   r!   c                  ,    e Zd ZU ded<   ded<   ded<   y)
FailedItemr   r"   r#   r$   errorNr   r   r   r   r(   r(   @   s    
OOJr   r(   c                      e Zd ZddZddZy)RateLimiterc                f    |dkD  rd|z  nd| _         t        j                         | _        d| _        y )Nr   g      N@        )interval	threadingLocklocknext_allowed_at)selfrequests_per_minutes     r   __init__zRateLimiter.__init__H   s/    6IA6M22SVNN$	"r   c                F   | j                   dk  ry | j                  5  t        j                         }t	        d| j
                  |z
        }t	        || j
                        | j                   z   | _        d d d        dkD  rt        j                  |       y y # 1 sw Y   %xY w)Nr   r-   )r.   r1   time	monotonicmaxr2   sleep)r3   now	sleep_fors      r   waitzRateLimiter.waitM   s    ==AYY 	R.."CC!5!5!;<I#&sD,@,@#ADMM#QD 	R q=JJy! 		R 	Rs   ABB N)r4   floatreturnNone)r   r   r   r5   r=   r   r   r   r+   r+   G   s    #
"r   r+   c            
     8   t        j                  d      } | j                  ddd       | j                  dt        t              d	       | j                  d
dd       | j                  dt
        dd       | j                  ddd       | j                         }t        t        |j                              }t        |       t        |j                        j                         j                         }|j                         r|j                         st!        d|       t#        |d   d         }|dz  }|j%                  dd       |j%                  dd       t#        |d   d         }|j&                  j%                  dd       t)        j*                  |d      }t-        |       t/        t0              }t3        |      }	|j4                  dkD  r|	d |j4                   }	t7        d|        t7        dt9        |	       d|        t7        dt:        j<                  j?                                 tA        |	|      }
tC        ||	||||jD                  |jF                  |
       }tI        ||       |jK                          t7        d!| d"|        y)#Nz'Process ramen soup videos with VLM API.)descriptionz--inputTz*Folder containing videos and optional CSV.)requiredhelpz--configzYAML config path.)defaultrE   z	--dry-run
store_truez1Extract frames and record rows without API calls.)actionrE   z--limitr   z$Maximum number of videos to process.)typerF   rE   z--forcez'Reprocess videos already present in DB.zInput folder not found: paths
output_dirframes)parentsexist_okdb_pathF)check_same_threadzinput=zitems=z db=zopencl=)connitemsconfigr   
frames_dirdry_runforcedensity_mapzdone processed=z output=)&argparseArgumentParseradd_argumentr#   CONFIG_PATHint
parse_argsload_configr   rS   setup_accelerationinput
expanduserresolveexistsis_dir
SystemExitresolve_pathmkdirparentsqlite3connectinit_dbbuild_promptPOLICY_PATHdiscover_itemslimitprintlencv2ocl	useOpenCLresolve_densitiesrun_pipelinerU   rV   export_datasetsclose)parserargsrS   	input_dirrK   rT   rO   rQ   r   rR   rW   	processeds               r   mainr}   X   sV   $$1Z[F
	D7cd

C,<CVW
L?rs
	Q=cd
	,=fgDdkk*+FvTZZ ++-557IY%5%5%73I;?@@fWol;<Jh&JTD1TD16'?956GNN5??7e<DDM+&F9%EzzA~l

#	F9+
	F3u:,d7)
,-	GCGG%%'(
)*#E62Kjj	I D*%JJL	OI;hzl
;<r   c                   |j                  di       xs i }|j                  dd      si S 	 ddlm}m} i }|j                  d      }|r7t        t        t        |                  }|rt        d	t        |       d
       i }d}	| D ]  }
|j                  |
j                  j                        }||	 |t        |j                  dd            t        |j                  dd            t        |j                  dd            t        |j                  dd            t        |j                  dd            t        |j                  dd            t        |j                  dd                  }	|	j                  |
j                  |
j                        }||t        |
j                        <   |j                  d      dk(  r|d   n|j                  d      }t        d|
j                  j                    d|j                  d       d | d!|j                  d"       d#|j                  d$       
        |S # t        $ r}t        d|        i cY d}~S d}~ww xY w)%u_  LLM送信前に各動画の濃度を確定する条件分岐。

    CSV等に濃度があればそのまま、無ければ画像モデルで推定（スープが見えなければ判定不可）。
    config["density"]["enabled"] が False の場合は何もしない（従来動作）。
    戻り値は video_path(str) -> 解決結果dict。
    densityenabledFr   )DensityResolverdensity_in_metadataz#WARN density resolver unavailable: N
cache_pathzdensity cache: u    件読み込み	conf_keepg      ?crop_thresholdg?rL      	multi_min   vote_mingffffff?high_mean_confg
ףp=
?deviceauto)r   r   rL   r   r   r   device_namestatusoksourcezDENSITY : valuez (/
confidencez) note)getdensity_resolverr   r   	Exceptionrp   load_density_cacherf   r#   rq   r   stemr>   r\   rb   r   name)rR   rS   density_cfgr   r   exccache	cache_cfgoutresolverr"   restags                r   ru   ru      s    **Y+1rK??9e,	I (*E-I"<I#?@OCJ</?@A%'CH wii,,-;*#KOOK$FG#(9I4)P#Q{x<=!+//+q"AB";??:t#DE#(9I4)P#Q #KOOHf$E F ""4??DMMBC$'C !"wwx0D8c(mcggh>O--.b1A0B"SE377S_K`Jaacdgdkdklrdsctuv!w" J?  3C59:	s   H9 9	IIIIc                Z   | j                         si S i }| j                  dd      5 }|D ]N  }|j                         }|s	 t        j                  |      }|j                  d      s>||t        |d         <   P 	 ddd       |S # t        j
                  $ r Y qw xY w# 1 sw Y   |S xY w)ug   prepare_densities.py が出力した濃度キャッシュ(JSONL: 1行1動画)を stem->res で読む。rutf-8encodingr   N)rc   openstripjsonloadsJSONDecodeErrorr   r#   )r   r   fhlinerecs        r   r   r      s    	%'C	w	/ 
,2 		,D::<Djj& wwv(+CF$%		,
, J	 '' 
, Js5   B BB )B BB BB  B*c                   | syg }| d   dk(  r)| j                  d      r|j                  d| d           nV| d   dk(  r=| j                  d      dk(  r)| j                  d      r|j                  d	| d           n|j                  d
       | j                  d      du r|j                  d       n$| j                  d      du r|j                  d       dj                  |      S )u  解決済み濃度を、LLMへ渡す『別入力』テキストに整形する。

    精度最優先のため、LLMに数値を渡すのは
      - CSV提供値 (source=provided)
      - 画像モデル推定のうち高信頼 (confidence=high)
    のみ。中信頼以下は誤りリスクがあるため数値を渡さず「判定不可」とする
    （弱い推定値はDBの density_resolution に保持され、後段分析で参照できる）。
     r   providedr   u8   【別入力】スープ濃度(計測/人手ラベル): modelr   highuG   【別入力】スープ濃度(画像モデル推定 / 信頼度:高): un   【別入力】スープ濃度: 判定不可（画像から高信頼に確認できないため数値なし）readableFu  【撮影品質】湯気または構図によりスープ表面が確認できません。濃度値が分かっていても液体本体の見た目は判断できないため、assessable=false / retake_recommended=true とし、confidence を下げてください。
assessableu   【撮影品質】スープ表面の視認性が低めです。確信が持てない項目は confidence を下げ、必要に応じて retake_recommended=true としてください。
)r   appendjoin)r   liness     r   density_input_noter      s     E
8}
"swww'7OPST[P\~^_	X'	!cggl&;v&E#''RYJZ^_bcj_k^lmn  F  	G
wwze#i	

 
	%	'R	
 99Ur   c                Z   |j                  di       xs i }t        |j                  dd            }| r|dv ry| j                  d      ry|dk(  rdd	| j                  d
       fS t        |j                  dd            }t        | j                  d
d            }||k\  rdd|dd| fS y)u  不可読動画をLLMに送る前にスキップすべきか判定する。

    action:
      - skip_if_steamy (既定): 不可読 かつ 湯気が多い(steam_mean>=閾値)ときのみスキップ。
            湯気が薄いのに不可読＝RF-DETRの構図未対応(OOD)の疑いがあるためLLMに送る。
      - always_skip            : 不可読なら必ずスキップ。
      - always_send / off      : スキップしない（従来動作）。
    可読(readable=True)な動画は常にLLMへ。
    r   unreadable_actionskip_if_steamy)always_sendoff)Fr   r   always_skipTu,   不可読(全スキップ設定) steam_mean=
steam_meansteam_skip_thresholdg?      ?u$   不可読かつ湯気多 steam_mean=.2fz>=)r   r#   r>   )r   rS   r   rH   	steam_thrr   s         r   decide_skip_llmr      s     **Y+1rK!46FGHF&22
wwzCCGGLDYCZ[[[koo&<dCDIsww|S12JY;Js;K2i[YYYr   c                    | xs i } | j                  d      dk(  r| j                  d      nd}ddddd	d
ddiddidd|r|ndd|ddS )ul   LLMをスキップした不可読動画のための、評価スキーマ準拠の判定不可レコード。r   r   r   NFTu   不良u   判定不可u   低)r   r   stater   ui   可読性レイヤーによりスープ表面が確認できずLLM評価を見送り（判定不可）。readability_layer)r   retake_recommendedphoto_qualityvisual_densitywater_leveloil_emulsificationboiling_heat_stateimage_condition_scoresoup_density_inputsummaryskip_reasonevaluation_sourcer   )r   reasonr   s      r   synthetic_unassessabler     sl    
)C#&778#4
#BswwwH"!$2%H0&7,!"*2h~0 r   c           
         xs i j                  di       }t        dt        |j                  dd                  }	rdn$t        dt        |j                  dd                  }
t        |j                  dd            }t	        j
                         t	        j
                  |
dz  |	z         t        j                         t        |      d	d
i|D ]  }j                  |        t        |	      D ]  }j                  d         d fd}d f	d}t        |	      D cg c]  }t        j                  |d       }}t        |
      D cg c]  }t        j                  |d       }}||z   D ]  }|j                           |D ]  }|j                           t        |
      D ]  }j                  d         |D ]  }|j                           d	   S c c}w c c}w )Nconcurrencyr	   frame_workers   api_workersr4      )maxsizer|   r   c                    	 j                         } 	 | 	 j                          y t        | j                        }5   xr t	        |      }d d d        r4t        d| j                  j                          	 j                          t        d| j                  j                          t        | j                        }| j                  j                   d|d d  d}|z  }t        ||d   t        d   d                
j                  t        | |||j                         D ci c]  \  }}|dk7  s|| c}}	             j                          _# 1 sw Y   xY wc c}}w # t        $ rc}| r/| j                  j                         rt        | j                        nd
}	
j                  t!        | |	t#        |                   Y d }~d }~ww xY w# j                          w xY w)NzSKIP already_done zEXTRACT _
   .jpgimage
processingjpeg_quality)r"   r$   r%   r&   r   )r"   r$   r)   )r   	task_donefile_sha256r   already_donerp   r   extract_best_framer   
write_jpegr\   putr!   rR   r   rc   r(   r#   )r"   r$   skipframe
frame_namer%   kvr   fallback_hash	api_queuerS   rQ   db_lockrV   rT   input_queues             r   	extractorzrun_pipeline.<locals>.extractor;  s   ??$D(<2 %%'1 )9
 J %II<j+IDJ.t/C/C.DEF& %%'# !5!5 678*4??FC $ 4 45Qz#26GtL
'*4
:uW~s6,;OP^;_7`a!!#-#-8=&V1gq!t&V	 %%'; J J  'W  _@DI_I_IaDOO <gijd}TWX[T\]^^_ %%'s_   E5 E5 E",E5 B!E5 0E/>E/E5 "E,'E5 5	G!>AGG$ G!!G$ $G6c                 0  	 	 j                         } 	 | 	 j                          y t        | t              r5  t	        | j
                  | j                  t        d      i i d d | j                  
       dxx   dz  cc<   d d d        t        d| j
                  j                  j                   d| j                          	 j                          Չj                  t        | j
                  j                              }t        |      \  }}|rt        ||      }i | j                  d|i}5  t	        | j
                  | j                  | j                   |d|d	d |d
       dxx   dz  cc<   d d d        t        d
| j
                  j                  j                   d| d       	 j                          | j                   }j                  di       j                  dd      r=|r;|j                  d      xs d}|r$t        |      j#                         rt        |      }t%        |t'        |            }d }	d }
d}rd}n(j)                          	 t+        |      }	t-        |	      }
|ri | j                  d|in| j                  }5  t	        | j
                  | j                  ||||	|
|
       dxx   dz  cc<   d d d        |
rdnrdnd}t        | d| j                   j                   d| j                  j                  dd      dd|        j                          9# 1 sw Y   xY w# 1 sw Y   xY w# t.        $ r}t        |      }Y d }~d }~ww xY w# 1 sw Y   xY w# j                          w xY w)NTr   
rQ   r"   r$   r%   r&   request_payloadapi_response
assessmentr)   rU   r|   r	   zERR extract  density_resolution)skippedr   z	SKIP-LLM u    判定不可 ()r   use_best_frame_for_llmbest_frame_pathzdry_run: API call skippedOKDRYERRz frame=z score=selection_scorer   r   )r   r   
isinstancer(   save_resultr"   r$   r   r)   rp   r   r   r#   r   r   r&   r%   rc   build_request_payloadr   r=   call_byteplusparse_assessmentr   )workdensity_resr   r   	syntheticframe_metrics_skipllm_frame_path
best_framer   r   parsedr)   r   frame_metrics_outr   r   rS   rQ   countersr   rW   rU   limiterr   s                  r   
api_senderz run_pipeline.<locals>.api_sender[  s   ==?DS&<b ##%a dJ/  3#!%!%'+'+Bx*,,.)-'+"&**$+ !-2-3 L)=)=)B)B(C1TZZLQR@ ##%} *ooc$))2F2F.GH %4K$H!k 6{K PI)bD,>,>)b@TVa)b&  3#!%!%'+'+*<8<,T)-'0"$$+ !-2-3 Idii&:&:&?&?%@P[}\]^_P ##%M "&::i,001I4PU`!,1B!C!IrJ!d:&6&=&=&?)-j)9"7XjkvXw"x6:047ELLN)'4V_'M!1,!? bm$]t'9'9$];OQ\$]rv  sE  sE! /!!YY#'??#1&7(7%1#)# ' [)Q.)/ "(weE(<(<'=WTEWEWE[E[\mopEqruDvvwx}w~  A##%k 3 303 3D % ) #C)/ /" ##%s   N N A
L<AN AN 6AM	:8N BN #M :"N 7M7AN <MN 	MN 	M4M/*N /M44N 7N <N NT)targetdaemonr?   )r   r9   r\   r>   queueQueuer/   r0   r+   r   rangeThreadstartr   )rQ   rR   rS   r   rT   rU   rV   rW   r   r   r   rpmr"   r   r   r  extract_threadsapi_threadsthreadr   r  r   r   r  s   ` ``````           @@@@@r   rv   rv      s    #K**]B/K3{BCDM!C3{}a/P+Q$RK
 5r:
;C16K@ET_bcTcfsTs@tInnG#GQH =! ( (@V& V&p QVVcPde1y''yFeOeMRS^M_`9##:dC`K`!K/ ! ; d K   f`s   G<.Hc                    | j                         r| nt        }|j                  dd      5 }t        j                  |      cd d d        S # 1 sw Y   y xY w)Nr   r   r   )rc   DEFAULT_CONFIG_PATHr   yaml	safe_load)pathr   r   s      r   r^   r^     sE    [[]T(;F	S7	+ "r~~b!" " "s   AAc                N    t        |       }|j                         r|S t        |z  S N)r   is_absoluteROOT)r   r&  s     r   rf   rf     s%    ;D##%464$;6r   c                    t        | j                  di       j                  dd            }	 t        j                  j	                  |       t        j
                  d       y # t        $ r Y y w xY w)Nr   
use_openclT)boolr   rr   rs   setUseOpenCLsetUseOptimizedr   )rS   r   s     r   r_   r_     s[    6::lB/33L$GHGW%D! s   4A" "	A.-A.c                2    | j                  d      }d| dS )Nr   r   u   あなたはラーメン豚山のスープ状態を画像から評価するAI評価者です。
以下の方針を固定の評価基準として厳守してください。

uw   

出力はJSONのみ。Markdown、コードブロック、前置き、補足説明は出力しないでください。)	read_text)policy_pathpolicys     r   rl   rl     s1    ""G"4F	Z( @	@r   c                4   t        | j                  d            }| j                         D ci c]>  }|j                  j	                         t
        v s$|j                  j	                         |@ }}g }|rS|D ]K  }|j                  ddd      5 }t        t        j                  |            D ]  \  }}|j                  d      xs |j                  d      xs dj                         }	|j                  d      xs |j                  d	      xs dj                         }
|	s|
sx|j                  |	j	                               xs | |	z  }|j                         s|
rt        | |
|      }|j                         r(|j                  t!        |||t#        |      
             t%        d|dz    d|	         	 d d d        N |S t        |j'                               D ]   }|j                  t!        |d d i 
             " |S c c}w # 1 sw Y   xY w)Nz*.csvr   	utf-8-sigr   r   newlineu   添付ファイルvideoIDid)r   r   r   r   zWARN missing_video row=r	   z name=)sortedglobiterdirsuffixlowerVIDEO_EXTENSIONSr   r   	enumeratecsv
DictReaderr   r   rc   resolve_video_by_idr   r   dictrp   values)r{   	csv_filespvideosrR   r   r   idxrow
video_namevideo_idr   s               r   rn   rn     s   y~~g./I)2):):)<eA@PTd@daffllnaeFeE! 	UHs["E U )#..*< = UHC"%''*>"?"Y3777CS"YWY!`!`!bJ # D D"KKMH%h !'J,<,<,>!?!Y9zCYJ%,,.8%8Hf%U
!((*Y*xcfquvyqz%{| 7ayzlSTUU U	U$ L !1 	gJLLj4SWbdef	g L- f
U Us   %HHD+HH	c                    t        t              D ]-  }| | }|j                  |j                               }|s+|c S  | | dz  S )Nz.MOV)r;  r@  r   r?  )r{   rM  rI  	extensioncandidate_namer   s         r   rD  rD    sY    ,- 	$:i[1ZZ 4 4 67
	
 (4(((r   c                   t        j                  t        |             }t        |j	                  t         j
                              xs d}t        |j	                  t         j                        xs d      }|dk  r|j                          t        d|        t        |j	                  di       j	                  dd            }|dk(  rlt        | |      \  }}}|j                          t        |      }|t        |      |t        |d   t        |d   j	                  d	d
            z        d|d|iS |dk(  rt        dt        |d   j	                  dd                  }	d }d}t        t        ||	dz               D ]  }|j                         \  }
}|
s n|} |j                          |t        d|        t        |      }|t        |      |t        |d   t        |d   j	                  d	d
            z        d|d|iS t        |d   d         }t        dt        t!        ||z                    }t#        t        d||            }t        |d   d         }|dkD  rVt%        |      |kD  rHt'        j(                  dt%        |      dz
  |      j+                  t              }|D cg c]  }||   	 }}d }d }t        |d   j	                  dd            }t        |d   j	                  d	d
            }|D ]  }|j-                  t         j.                  |       |j                         \  }
}|
s9t        |      }t1        ||dz  z
        t        |d      z  }|d   |z  |d   dz  z   |d   dz  z
  |d   dz  z
  |d   dz  z
  |dz  z
  }|t        |      |t        |      d|}||d   |d   kD  r|}|d   |k  r||d   |d   kD  s|} |j                          ||}|t        d|        |S c c}w ) Nr         >@zVideo has no readable frames: r   extraction_strategybest_sampleffmpeg_middle	sharpnesssharpness_weightgQ?)r   frame_no	video_fpsr  
fast_firstfast_warmup_frames   r	   zNo readable initial frames: 
sample_fpsmax_candidatesmin_sharpnessg      T@r   contrastg?blowout_ratio      ^@steam_haze_scoreg     V@motion_blur_scoreg       @r  zNo readable sampled frames: )rr   VideoCapturer#   r\   r   CAP_PROP_FRAME_COUNTr>   CAP_PROP_FPSreleaseRuntimeErrorextract_frame_with_ffmpegr&   r9   r  minreadroundlistrq   nplinspaceastypesetCAP_PROP_POS_FRAMESabs)r   rS   captotalfpsstrategyr   rX  metricswarmup_framesr   currentr]  step
candidatesr^  indexesibestfallback_bestr_  rW  center_penaltyr  	candidates                            r   r   r     s   


3z?
+C00127aE
(()1T
2Cz;J<HII6::lB/334I=YZH?"8VLx&H$W[%9E&BVBZBZ[motBu<v%vw	

 
 "8
 	
 <As6,#7#;#;<PRT#UVWc%):;< 	H((*KBE		
 	=!=j\JKK&H$W[%9E&BVBZBZ[motBu<v%vw	

 
 "8
 	
 vl+L9:Jq#eC*,-./DeAud+,J-.>?@Nc*o>++aZ1!4nELLSQ-45jm5
5"&D+/M&.22?DIJMVL1556H%PQ ''2HHJ	E&X34s5!}DK #33j!C'(o&./ ()D01 )*T1	2
 s"# 	 H$_5	

 
	  I.?$@=QbCc$c%M;-/<9%67$?P:QQD7: KKM||9*FGGKQ 6s   /O>c           
        t        j                  | t         j                        }t        t        j                  |t         j
                        j                               }t        j                  |t         j
                  ddd      }t        j                  |t         j
                  ddd      }t        t        |j                               t        |j                               z
        t        t        |j                         |j                         z         d      z  }t        |dkD  j                               }t        |j                         dz        }t        |dkD  j                               }t        d	d
|z
        }	t        t        d|dz  |	dz  z               }
t        t        dt        d	d|z
  dz        |dz  z               }|||||
dS )Nr	   r      )ksizer      g     o@   r-   g)\(?g      ?       @rb  g      ?)rV  rd  ra  r`  rc  )rr   cvtColorCOLOR_BGR2GRAYr>   	LaplacianCV_64FvarSobelrt  r9   meanstdrk  )r   grayrV  sobel_xsobel_ydirectional_gapra  r`  bright_ratiolow_contrastrc  rd  s               r   r&   r&   _  sy   <<s112DcmmD#**599;<Iiicjj!Qa8Giicjj!Qa8G%.w{{}1EEFUSZS^S^S`cjcncncpSpMqsvIwwO4#:++-.MTXXZ%'(H$***,-LsD8O,LSlT&9L3<N&NOPc#s31Be0K'LaeOe'efg.&, r   c                J   t        |d   j                  d      d      }t        |d   j                  d      d      }t        || d      }t        ||       }t	        |d   j                  dd            }|d	kD  rt        d
||z        nd
}t        j                  dd      5 }t        |j                        }	d d d        	 |dddd|ddt        |       dddddt        	      g}
t        j                  |
ddd      }|j                  d	k7  r3t        d| j                   d|j                  j!                                t#        j$                  |	j'                         t"        j(                        }t+        j,                  |t*        j.                        }|t        d| j                         |d	kD  rt1        t3        ||z              nd	}|||f	 |	j5                          S # 1 sw Y   /xY w# t6        $ r Y S w xY w# 	 	j5                          w # t6        $ r Y w w xY wxY w) Nr   ffmpeg_pathffmpegffprobe_pathffprobedurationffmpeg_position_ratiogffffff?r   r-   r   F)r>  deletez-hide_bannerz	-loglevelr)   z-ssz.3fz-iz	-frames:v1z-q:v2z-yT<   capture_outputtexttimeoutzffmpeg failed for r   )dtypez'ffmpeg output is not a readable image: )resolve_binaryr   probe_float	probe_fpsr>   r9   tempfileNamedTemporaryFiler   r   r#   
subprocessrun
returncoderi  stderrr   ro  
frombuffer
read_bytesuint8rr   imdecodeIMREAD_COLORr\   rm  unlinkFileNotFoundError)r   rS   r  r  r  rw  position_ratioseek_secondstmptmp_pathcmdresultdatar   rX  s                  r   rj  rj  t  s
   F<044]CXNFVL155nEyQG7J
;H
GZ
(C6,/334KTRSN:BQ,3sH~56CL		$	$F5	A "S>"C 
OM
  DtRP!!3JOO3DBv}}GZGZG\F]^__}}X002"((CT3#3#34=!HHYZ[[581W3u\C/01!h#	OO=" "> ! 			OO  		sO   !G$ DH  G1$G.1	G=<G= H"HH"	HH"HH"c                    | r=t        t        |             j                         }|j                         rt        |      S t	        j
                  |      }|r|S t        | d| d      )Nz1 was not found. Install ffmpeg or set processing.z_path.)r   r#   ra   rc   shutilwhichri  )
configuredr   r&  founds       r   r  r    sa    C
O$//1;;=t9LLE
$PQUPVV\]
^^r   c                    t        j                  | dddd| ddt        |      gddd	      }|j                  d
k7  ry	 t	        |j
                  j                               S # t        $ r Y yw xY w)N-vr)   -show_entrieszformat=-of"default=noprint_wrappers=1:nokey=1T   r  r   r-   )r  r  r#   r  r>   stdoutr   
ValueError)r  r   fieldr  s       r   r  r    s    ^^eW0
O		
 F AV]]((*++ s   "A" "	A.-A.c                X   t        j                  | ddddddddt        |      g
d	d	d
      }|j                  j	                         }d|v r7|j                  dd      \  }}	 t        |      t        t        |      d      z  S 	 t        |      S # t        $ r Y yw xY w# t        $ r Y yw xY w)Nr  r)   z-select_streamszv:0r  zstream=avg_frame_rater  r  Tr  r  r   r	   r   rR  )	r  r  r#   r  r   splitr>   r9   r  )r  r   r  r   	numeratordenominators         r   r  r    s    ^^#0
O	
 F" MM!E
e|!&S!!4	;	#c%*<c&BBBU|  		  s$   ! B 
B 	BB	B)(B)c                    t        j                  d|t        t         j                        |g      \  }}|st	        d|        | j                  |j                                y )Nr   zFailed to encode JPEG: )rr   imencoder\   IMWRITE_JPEG_QUALITYri  write_bytestobytes)r&  r   qualityr   encodeds        r   r   r     sS    ,,vus33K3K/Lg.VWKB4TF;<<W__&'r   c                \    t        |      }|r| d| n|}| d   d   dd|dd|dgd	gd
S )Nz

apir   userinput_image)rI   	image_url
input_text)rI   r  )rolecontent)r   r`   )image_data_url)rS   r   r%   density_notedata_urlr  s         r   r	  r	    sZ    j)H,8fXT,(fDw' *B)48
 r   c           
        t        |       }t        | d   j                  dd            }t        | d   j                  dd            }d}t	        |dz         D ]  }t        j                  | d   d   d	| d
d|t        | d   d               }	 |j                         }|j                  dk  r|c S d|j                   dt        j                  |d       }|j                  dvs||k\  r t#        |      |j                  j                  d      }	|	r,|	j                  ddd      j                         rt        |	      n|d|z  z  }
t        j                   |
       
 t#        |      # t        $ r d|j                  i}Y w xY w)Nr  max_retriesr   retry_base_secondsr  r   r	   endpointzBearer zapplication/json)AuthorizationzContent-Typetimeout_seconds)headersr   r  raw_texti  z
API error r   Fensure_ascii>             zretry-after.r   )read_api_keyr\   r   r>   r  requestspostr   r  r  status_codedumpsr  replaceisdigitr7   r:   ri  )rS   payloadapi_keyr  
retry_base
last_errorattemptresponser  retry_afterwait_secondss              r   r
  r
    s   6"GfUm''q9:Kve}(()=sCDJJq) !==5M*%(/y&9K]^u&789	
	/==?D #%K!("6"6!7r$**TX]:^9_`
'@@G{DZ z
"" &&**=9-8[=P=PQTVXZ[=\=d=d=fu[)lvz{  ~E  {E  mF

< '!( z
""  	/.D	/s   E..FFc                N   | d   j                  dd      }t        j                  j                  |d      j                         }|r|S t	        | d   j                  dd            }|j                         r |j                  d      j                         S t        d	| d
|       )Nr  key_envARK_API_KEYr   key_filezsecrets/byteplus.keyr   r   zAPI key not found. Set z or create )r   osenvironr   rf   rc   r1  ri  )rS   env_namekeyr  s       r   r  r    s    e}  M:H
**..2
&
,
,
.C

F5M--j:PQRH!!7!399;;
0
+hZP
QQr   c                p    t        j                  | j                               j                  d      }d| S )Nasciizdata:image/jpeg;base64,)base64	b64encoder  decode)r&  r  s     r   r  r    s1    t0188AG$WI..r   c                
   t        |       }|sy |j                         t        |      t        |      g}|D ]2  }|s	 t	        j
                  |      }t        |t              r|c S d c S  y # t        j                  $ r Y Kw xY wr(  )	extract_output_textr   strip_code_fenceextract_json_objectr   r   r  rE  r   )r   r  r}  r  r  s        r   r  r  $  s    |,D**, 0 68KD8QRJ 		ZZ	*F'56?4?  ## 		s   &A,&A,,BBc                z   t        | j                  d      t              r| d   j                         S g }| j                  dg       xs g D ]P  }|j                  dg       xs g D ]5  }|j                  d      }t        |t              s%|j	                  |       7 R dj                  |      j                         S )Noutput_textoutputr  r  r   )r  r   r#   r   r   r   )r  chunksr"   r  r  s        r   r  r  4  s    $((=)3/M"((**F2&," $xx	2.4" 	$G;;v&D$$d#	$$
 99V""$$r   c                    | j                         }|j                  d      r|j                  dd      d   }|j                  d      r|j	                  dd      d   }|j                         S )Nz```r   r	   r   )r   
startswithr  endswithrsplit)r  r   s     r   r  r  @  s]    JJLED!$R(~~eUA&q);;=r   c                n    | j                  d      }| j                  d      }|dk\  r||kD  r| ||dz    S dS )N{}r   r	   r   )findrfind)r  r  ends      r   r  r  I  s>    IIcNE
**S/C$)QJ3;4a FBFr   c                h    | j                  d       | j                  d       | j                          y )NaT  
        CREATE TABLE IF NOT EXISTS evaluations (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          created_at TEXT NOT NULL,
          input_video_path TEXT NOT NULL,
          video_sha256 TEXT NOT NULL,
          csv_path TEXT,
          csv_row_index INTEGER,
          metadata_json TEXT NOT NULL,
          frame_path TEXT NOT NULL,
          frame_metrics_json TEXT NOT NULL,
          request_json TEXT NOT NULL,
          response_json TEXT,
          assessment_json TEXT,
          error TEXT NOT NULL DEFAULT '',
          dry_run INTEGER NOT NULL DEFAULT 0
        )
        zTCREATE INDEX IF NOT EXISTS idx_evaluations_video_sha256 ON evaluations(video_sha256))executecommit)rQ   s    r   rk   rk   O  s+    LL	( 	LLghKKMr   c                L    | j                  d|f      j                         }|d uS )NzGSELECT 1 FROM evaluations WHERE video_sha256 = ? AND error = '' LIMIT 1)r#  fetchone)rQ   r$   rK  s      r   r   r   h  s0    
,,Q	 hj  d?r   c
                ^   | j                  dt        j                  t        j                        j                         t        |j                        ||j                  rt        |j                        nd |j                  t        j                  |j                  d      t        |      t        j                  |d      t        j                  t        |      d      |t        j                  |d      nd |t        j                  |d      nd ||	rdndf       | j                          y )Na3  
        INSERT INTO evaluations (
          created_at, input_video_path, video_sha256, csv_path, csv_row_index,
          metadata_json, frame_path, frame_metrics_json, request_json,
          response_json, assessment_json, error, dry_run
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        Fr  r	   r   )r#  r   r;   r   utc	isoformatr#   r   r   r   r   r  r   redact_request_imager$  r   s
             r   r  r  p  s     	LL	 LL&002 "&--CTNNJJt}}59
OJJ}59JJ+O<5Q<H<TDJJ|%8Z^:D:PDJJz6VZAa	
0 	KKMr   c                    t        j                  t        j                  | d            }|j                  dg       D ]3  }|j                  dg       D ]  }|j                  d      dk(  sd|d<    5 |S )	NFr  r`   r  rI   r  z[data-url-redacted]r  )r   r   r  r   )r  cloner"   r  s       r   r*  r*    sq    JJtzz'>?E		'2& =xx	2. 	=G{{6"m3'<$	== Lr   c                    | j                  d      j                         }|dz  }|dz  }|j                  dd      5 }|D ]6  }t        |      }|j	                  t        j                  |d      d	z          8 	 d d d        g d
}|j                  ddd      5 }	t        j                  |	|      }
|
j                          |D ]'  }t        |      }|
j                  t        |             ) 	 d d d        y # 1 sw Y   xY w# 1 sw Y   y xY w)Nz
        SELECT input_video_path, csv_path, csv_row_index, metadata_json, frame_path,
               frame_metrics_json, assessment_json
        FROM evaluations
        WHERE assessment_json IS NOT NULL AND error = ''
        ORDER BY id
        ztraining_dataset.jsonlztraining_dataset.csvwr   r   Fr  r   r   r%   storeslotbrix_rawhuman_soup_scorehuman_total_scorer   r   r   r   r   r   r   r5  r   r6  )
fieldnames)r#  fetchallr   dataset_recordwriter   r  rB  
DictWriterwriteheaderwriterowflatten_for_csv)rQ   rK   rows
jsonl_pathr   r   rK  recordfieldsr   writers              r   rw   rw     s   <<	 hj 	 66J22H	w	/ E3 	EC#C(FIIdjje<tCD	EE
F  
s["	= 5v6 	5C#C(FOOOF34	55 5+E E*5 5s   <C8AD8DDc                   | \  }}}}}}}t        j                  |      }t        j                  |      }	|||||t        j                  |      |	|j                  d      xs |j                  d      |j                  d      xs |j                  d      |j                  d      xs |j                  d      |j                  d      xs |j                  d      |j                  d	      xs |j                  d
      |j                  d      xs |j                  d      |j                  d      xs |j                  d      ddS )Nu	   提出者r0  u	   時間帯r1  u   スープ濃度r2  u   スープのみの点数soupu   濃度込みの点数rv  u   評価備考commentu   通知するブロック長	evaluator)r0  r1  r2  r3  r4  human_commentrE  )r   r   csv_row_indexr   r%   r&   r   labels)r   r   r   )
rK  r   r   rG  metadata_jsonr%   frame_metrics_jsonassessment_jsonr   r   s
             r   r7  r7    s   jmgJ-
DVXgzz-(HO,J & $67 \\+.G(,,w2GLL-Ef1E %67S8<<
;S (-G H `HLLY_L`!).E!F!_(,,W^J_%\\.9TX\\)=T!&CDaU`Ha
 r   c                   | d   }| d   }| d   | d   |j                  d      |j                  d      |j                  d      |j                  d      |j                  d	      |j                  d
      xs i j                  d      |j                  d      xs i j                  d      |j                  d      xs i j                  d      |j                  d      |j                  d      |j                  d      |j                  d      dS )Nr   rH  r   r%   r0  r1  r2  r3  r4  r   r   r   r   r   r   r   r   r   r/  r   )r?  r   rH  s      r   r<  r<    s    %JHF\*\*G$

6"JJz*"JJ'9:#ZZ(;<%>>*:;ArFFwO"}5;@@I)~~.BCIrNNwW(nn-AB#8!+0G!H>>), r   c                   t        j                         }| j                  d      5 t        fdd      D ]  }|j	                  |        	 d d d        |j                         S # 1 sw Y   |j                         S xY w)Nrbc                 &     j                  d      S )Ni   )rl  )r   s   r   <lambda>zfile_sha256.<locals>.<lambda>  s    "''+"6 r   r   )hashlibsha256r   iterupdate	hexdigest)r&  digestchunkr   s      @r   r   r     sq    ^^F	4 !B6< 	!EMM% 	!! ! s   &A&&A>__main__)r@   r\   )rR   list[InputItem]rS   r   r@   dict[str, dict[str, Any]])r   r   r@   rZ  )r   dict[str, Any] | Noner@   r#   )r   r[  rS   r   r@   ztuple[bool, str])r   r[  r   r#   r@   r   r(  )rQ   sqlite3.ConnectionrR   rY  rS   r   r   r#   rT   r   rU   r-  rV   r-  rW   z dict[str, dict[str, Any]] | Noner@   r\   )r&  r   r@   r   )r   r#   r@   r   )rS   r   r@   rA   )r2  r   r@   r#   )r{   r   r@   rY  )r{   r   rM  r#   rI  zdict[str, Path]r@   r   )r   r   rS   r   r@   r   )r   
np.ndarrayr@   zdict[str, float])r   r   rS   r   r@   ztuple[np.ndarray, int, float])r  r   r   r#   r@   r#   )r  r#   r   r   r  r#   r@   r>   )r  r#   r   r   r@   r>   )r&  r   r   r]  r  r\   r@   rA   )r   )
rS   r   r   r#   r%   r   r  r#   r@   r   )rS   r   r  r   r@   r   )rS   r   r@   r#   )r&  r   r@   r#   )r   r   r@   r[  )r  r   r@   r#   )r  r#   r@   r#   )rQ   r\  r@   rA   )rQ   r\  r$   r#   r@   r-  )rQ   r\  r"   r   r$   r#   r%   r   r&   r   r   r   r   r[  r   r[  r)   r#   rU   r-  r@   rA   )r  r   r@   r   )rQ   r\  rK   r   r@   rA   )rK  ztuple[Any, ...]r@   r   )r?  r   r@   r   )T__doc__
__future__r   rX   r  rB  rQ  r   r  r  r  ri   r  sysr  r/   r7   dataclassesr   r   r   pathlibr   typingr   rr   numpyro  r  r$  __file__rb   rM   r*  r  r   ra   rm   	with_namer[   r#  r@  r   r!   r(   r+   r}   ru   r   r   r   r   rv   r^   rf   r_   rl   rn   rD  r   r&   rj  r  r  r  r   r	  r
  r  r  r  r  r  r  rk   r   r  r*  rw   r7  r<  r   r   exitr   r   r   <module>rh     s   #   
   	     
    ! '   
    H~''*
 
zz~~)* 	'	()446>>@	7	7 
 8n$$&00?8n,,.889NO ;     " " "   " ""3l,^&D48 59]!
]!]! ]! 	]!
 ]! ]! ]! 2]! 	]!@"7
6)Zz*'T_0>("#8R/
 	%G2$
$
$ $ 	$
 "$ $$ ($ &$ $ $ 
$N'5T0* zCHHTV r   