#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成 m4_event_rules.json：5类动态的可编程判定规则 + 正负例。

所有示例 URL 均来自本次实测可达的真实页面；「实测状态码」在构建时实时写入。
正例/负例的选取刻意包含「陷阱型负例」（正文含关键词但事实不成立），
用于检验判定规则是否只靠关键词匹配而误判。
"""
import json
import os
import urllib.error
import urllib.request
import time

OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "m4_event_rules.json")
UA = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
      "(KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36")


def probe(url, timeout=25):
    req = urllib.request.Request(url, headers={"User-Agent": UA,
                                               "Accept": "*/*",
                                               "Accept-Language": "zh-CN,zh;q=0.9"})
    try:
        with urllib.request.urlopen(req, timeout=timeout) as r:
            code = r.status
    except urllib.error.HTTPError as e:
        code = e.code
    except Exception as e:  # noqa: BLE001
        code = f"不可达({type(e).__name__})"
    time.sleep(1.2)
    return code


RULES = [
    {
        "动态类型": "新品发布",
        "判定要素": [
            "来源域名属于竞品官方站点或官方新闻稿页（白名单，非转载）",
            "出现具体产品名或货号/型号，而非泛指「新产品」",
            "含发布动作词：发布/推出/上市/上新/首发/launches/unveils/introduces/releases",
            "满足任一即可命中：①官方产品目录新增可索引条目；②新闻稿含发布动作词+产品名",
        ],
        "可匹配关键词": {
            "中文": ["发布", "推出", "上市", "首发", "上新", "全新", "正式面世", "新增货号"],
            "英文": ["launches", "unveils", "introduces", "releases", "new product", "now available"],
        },
        "需要的字段": ["来源URL", "标题", "发布日期", "产品名或货号", "品牌", "是否官方域名"],
        "正例": [
            {"URL": "https://bio.vazyme.com/product/236/",
             "标题": "诺唯赞产品详情页（示例货号236）",
             "为何命中": "官方产品站的产品详情页，含明确货号与产品名；属于「官方产品页新增货号」这一判定分支"},
            {"URL": "https://diagnostics.roche.com/global/en/news-listing/2026/roche-launches-newborn-screening-test-for-three-severe-genetic-conditions.html",
             "标题": "Roche launches newborn screening test for three severe genetic conditions",
             "为何命中": "官方新闻稿，标题含 launches + new test，具体产品名明确"},
        ],
        "负例": [
            {"URL": "https://www.transgen.com/news/1400.html",
             "标题": "【助力 Cell】全式金生物助力揭示飞蝗成灾的共生菌调控新范式",
             "为何不命中": "属科研应用/客户论文致谢类内容，无新品、无货号、无发布动作词"},
            {"URL": "https://www.vazyme.com/news/1/",
             "标题": "诺唯赞新闻分类列表页",
             "为何不命中": "是列表页而非单一产品发布事实，不应作为一条动态入库（需下钻到详情页）"},
        ],
    },
    {
        "动态类型": "战略合作",
        "判定要素": [
            "来源为官方站点或权威行业媒体（需二者之一）",
            "含合作动作词：战略合作/签署/签约/联合/共建/达成合作/partnership/signs agreement",
            "必须同时出现对方主体名（另一家企业全称）",
            "仅表达「寻求合作伙伴」「开放授权」而无已签署对手方的，判为不算命中",
        ],
        "可匹配关键词": {
            "中文": ["战略合作", "签署", "签约", "达成合作", "联合实验室", "共建", "合作协议"],
            "英文": ["strategic partnership", "signs agreement", "collaboration",
                     "joint development", "co-development", "distribution agreement"],
        },
        "需要的字段": ["来源URL", "标题", "发布日期", "我方主体", "对方主体名", "合作内容"],
        "正例": [
            {"URL": "https://www.yeasen.com/news/detail/2047926877305712640",
             "标题": "艾斯基因与翌圣生物达成战略合作，携手共拓表观多组学新格局",
             "为何命中": "官网新闻详情页，2026-04-25 签署战略合作协议，动作词+双方主体名齐备"},
            {"URL": "https://www.vbdata.cn/newsDetail/f38491b4a89111f1a8d400163e034e34",
             "标题": "华大智造和翌圣生物达成战略合作，共同推动长读长测序相关产品及解决方案的开发与应用",
             "为何命中": "权威行业媒体（动脉网），2026-09-02 签署战略合作协议，对方主体明确"},
        ],
        "负例": [
            {"URL": "https://en.faponbiotech.com/press-100",
             "标题": "Fapon Spotlights Localization-Focused One-Stop IVD Solutions at WHX Labs Dubai 2026",
             "为何不命中": "陷阱型负例：正文出现 collaboration models、partners 等词，且提到2500家合作客户，但仅为展会宣传，未签署任何具名对手方"},
            {"URL": "https://www.transgen.com/news/1399.html",
             "标题": "【助力 Cell】全式金生物助力揭示低温环境中植物叶绿体平衡能量生产与胁迫防御的分子机制",
             "为何不命中": "科研成果应用类内容，无签约、无对手方主体"},
        ],
    },
    {
        "动态类型": "经营数据",
        "判定要素": [
            "含经营类数值：营业收入/营收/净利润/毛利/同比/环比/出货量/产能",
            "数值须带单位与期间（年度或季度）",
            "来源须为官方披露平台或公司IR，不采信无出处的二手转述",
        ],
        "可匹配关键词": {
            "中文": ["营业收入", "营收", "净利润", "毛利", "同比增长", "环比", "出货量", "产能", "销售额"],
            "英文": ["revenue", "net profit", "gross margin", "year-over-year",
                     "sales", "operating results"],
        },
        "需要的字段": ["来源URL", "报告期间", "指标名", "数值", "单位", "同比/环比", "来源平台"],
        "正例": [
            {"URL": "http://static.cninfo.com.cn/finalpage/2026-08-28/1225517386.PDF",
             "标题": "诺唯赞 2026年半年度报告",
             "为何命中": "巨潮法定披露原件，含营业收入、净利润及同比数据，来源权威"},
            {"URL": "https://www.roche.com/investors/annualreport24",
             "标题": "Roche Annual Report（IR 年报入口）",
             "为何命中": "公司IR官方年报页，含分部营收等经营数值"},
        ],
        "负例": [
            {"URL": "http://static.cninfo.com.cn/finalpage/2026-09-25/1225581464.PDF",
             "标题": "诺唯赞关于持股5%以上股东减持股份计划完成暨减持结果公告",
             "为何不命中": "陷阱型负例：含大量数字（股数、比例、金额），但属股东减持，不含营收/利润等经营指标"},
            {"URL": "http://static.cninfo.com.cn/finalpage/2026-10-10/1225598991.PDF",
             "标题": "诺唯赞2026年第二次临时股东会决议公告",
             "为何不命中": "程序性公告，仅有议案表决结果，无经营类数值"},
        ],
    },
    {
        "动态类型": "财报季报年报半年报",
        "判定要素": [
            "披露平台出现标题含：年度报告/半年度报告/季度报告/年报/半年报/季报",
            "须为法定披露原件（巨潮PDF或交易所公告），非媒体转述",
            "按公告类别参数过滤时使用：年报 category_ndbg_szsh、半年报 category_bndbg_szsh",
        ],
        "可匹配关键词": {
            "中文": ["年度报告", "半年度报告", "季度报告", "年报", "半年报", "季报", "业绩预告", "业绩快报"],
            "英文": ["annual report", "half-year report", "quarterly report", "financial results"],
        },
        "需要的字段": ["来源URL", "公告标题", "披露日期", "报告期间", "披露平台", "股票代码"],
        "正例": [
            {"URL": "http://static.cninfo.com.cn/finalpage/2026-04-23/1225154804.PDF",
             "标题": "诺唯赞 2025年年度报告",
             "为何命中": "巨潮法定披露原件，标题严格匹配「年度报告」，2026-04-23披露"},
            {"URL": "http://static.cninfo.com.cn/finalpage/2026-08-28/1225517386.PDF",
             "标题": "诺唯赞 2026年半年度报告",
             "为何命中": "巨潮法定披露原件，标题严格匹配「半年度报告」，2026-08-28披露"},
        ],
        "负例": [
            {"URL": "http://static.cninfo.com.cn/finalpage/2026-10-10/1225599004.PDF",
             "标题": "北京市天元律师事务所关于诺唯赞2026年第二次临时股东会的法律意见",
             "为何不命中": "同批披露但属法律意见书，标题无任何报告期字样"},
            {"URL": "http://www.cninfo.com.cn/new/disclosure/stock?stockCode=688105",
             "标题": "巨潮资讯 个股公告列表页（688105）",
             "为何不命中": "是公告聚合列表页而非某一份财报原件，不构成单条财报动态"},
        ],
    },
    {
        "动态类型": "中标投标",
        "判定要素": [
            "来源为公共资源交易平台或招标网（非企业自述、非媒体转述）",
            "标题或正文含：中标公告/成交公告/中标（成交）结果公告/成交公示",
            "正文需出现中标（成交）供应商或采购单位名称",
            "URL路径含类型码时：0202=政府采购中标结果、2502=成交公告类、9001=其他交易公告",
        ],
        "可匹配关键词": {
            "中文": ["中标公告", "成交公告", "中标（成交）结果公告", "成交公示", "中标供应商", "成交供应商"],
            "英文": ["tender win", "awarded contract", "procurement award"],
        },
        "需要的字段": ["来源URL", "项目名称", "中标/成交单位", "公告日期", "金额", "采购单位", "平台名称"],
        "正例": [
            {"URL": "https://www.ggzy.gov.cn/information/deal/html/a/220000/0202/20261013/0022d88ec8b65c5b4d8b91f098471fec89fd.html",
             "标题": "白山市江源区人民法院数字法庭建设项目中标(成交)结果公告",
             "为何命中": "全国公共资源交易平台正式中标结果公告，类型码0202（政府采购），含项目编号与采购单位"},
            {"URL": "https://www.ggzy.gov.cn/information/deal/html/a/360000/2502/20261013/00367cbc9dac711b421bb57331870582285b.html",
             "标题": "峡江县2个标的林木采伐权转让（第一批第二次）项目交易成交公告",
             "为何命中": "全国公共资源交易平台成交公告，信息来源为江西省公共资源交易服务中心"},
        ],
        "负例": [
            {"URL": "https://bio.vazyme.com/product/236/",
             "标题": "诺唯赞产品详情页（示例货号236）",
             "为何不命中": "非交易平台来源，页面无中标/成交要素，属产品页"},
            {"URL": "https://diagnostics.roche.com/global/en/news-listing/2026/roche-ce-mark-apoe4.html",
             "标题": "Roche CE mark for APOE4 相关公告",
             "为何不命中": "属监管获批类新闻而非招投标，不含中标/成交要素"},
        ],
    },
]


def main():
    out = {
        "_元信息": {
            "生成日期": "2026-10-13",
            "说明": "每条示例URL均为本次实测可达的真实页面，「实测状态码」由构建时实时探测写入。",
            "负例设计": "刻意包含陷阱型负例（正文含关键词但事实不成立），用于检验规则是否会因纯关键词匹配而误判。",
            "边界": "全部为公开页面，未采集登录墙、付费或验证码内容。",
        },
        "规则": [],
    }
    for r in RULES:
        item = dict(r)
        for side in ("正例", "负例"):
            for ex in item[side]:
                print(f"  [M4] {side} {ex['URL']}")
                ex["实测状态码"] = probe(ex["URL"])
        out["规则"].append(item)
    with open(OUT, "w", encoding="utf-8") as f:
        json.dump(out, f, ensure_ascii=False, indent=2)
    print(f"完成，共 {len(out['规则'])} 条规则。")


if __name__ == "__main__":
    main()