# -*- coding: utf-8 -*-
"""scoring_prototype.py を人間スコア(686件)で検証。実行: python validate_prototype.py"""
import pandas as pd, numpy as np, re, os, json
import sys

HERE=os.path.dirname(os.path.abspath(__file__))
ROOT=os.path.dirname(HERE)
sys.path.insert(0, os.path.join(ROOT, "trackB_claude"))

from scoring_prototype import VisualFeatures, score_soup

df=pd.read_csv(os.path.join(ROOT,"data","raw_csv","base_export.csv"))
df=df.rename(columns={'テキスト':'dt','時間帯':'slot','スープ濃度':'brix_raw',
 'スープのみの点数':'soup','濃度込みの点数':'total','評価備考':'comment'}).dropna(subset=['dt'])
for c in ['soup','total']: df[c]=pd.to_numeric(df[c],errors='coerce')
df=df[df['soup'].notna()&df['total'].notna()&(df['total']<=100)].copy()
def pb(x):
    x=str(x)
    if '10' in x and ('～' in x or '〜' in x): return 9.5
    if '14' in x and ('～' in x or '〜' in x): return 14.5
    m=re.findall(r'\d+',x); return float(m[0]) if m else np.nan
df['brix']=df['brix_raw'].apply(pb); c=df['comment'].fillna('')
P={'good_emulsion':r'良い|◎|◯|完璧|状態良|good|Good|グッド|素晴','oil_excess':r'アブラ感[がは]?強|脂感|油.*強|重い|アブラスープ|アブラ先行',
'light':r'軽|アブラ感[がは]?(?:少|足|弱)','fire_strong':r'火[がは]?強|火力',
'separation':r'分離|乳化不|油層|白い|しろい|シャバ|白優先|乳化が進|乳化しすぎ','thin_look':r'濃度.*(?:低|薄|欲|足り)|薄い|軽そう',
'meat_collapse':r'ボロ|崩れ|くずれ','unusable':r'見え|見ず|見に|雲|くもって|湯気|煙|沸いて|投稿|撮影|タイミング',
'low_water':r'水位','gara_weak':r'ガラ感.*(?:増|足|頑張|出す)'}
import warnings; warnings.filterwarnings('ignore')
preds=[]
for _,r in df.iterrows():
    vf=VisualFeatures(**{k:float(bool(re.search(p,str(r['comment'])))) for k,p in P.items()})
    preds.append(score_soup(vf,r['brix'],r['slot']).total_score)  # bias=0
df['pred']=preds
mae=(df['pred']-df['total']).abs().mean()
r2=1-((df['total']-df['pred'])**2).sum()/((df['total']-df['total'].mean())**2).sum()
print(f"プロトタイプ vs 人間(濃度込み): N={len(df)}  MAE={mae:.1f}  R^2={r2:.3f}")
print(f"±10点以内={ (df['pred']-df['total']).abs().le(10).mean():.0%}  ±15点以内={(df['pred']-df['total']).abs().le(15).mean():.0%}")
print("※コメントは事後の指摘のみで全状態を網羅しないため過大評価寄り。CV特徴量導入で改善見込み。")
