"""填充 social_hotspots 下的 heat_score 字段
全部5条交由 DeepSeek 逐条判定热度（90-100）
用法: python3 fill_heat_score.py <json_path>"""

import sys, json, os, re, urllib.request
from datetime import datetime

DEEPSEEK_API_URL = 'https://api.deepseek.com/v1/chat/completions'


def get_deepseek_keys():
    """DeepSeek API key 候选列表（2026-09-17 修正：openclaw 里的 key 已失效）
    1) ~/.hermes/config.yaml providers.deepseek.api_key —— 实际生效的 key
    2) /root/.openclaw/openclaw.json —— 历史来源，可能已失效（脚本会依次尝试）
    """
    keys = []
    cfg_path = os.path.expanduser('~/.hermes/config.yaml')
    try:
        with open(cfg_path) as f:
            txt = f.read()
        m = re.search(r'^\s*api_key:\s*(sk-[A-Za-z0-9_\-]+)', txt, re.M)
        if m:
            keys.append(m.group(1))
    except Exception:
        pass
    try:
        with open('/root/.openclaw/openclaw.json') as f:
            k = json.load(f)['models']['providers']['deepseek']['apiKey']
        if k and k not in keys:
            keys.append(k)
    except Exception:
        pass
    return keys


def get_deepseek_key():
    ks = get_deepseek_keys()
    return ks[0] if ks else None


def call_deepseek_batch(items):
    """将全部5条标题发给DeepSeek，让AI逐条判定热度（90-100）"""
    keys = get_deepseek_keys()
    if not keys:
        return None

    # 构建条目列表文本
    lines = []
    for i, it in enumerate(items, 1):
        title = it.get('title', '')
        summary = it.get('summary', '')
        lines.append(f"[{i}] 标题：{title}")
        lines.append(f"    摘要：{summary}")
    items_text = "\n".join(lines)

    prompt = f'''你是一位汽车行业热点分析师。请为以下5条新闻逐条判定热度分数。

分数规则（90-100），充分利用全区间：
- 99-100：全网级现象级热点（如千万级阅读量、全民热议话题）
- 96-98：行业级重磅事件（标志性新车发布、重大战略合作、高阅读量热点）
- 93-95：有一定影响力的行业新闻
- 90-92：普通行业消息

注意各条标题中的阅读量/热榜数字（如"460.9万"、"153.4万"）可以辅助判断热度高低。
请严格按照以下JSON格式输出，只输出JSON数组，不要任何其他文字：
[
  {{"idx": 1, "score": 95}},
  {{"idx": 2, "score": 92}},
  ...
]

待评新闻：
{items_text}'''

    payload = json.dumps({
        "model": "deepseek-chat",
        "messages": [{"role": "user", "content": prompt}],
        "temperature": 0.3,
        "max_tokens": 500
    }).encode()

    for key in keys:
        req = urllib.request.Request(
            DEEPSEEK_API_URL, data=payload,
            headers={
                'Authorization': f'Bearer {key}',
                'Content-Type': 'application/json'
            }
        )
        try:
            resp = urllib.request.urlopen(req, timeout=30)
            result = json.loads(resp.read().decode('utf-8'))
            reply = result['choices'][0]['message']['content'].strip()

            # 提取JSON数组
            json_start = reply.find('[')
            json_end = reply.rfind(']') + 1
            if json_start >= 0 and json_end > json_start:
                reply_json = reply[json_start:json_end]
                scores = json.loads(reply_json)
                # 按idx映射
                score_map = {}
                for s in scores:
                    idx = s.get('idx')
                    score = s.get('score', 0)
                    score_map[idx] = max(90, min(100, int(score)))
                return score_map
        except Exception as e:
            print(f"  ⚠️ DeepSeek 请求失败(key {key[:10]}...): {type(e).__name__} {e}")
            continue
    return None


def main():
    if len(sys.argv) < 2:
        print("用法: python3 fill_heat_score.py <json_path>")
        sys.exit(1)

    path = sys.argv[1]
    if not os.path.exists(path):
        print(f"文件不存在: {path}")
        sys.exit(1)

    with open(path) as f:
        data = json.load(f)

    updated = 0
    item_list = []
    for item in data:
        if item.get('name') == 'social_hotspots':
            item_list = item.get('list', [])
            total = len(item_list)
            if total == 0:
                print("social_hotspots 列表为空")
                return

            print(f"[{datetime.now().strftime('%H:%M:%S')}] \U0001f916 DeepSeek逐条判定热度（共{total}条）...")
            for i, it in enumerate(item_list, 1):
                print(f"    [{i}] {it.get('title', '')[:40]}")

            score_map = call_deepseek_batch(item_list)

            if score_map:
                for i, it in enumerate(item_list, 1):
                    score = score_map.get(i)
                    if score:
                        it['heat_score'] = score
                        updated += 1
                        print(f"    \U0001f7e2 [{i}] DeepSeek: {score}")
                    else:
                        it['heat_score'] = 95
                        updated += 1
                        print(f"    \u26a0\ufe0f [{i}] 未返回，默认: 95")
            else:
                print(f"    \u26a0\ufe0f DeepSeek 无返回，全部默认95")
                for it in item_list:
                    it['heat_score'] = 95
                    updated += 1


            # 去重：所有分值两两之间不能相同
            orig_scores = [it['heat_score'] for it in item_list]
            seen_scores = set()
            for idx in range(len(orig_scores)):
                s = orig_scores[idx]
                while s in seen_scores and s > 85:
                    s -= 1
                seen_scores.add(s)
                item_list[idx]['heat_score'] = s
                if s != orig_scores[idx]:
                    print(f"    ⚠️ [{idx+1}] 同分调整: {orig_scores[idx]} → {s}")

            break

    # 清洗 social_hotspots 标题（移除尾部热度值、平台名等）
    for item in data:
        if item.get('name') == 'social_hotspots':
            for entry in item.get('list', []):
                old = entry.get('title', '')
                new = re.sub(r'\s+\d+(\.\d+)?\s*(万|亿)?\s*(热度)?$', '', old).strip()
                new = new.replace('IT 之家', '').replace('36Kr', '').replace('36氪', '').strip()
                new = re.sub(r'\s+$', '', new)
                if new != old:
                    entry['title'] = new

    with open(path, 'w') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

    scores = [it.get('heat_score') for it in item_list]
    print(f"[{datetime.now().strftime('%H:%M:%S')}] \u2705 更新 {updated} 条 heat_score")
    print(f"   首条: {scores[0]}  \u5c3e\u6761: {scores[-1]}  \u8303\u56f4: {min(scores)}-{max(scores)}")
    print(f"   趋势: {scores[:5]} ... {scores[-3:]}")


if __name__ == '__main__':
    main()
