
    !_jG                         d Z ddlmZ ddlZddlmZ ddlZddlZ	dZ
dddd	e
d	iZd
ddddddde
d	iZdddddde
d	iZdddddddddddd	e
d	iZdZd#dZd$dZd%dZd&dZd'dZd(dZd)d Zd*d!Zd+d"Zy),u  ラーメンスープ評価 — 推論エンジン（利用システム / 自己完結・推論専用）

学習機能は持たない。AI開発システムが学習・保存した models/ を読み込み、
入力（濃度brix・時間帯slot・動画由来のLLM画像評価）から
スコア／グレード／要確認 を出力するだけのモジュール。

公開API:
    load_models(model_dir)         -> 学習済みモデル読込
    score_record(record, models)   -> 単件推論（dict in -> dict out）
    score_batch(raw_df, models)    -> バッチ推論（DataFrame in -> DataFrame out）
    grade(score)                   -> A/B/C/D グレード

入力レコードのキー（動画は上流で下記LLM評価項目に変換済みである前提）:
    brix_raw                : 濃度数値（実測 or 濃度推定AI）
    slot                    : 時間帯（開店前 / 17時〜19時 等）
    visual_density / water_level / oil_emulsification /
    boiling_heat_state / photo_quality / image_condition_score
                            : 動画→最良フレーム→LLM画像評価AI の出力
    readable（任意）        : 上流RF-DETRスープ可読性(bool)。Falseで「要確認」
    )annotationsN)Pathu   判定不可u   水位良好      ?u   水位不足        u!   油感と乳化の状態が良いu   乳化が進んでいるg333333?u   油感が強いg?u   乳化しすぎgffffff?   良いu   弱いu   強すぎるu   湯気が多いu	   白飛びu   暗いu   角度不良u   不良)human_total_scorehuman_soup_scorec                    t        j                  | t              }t        j                  |j                  dd      }d||dk\  <   d||dk\  <   d||d	k\  <   |S )
NdtypeDz<U1C   B<   AP   )npasarrayfloatfullshape)scorevaluesouts      ;/var/www/ramen.bs-engineer-server.com/app/scoring_engine.pygrader   5   sW    ZZU+F
''&,,5
1CC"C"C"J    c                    t        t        |             j                  }t        j                  d|      }|r|j                  d      S |S )Nz\d+r   )r   strstemresearchgroup)pathnamems      r   	_video_idr(   A   s:    D	?D
		&$A1771:$$r   c                X    	 t        |       S # t        $ r t        j                  cY S w xY w)N)r   	Exceptionr   nan)values    r   _to_densityr-   G   s)    U| vvs   
 ))c                    | j                  t              j                  t              j                  j	                         j                  |      j                  d      S )Nr   )fillnaUNASSESSABLEastyper    stripmap)seriesmappings     r   
_map_scorer6   N   sB    ==&--c266<<>BB7KRRSVWWr   c           
     	   | j                         } t        j                         }d| v r| d   j                  t              |d<   n*t        j
                  t        t        |                   |d<   | j                  d      |d<   | j                  d      |d<   | j                  dt        j
                  dgt        |       z              j                  d      j                  t              |d<   | j                  dt        j
                  dgt        |       z              j                  d      j                  t              |d<   t        j                  | j                  d      d	      |d
<   dD ]y  }| j                  |t        j
                  t        gt        |       z              j                  t              j                  t              j                  j                         ||<   { t        j                  | j                  d      d	      j                  d      |d<   |d   j                  t              |d<   |d   j!                         j                  t"              |d<   |d   t        k7  |d   t        k7  z  |d   t        k7  z  |d   t        k7  z  j                  t"              |d<   |d   dk7  |d   dk(  z  j                  t"              |d<   |d   |d
   z
  j%                         |d<   |d   |d
   z
  |d<   |d   |d
   k  j                  d      j                  t"              |d<   t'        |d   t(              |d<   t'        |d   t*              |d<   t'        |d   t,              |d<   t'        |d   t.              |d<   d |d   j                  d!      j1                  dd!      d"z  z
  j1                  dd#      |d$<   |d   j                  j3                  d%d&      j                  t"              |d'<   |d   j                  j3                  d(d)d*      j                  t"              |d+<   |d   d,k  j                  t"              |d-<   |g d   t        k(  j5                  d#.      j                  t"              |d/<   |S )0N
video_path	sample_id
frame_pathstoreunknownslotbrix_rawcoerce)errorsbrix)visual_densitywater_leveloil_emulsificationboiling_heat_statephoto_qualityimage_condition_scorer   rB   visual_density_numvisual_density_assessablerC   rD   rE   
assessablerF   r   retake_recommendeddensity_brix_abs_diffdensity_brix_signed_diffFdensity_below_brixwater_score	oil_scoreboiling_scorephoto_scorer      g      @   density_match_scoreu   開店)naslot_is_openingu   17|18|19|夜|夕T)regexrV   slot_is_evening   low_quality_flag)axisunassessable_axis_count)copypd	DataFramer3   r(   Seriesrangelengetr/   r1   r    
to_numericr0   r2   r-   notnaintabsr6   WATER_SCORE	OIL_SCOREBOILING_SCOREPHOTO_SCOREclipcontainssum)rawdfcols      r   preparers   U   s5   
((*C	Bsl+//	:;))E#c(O4;ww|,B|ww|,B|'''299i[3s8-C#DELLYW^^_bcBwKI;S+A!BCJJ9U\\]`aBvJswwz28DBvJm r''#ryy,#c()BCDKKLY``adeiiooq3r #%--8O0PYa"b"i"ijk"lB!"2377DB&()=&>&D&D&F&M&Mc&RB"#			-m,	."#|3	5 "#|3	5 fSk | "$O!4!@REUYZEZ [ccdghB#%&:#;bj#H"M"M"OB%'(<%=6
%JB!" "#7 82f: EMMeT[[\_`B"2m#4kBB} $8!99EB{O$R(<%=}MB"2o#6DB}!$+B(C(J(J1(M(R(RSTVW(X[^(^!_ e efgij kBvJNN33H3GNNsSBvJNN334FdW\3]ddehiB !89Q>FFsKB	j	ko{	{	!VVC[  ! Ir   c           	     ~    dd l }t        |       } t        D ci c]  }||j                  | | dz         c}S c c}w )Nr   z.pkl)joblibr   TARGETSload)	model_dirru   ts      r   load_modelsrz      s;    YI<CDqAv{{9!Dz122DDDs   :c                    i }|j                         D ]?  \  }}| |d   |d   z      }t        j                  |d   j                  |      dd      ||<   A |S )Nnumericcategoricalpipeliner   d   )itemsr   rm   predict)featmodelspredstargetbundleXs         r   _predict_scoresr      sh    E ,,. G	"VM%::;z 2 : :1 =q#FfG Lr   c           	     H   t        |       }t        ||      }d| j                  v r6| d   j                  d      j	                  t
              j                         }n$t        j                  t        |      t
              }|d   dk(  j                         }||z  }t        j                  |d   |d   |d   |d   ||d	   d
      }t        j                  |dd      |d<   t        j                  | dt        j                  | dd            |d<   t        D ]  }|dk(  rdnd}	||   j	                  t              }
t        j                  |t        j                  |
d      t        j                         ||	 d<   t        j                  |t#        |
      d      ||	 d<    |S )uc   バッチ推論。2段ゲート（① readable可読性 / ② assessable）で要確認を分岐。readableTr   rJ   rT   r9   r8   r:   rK   )r9   r8   r:   rJ   r   rK   scoredu	   要確認statusu^   readable=False（スープ表面が抽出/確認できない）→撮り直し/職人確認へuI   assessable=0（LLMが画像評価不能）→撮り直し/職人確認へ reasonr   totalsoup_score_grade)rs   r   columnsr/   r1   boolto_numpyr   onesrc   r_   r`   whererv   r   roundr+   r   )rp   r   r   r   r   llm_ok	scoreabler   r   rr   ss              r   score_batchr      s   3<DD&)ES[[ z?))$/66t<EEG773t9D1< A%//1F!I
,,+&<(<(<("#78 C HHY+>CMHH		s
&egijlCM  @#66gF&M  ' hhy"((1a."&&Ise6N hhy%(B?se6N	@
 Jr   c                   t        t        j                  | g      |      j                  d   j	                         }t        |j                               D ]1  \  }}t        |t              st        j                  |      s-d||<   3 |S )u%   単件推論。dict in -> dict out。r   N)r   r_   r`   ilocto_dictlistr   
isinstancer   r   isnan)recordr   reskvs        r   score_recordr      so    
bllF8,f
5
:
:1
=
E
E
GCSYY[! 1aBHHQKCF Jr   )returnz
np.ndarray)r%   objectr   r    )r,   r   r   r   )r4   	pd.Seriesr5   dictr   r   )rp   pd.DataFramer   r   )rx   z
str | Pathr   r   )r   r   r   r   r   r   )rp   r   r   r   r   r   )r   r   r   r   r   r   )__doc__
__future__r   r"   pathlibr   numpyr   pandasr_   r0   ri   rj   rk   rl   rv   r   r(   r-   r6   rs   rz   r   r   r    r   r   <module>r      s   ( # 	   
 sNCsK'.H$t.lC	 3$lTWXc$dKdND(Cs 4%X+bE<r   