# -*- coding: utf-8 -*-
"""黑板报文字逐行核对：把图里的中文抄回来，与文字稿做字符级比对"""
import base64, difflib, glob, json, os, re, sys
import requests

CFG = json.load(open('/data/www/files/LhyjdesignPro/config.json'))
API_KEY, BASE, VLM = CFG['api_key'], CFG['base_url'], CFG['models']['text_vision']

EXPECT = {
 'A_三联区_盾牌手机禁字': ['安全小卫士', '安全教育', '防诈四不', '远离毒品',
   '上下楼梯靠右行', '课间不追逐打闹', '过马路一停二看三通过', '不玩火 会报119',
   '不私自下水游泳', '被欺负要告诉老师', '不吃三无食品', '不跟陌生人走',
   '不轻信 免费送皮肤', '不透露 验证码密码', '不转账 要钱就挂断', '多核实 打96110',
   '被骗告诉爸妈老师', '毒品会伪装成糖果奶茶', '一次就可能上瘾', '不尝第一口',
   '不帮陌生人带东西', '发现涉毒打110'],
}
TITLES = {'A': '安全小卫士', 'B': '平安校园 从我做起', 'C': '三防小课堂'}
COMMON = ['安全教育', '防诈记心中', '远离毒品',
   '上下楼梯靠右行', '课间不追逐打闹', '过马路一停二看三通过', '不玩火 会报119',
   '不私自下水游泳', '被欺负要告诉老师', '不吃三无食品', '不跟陌生人走',
   '不轻信 免费送皮肤', '不透露 验证码密码', '不转账 要钱就挂断', '多核实 打96110',
   '被骗告诉爸妈老师', '毒品会伪装成糖果奶茶', '一次就可能上瘾', '不尝第一口',
   '不帮陌生人带东西', '发现涉毒打110']

ASK = ("请把这张图里所有中文逐行抄写出来，一行一条，按从上到下、从左到右的顺序。"
       "要求：只抄你真实看到的字，不要解释、不要补全、不要修正、不要翻译；"
       "看不清或你不确定的字，直接写一个 □ 代替，不要猜。最后不要加任何评论。")

NORM = re.compile(r'[\s，。、,.!！?？:：;；"“”\'‘’（）()·—\-…]+')


def norm(s):
    return NORM.sub('', s)


def read_text(path):
    b64 = base64.b64encode(open(path, 'rb').read()).decode()
    r = requests.post(f"{BASE}/chat/completions",
        headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
        json={"model": VLM, "messages": [{"role": "user", "content": [
            {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}},
            {"type": "text", "text": ASK}]}], "temperature": 0.0}, timeout=300)
    return r.json()['choices'][0]['message']['content']


B_FOOD = '不吃过期食品'
FOOD = '不吃三无食品'


def check(path, ver):
    common = [B_FOOD if (ver == 'B' and x == FOOD) else x for x in COMMON]
    expect = [TITLES[ver]] + common
    got_raw = read_text(path)
    got = [norm(l) for l in got_raw.splitlines() if l.strip()]
    pool = '\u0001'.join(got)
    ok, bad = [], []
    for e in expect:
        ne = norm(e)
        if ne in pool:
            ok.append(e)
            continue
        # 找最接近的一行，给出差异
        best, score = '', 0.0
        for g in got:
            s = difflib.SequenceMatcher(None, ne, g).ratio()
            if s > score:
                score, best = s, g
        diffs = ''
        if best:
            sm = difflib.SequenceMatcher(None, ne, best)
            diffs = ' | '.join(f'{ne[a:b]}→{best[c:d]}' for tag, a, b, c, d in sm.get_opcodes() if tag != 'equal')
        bad.append((e, best, round(score, 2), diffs))
    return ok, bad, got_raw


if __name__ == '__main__':
    files = sorted(glob.glob('/data/www/files/heibanbaoText/[ABC]_*.jpg'))
    if len(sys.argv) > 1:
        files = [f for f in files if sys.argv[1] in os.path.basename(f)]
    total_bad = 0
    for f in files:
        ver = os.path.basename(f)[0]
        ok, bad, raw = check(f, ver)
        print('=' * 74)
        print(f'【{os.path.basename(f)}】 命中 {len(ok)}/{len(ok)+len(bad)} 行')
        for e, best, sc, diffs in bad:
            print(f'  ✗ 应有「{e}」 读回「{best}」 相似度{sc} 差异: {diffs}')
        total_bad += len(bad)
        open(f'/tmp/read_{ver}.txt', 'w').write(raw)
    print('\n合计问题行:', total_bad)
