Download armiger_inference.py from NorviTech/armiger: direct link, hf CLI and curl.
- Browser
- Download file 24.6 kB
-
https://huggingface.co/NorviTech/armiger/resolve/main/armiger_inference.py
- Command line
-
hf download hf://NorviTech/armiger/armiger_inference.py
-
curl -L -o armiger_inference.py https://huggingface.co/NorviTech/armiger/resolve/main/armiger_inference.py
24.6 kB
| """Standalone Armiger v2.1 / Armiger Ultra ONNX Featurizer & Inference Runtime (`armiger_inference.py`). | |
| Implements exact feature parity with the Armiger v2.1 training pipeline (`sift/prepare.py` + | |
| `enrich_side21_v2` 36-dim `stats` vector + `vocab.json` 4,096-extension lookup + CRC32 | |
| digit-folded path-word hashing) with zero external codebase dependencies beyond `numpy` | |
| and `onnxruntime`. | |
| All release-group and publisher token tables are stored as 8-byte BLAKE2b-64 hex digests | |
| so zero copyrighted or scene group strings appear in plaintext. | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| import json | |
| import math | |
| import os | |
| from pathlib import Path | |
| import re | |
| from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple | |
| import zlib | |
| try: | |
| import numpy as np | |
| except ImportError: | |
| np = None # type: ignore[assignment] | |
| NEURAL_HEAD_CLASSES: Dict[str, List[str]] = { | |
| "category": [ | |
| "movie", "tv_show", "xxx", "music", "comic", | |
| "game", "audiobook", "software", "ebook", "course", "unknown", | |
| ], | |
| "adult": ["non_adult", "adult"], | |
| "junk": ["clean", "junk"], | |
| "anime": ["non_anime", "anime"], | |
| "english_subs": ["no_eng_subs", "has_eng_subs", "unknown"], | |
| "lang": ["english", "non_english", "multi_or_unknown"], | |
| "owner_scope": ["allowed_type", "excluded"], | |
| "title_language": ["english_title", "non_english_title"], | |
| } | |
| _VOCAB_EXT_MAP: Optional[Dict[str, int]] = None | |
| _PREP_KIND_EXTS = { | |
| 0: frozenset("mkv mp4 avi ts m2ts mts vob wmv mpg mpeg mov flv rmvb rm m4v divx webm 3gp asf f4v ogv mxf m2v bik".split()), | |
| 1: frozenset("mp3 flac m4a m4b aac ogg opus wav wma ape alac aif aiff aifc ac3 dts mka mpc wv shn mid midi dff dsf".split()), | |
| 2: frozenset("zip rar 7z gz tgz bz2 xz zst lz lzma tar cab iso img dmg mdf mds nrg wim par par2 z".split()), | |
| 3: frozenset("exe msi apk ipa dll bat cmd sh vbs ps1 com scr jar deb rpm appimage run lnk".split()), | |
| 4: frozenset("jpg jpeg png gif webp bmp tif tiff avif jxl heic heif psd ai svg ico tga cr2 nef arw dng raw eps".split()), | |
| 5: frozenset("pdf epub mobi azw azw3 djvu djv fb2 txt rtf doc docx odt xls xlsx ppt pptx csv chm cbz cbr cb7 html htm mht mhtml md tex lit".split()), | |
| 6: frozenset("srt ass ssa sub idx vtt sup smi sbv ttml dfxp usf scc stl mks".split()), | |
| } | |
| _PREP_EXT_TO_KIND = {e: k for k, es in _PREP_KIND_EXTS.items() for e in es} | |
| _PREP_SPLIT_ARC_RE = re.compile(r"[rsz]\d{2,3}|\d{3}") | |
| _PREP_WORD_RE = re.compile(r"[^\W_]+") | |
| _PREP_DIGIT_RE = re.compile(r"\d") | |
| _PREP_SAMPLE_RE = re.compile(r"(?<![a-z])samples?(?![a-z])", re.IGNORECASE) | |
| # BLAKE2b-64 digest sets for release-tag disambiguation (zero plaintext group names) | |
| _SUB_ONLY_GRP_H = frozenset(['00d47045a1f1cd70', '0380c309e464115a', '0665f92d474878ff', '0f8f3809c6074d35', '1bc080c5d14b4eae', '1bf62e9b91086379', '22325081668ed28b', '26503f6826942362', '33b21e80d5dbfa62', '3e370e64b7539495', '4297edae7e25ba02', '4491be5b41a66832', '44e08227cfda9421', '4b956de9c462ee70', '519230ab4d0911f7', '581a8006ea8bd801', '65dfe6849ae4bb0d', '66ced9df20d8f558', '6a437c446b5778d6', '6cff013c3e752ac8', '6d3b6a62beedc878', '7bc52c5f863149cc', '867c636203d0524d', 'a7637cb5c531d8e9', 'b61d75b73d8e0c59', 'bed3322685febfa5', 'c603a601b7cb9d4c', 'd4eaba2bc7ef10d6', 'e20a8d50ddf1aa2e', 'e3fd326207da261c', 'fc94bcdf9fcb0164']) | |
| _DUAL_DUB_GRP_H = frozenset(['16bdcdbbbd493d9e', '17addcc669201a7b', '1cb486cd76cea8c6', '1cc2f6b1aa24d6f7', '236a71bfa2d47ca3', '24eee113ee4bddb0', '341556a463a4784b', '3658912d4f05f762', '6149de24f7784f27', '627dcb38527b8e4c', '6f09d409143a679c', '727c5e1f0f05ad51', '8b7c320e1df4bf3e', '9e64e0c8c213bf00', 'ac3675ff37aaf11e', 'b2c26515563660f5', 'bd672057ff15b985', 'd9621931df7eb664', 'e20db1736162ba0c', 'e2ee075c6b5545ad', 'eb446df9e0b5f645', 'f7a175e4cf1907fb', 'fe0fe2b14bb48506']) | |
| _GAME_GRP_H = frozenset(['03f22fe2a782da12', '0ae36a7939ac0be1', '1217fb0deda20335', '1c8f3166691fa2c6', '306372c75c8ceaa2', '32ba70bb6b5ae022', '4509f87fe97d6ed9', '4afe068be7dcf016', '6f7a14ce24f000a0', '7403ff2453c8a173', '7de6d237db23b5fa', '9641051915abdbb6', 'a491e84e39e2064e', 'a65a1816debe0915', 'aa89d2a9d5d18f01', 'aaac60aa2d75341b', 'bb98906accdd6e05', 'c200372b38fb6d26', 'c430ddffd526c993', 'cc81415c4d797870', 'e37a0da20d8d24ac', 'ed5d3b0f00026714', 'ee7b45399bcf968a', 'f0982ea7c2028c50', 'f1737c198253be9d', 'f766dbb74e38db04', 'fbe41c3bbd33ac19']) | |
| _SW_GRP_H = frozenset(['09455d377a262608', '0e30392b37df5495', '103064b4fea08f1c', '11a120607b793e4c', '158ba6de7392b368', '193a01c7e1bd0f62', '2199b8b3ff553486', '240843438078b817', '2508ee34b17c2225', '2a4eb6e114be0fab', '352836dac99f04b7', '391bd8a58914224a', '4185301675b9d80c', '4472c2744066912a', '4c4684b615a127b2', '522a470219d3a4f1', '5a6bb90382b6c1f6', '5ca7613c608a9ea5', '63f15e4687bfc135', '66a7555e70f0872e', '73d877e885d34562', '77c343b865d05e31', '780409423e866d09', '7e0a43f55a6714fd', '97409999bccb98f4', '996bd865c828c8f9', '9b60cdfff0e2ab1c', 'a330b94802e4b6c6', 'a9c5a9029bc6a596', 'b48e9326bf6316ef', 'c595d125bfd5ebe9', 'c8575232dac0347d', 'd64fa92611ac0eb2', 'e182e241e26cb119', 'e88087f130a6e7d6']) | |
| _BOOK_COMIC_GRP_H = frozenset(['0cad54552908fa65', '338c3fad71b18311', '5913147687b3c1e5', '712f82b4b85131a0', '7f5fc23af41380b2', '8d8b63a8bb00b7e4', '913bd80742a62e95', 'c00722c39b756d92', 'ecfebbed5476af20', 'ee2807f40b38f779', 'f89c7ccfb7b1338c', 'fdffac028227e18e', 'ffb2c2ead4c7ba7e']) | |
| _BENIGN_README_EXE_H = frozenset(['062b96e72d602b6e', '9a9f15179701c6ae', 'ddf05591355cf7e0']) | |
| _TOKEN_SCAN_RE = re.compile(r"[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*") | |
| _SIDE_ANIME_KW_RE = re.compile( | |
| r"(?i)\b(?:anime|ova|ona|donghua|aeni|bdrip[ ._-]*1080p[ ._-]*flac|dual[ ._-]*audio[ ._-]*\[?(?:jpn|jap))\b" | |
| ) | |
| _SIDE_VID_CLAIM_RE = re.compile( | |
| r"(?i)\b(?:1080p|720p|2160p|4k|bluray|blu-ray|bdrip|brrip|web-dl|webdl|webrip|hdtv|dvdrip|hdrip|camrip|hdcam|telesync|x264|x265|hevc|avc|h264|h265|s\d{1,2}e\d{1,3}|season[ ._-]*\d+|fc2-?ppv)\b|高清首发|更新至第" | |
| ) | |
| _SIDE_DECEPTIVE_SUB_STRIP_RE = re.compile( | |
| r"(?i)\b(?:eng(?:lish)?|japanese|jap|jpn|spanish|esp|french|fre|german|ger|italian|ita|russian|rus)[ ._-]+(?:hard|soft)?sub(?:s|bed|titled|titles)?\b|" | |
| r"\b(?:hard|soft)?sub(?:s|bed|titled|titles)?[ ._-]+(?:eng|english|esp|ja|jpn|fr|de|it|ru)\b|" | |
| r"\b(?:m[ ._-]?subs?|multi[ ._-]?subs?|esubs?|vostfr|hardsubs?)\b" | |
| ) | |
| _SIDE_ANIME_DUB_KW_RE = re.compile( | |
| r"(?i)\b(?:dual[ ._-]?audio|dubbed|eng(?:lish)?[ ._-]?dub(?:bed)?|multi[ ._-]?audio)\b" | |
| ) | |
| _SIDE_SW_APP_TITLE_RE = re.compile( | |
| r"(?i)\b(?:v?\d+\.\d+\.\d+|repack|portable|cracked|keygen|patch|patcher|activat(?:ed|or)|" | |
| r"multilingual|win(?:32|64)|x64|x86|macos|macosx|android|apk|pc[ ._-]?game|nintendo[ ._-]?switch|ps4|ps5|" | |
| r"emulator|driver|firmware|setup|installer|downloader|studio|vst3?|" | |
| r"pro[ ._-]+v?\d|ce[ ._-]+v?\d)\b" | |
| ) | |
| _SIDE_COURSE_RE = re.compile( | |
| r"(?i)\b(?:complete[ ._-]+course|video[ ._-]+course|masterclass|bootcamp|tutorial[ ._-]+series|certification[ ._-]+course|hands-on[ ._-]+training)\b" | |
| ) | |
| _SIDE_BOOK_COMIC_KW_RE = re.compile( | |
| r"(?i)\b(?:audiobooks?|audible|m4b|unabridged|narrated[ ._-]?by|ebook|e-book|epub|mobi|azw3|calibre)\b" | |
| ) | |
| _SIDE_VPN_TRAP_RE = re.compile( | |
| r"(?i)免费安装下载vpn|打不开网页|codec[ ._-]?(?:pack|setup|install)|player[ ._-]?setup|instructions?[ ._-]?to[ ._-]?watch" | |
| ) | |
| _SIDE_CJK_RE = re.compile(r"[\u4e00-\u9fff]") | |
| _SIDE_EP_ZIP_RE = re.compile( | |
| r"(?i)(?:^\[[^\[\]]{2,30}\].*?(?:\s-\s*\d{1,3}\b|\bS\d{1,2}E\d{1,3}\b).*?\b(?:1080p|720p|2160p|480p)\b|" | |
| r"\bS\d{1,2}E\d{1,3}\b.*?\b(?:1080p|720p|2160p|WEB-DL|WEBRip|BluRay|HDTV)\b)" | |
| ) | |
| _SIDE_BENIGN_ZIP_RE = re.compile( | |
| r"(?i)\b(?:batch|complete|season[ ._-]*\d+|s\d{1,2}[ ._-]*complete|e?\d{1,3}[ ._-]*[~-][ ._-]*e?\d{1,3}|시즌\s*\d+|완결|全集|合集|" | |
| r"ost|soundtrack|artbook|scans?|wallpapers?|fonts?|subs?|subtitles?)\b" | |
| ) | |
| def _h64(s: str) -> str: | |
| return hashlib.blake2b(s.strip().lower().encode("utf-8"), digest_size=8).hexdigest() | |
| def _extract_token_hashes(text: str) -> frozenset[str]: | |
| toks = [m.group(0).lower() for m in _TOKEN_SCAN_RE.finditer(text)] | |
| out = {_h64(t) for t in toks} | |
| for i in range(len(toks) - 1): | |
| out.add(_h64(f"{toks[i]} {toks[i + 1]}")) | |
| return frozenset(out) | |
| def _get_vocab_ext_map() -> Dict[str, int]: | |
| global _VOCAB_EXT_MAP | |
| if _VOCAB_EXT_MAP is not None: | |
| return _VOCAB_EXT_MAP | |
| vpath = Path(__file__).resolve().with_name("vocab.json") | |
| if not vpath.exists() and os.environ.get("ARMIGER_MODEL_DIR"): | |
| vpath = Path(os.environ["ARMIGER_MODEL_DIR"]) / "vocab.json" | |
| if vpath.exists(): | |
| data = json.loads(vpath.read_text(encoding="utf-8")) | |
| _VOCAB_EXT_MAP = {e: i + 1 for i, e in enumerate(data.get("exts", []))} | |
| else: | |
| _VOCAB_EXT_MAP = { | |
| "mp3": 2, "mp4": 3, "mkv": 4, "avi": 7, "srt": 10, "zip": 12, | |
| "rar": 17, "exe": 23, "flac": 24, "png": 25, "dll": 31, "m4b": 53, | |
| "epub": 81, "cbz": 96, "lnk": 150, "scr": 310, | |
| } | |
| return _VOCAB_EXT_MAP | |
| def _hash_ext(ext: str) -> int: | |
| if not ext: | |
| return 4096 | |
| return _get_vocab_ext_map().get(ext.lower(), 4096) | |
| def _hash_word(w: str) -> int: | |
| if not w: | |
| return 0 | |
| folded = _PREP_DIGIT_RE.sub("0", w.lower()) | |
| return (zlib.crc32(folded.encode("utf-8")) % 32767) + 1 | |
| def _log2_size_bucket(sz: int) -> int: | |
| return min(47, max(int(sz), 1).bit_length() - 1) | |
| def _prep_split_path(path: str) -> Tuple[str, str, str, int]: | |
| p_norm = path.replace("\\", "/") | |
| parent, _, base = p_norm.rpartition("/") | |
| i = base.rfind(".") | |
| ext = base[i + 1:].lower() if i > 0 else "" | |
| if len(ext) <= 10 and ext.isascii() and ext.isalnum(): | |
| stem = base[:i] | |
| else: | |
| ext, stem = "", base | |
| return parent.rpartition("/")[2], stem, ext, p_norm.count("/") | |
| def _prep_path_words(parent: str, stem: str) -> List[int]: | |
| p_words = [_hash_word(w) for w in _PREP_WORD_RE.findall(parent.lower())][-2:] if parent else [] | |
| s_words = [_hash_word(w) for w in _PREP_WORD_RE.findall(stem.lower())][-(4 - len(p_words)):] | |
| res = p_words + s_words | |
| while len(res) < 4: | |
| res.append(0) | |
| return res[:4] | |
| def encode_torrent_features( | |
| row: Mapping[str, Any], | |
| max_name_len: int = 256, | |
| max_files: int = 64, | |
| ) -> Dict[str, Any]: | |
| """Encode a torrent metadata dictionary into the exact ONNX tensor inputs for Armiger v2.1.""" | |
| name = str(row.get("name") or row.get("title") or "") | |
| b_name = name.encode("utf-8", "replace") | |
| if len(b_name) > max_name_len: | |
| b_name = b_name[:max_name_len].decode("utf-8", "ignore").encode("utf-8") | |
| raw_bytes = list(b_name) if b_name else [32] | |
| raw_files = row.get("files") or [] | |
| total_size = int(row.get("size") or 0) | |
| items: List[Tuple[str, int]] = [] | |
| for f in raw_files[:max_files]: | |
| if isinstance(f, Mapping): | |
| p = str(f.get("path") or f.get("p") or f.get("name") or "") | |
| sz = int(f.get("size") or f.get("s") or 0) | |
| else: | |
| p = str(f or "") | |
| sz = 0 | |
| if p: | |
| items.append((p, sz)) | |
| if not items and (row.get("ext") or row.get("extension") or "." in name): | |
| items.append((name, total_size)) | |
| ext_map = _get_vocab_ext_map() | |
| exts: List[int] = [] | |
| sizes: List[int] = [] | |
| depths: List[int] = [] | |
| words_list: List[List[int]] = [] | |
| f_exts_str: List[str] = [] | |
| kbytes = [0.0] * 8 | |
| kcount = [0] * 8 | |
| has_sample = False | |
| for path, sz in items: | |
| parent, stem, ext, depth = _prep_split_path(path) | |
| f_exts_str.append(ext) | |
| exts.append(ext_map.get(ext, 4096)) | |
| sizes.append(_log2_size_bucket(sz)) | |
| depths.append(min(depth, 7)) | |
| words_list.append(_prep_path_words(parent, stem)) | |
| k = _PREP_EXT_TO_KIND.get(ext) | |
| if k is None: | |
| k = 2 if _PREP_SPLIT_ARC_RE.fullmatch(ext) else 7 | |
| kbytes[k] += max(sz, 0) | |
| kcount[k] += 1 | |
| has_sample = has_sample or (_PREP_SAMPLE_RE.search(path) is not None) | |
| tot_k = sum(kbytes) | |
| weights = kbytes if tot_k > 0 else [float(c) for c in kcount] | |
| wsum = sum(weights) | |
| count = max(int(row.get("file_count") or 0), len(items)) | |
| biggest = max((max(s, 0) for _, s in items), default=0) | |
| max_share = (biggest / tot_k if tot_k > 0 else (1.0 / len(items) if items else 0.0)) | |
| base_stats = [ | |
| math.log1p(max(count, 0)), | |
| math.log1p(max(total_size if total_size > 0 else int(tot_k), 0)), | |
| ] | |
| base_stats += [w / wsum if wsum > 0 else 0.0 for w in weights] | |
| base_stats += [max_share, float(has_sample)] | |
| side = [0.0] * 24 | |
| n_f = float(max(1, len(items))) | |
| m_grp = re.match(r"^\[([^\[\]]{2,30})\]", name) | |
| grp_lc = m_grp.group(1).strip().lower() if m_grp else "" | |
| grp_h = _h64(grp_lc) if grp_lc else "" | |
| title_tok_h = _extract_token_hashes(name) | |
| has_sub_grp = (grp_h in _SUB_ONLY_GRP_H) or bool(title_tok_h & _SUB_ONLY_GRP_H) | |
| has_dub_grp = (grp_h in _DUAL_DUB_GRP_H) or bool(title_tok_h & _DUAL_DUB_GRP_H) | |
| has_game_grp = bool(title_tok_h & _GAME_GRP_H) | |
| has_sw_grp = bool(title_tok_h & _SW_GRP_H) | |
| has_book_grp = bool(title_tok_h & _BOOK_COMIC_GRP_H) | |
| if items: | |
| ebk_set = {"epub", "mobi", "azw3", "azw", "djvu", "fb2", "lit", "iba"} | |
| pdf_set = {"pdf"} | |
| m4b_set = {"m4b", "aa", "aax"} | |
| com_set = {"cbz", "cbr", "cb7", "cbt"} | |
| con_set = {"nsp", "xci", "xcz", "nsz", "wbfs", "rvz", "gcz", "cia", "3ds", "vpk", "ps4", "fpkg"} | |
| app_set = {"dmg", "pkg", "apk", "ipa", "deb", "rpm", "appimage"} | |
| exe_dll_set = {"exe", "msi", "bat", "cmd", "sh", "com", "dll"} | |
| iso_set = {"iso", "bin", "cue", "mdf", "mds", "nrg", "img"} | |
| arc_set = {"rar", "zip", "7z", "tar", "gz", "xz", "bz2", "001"} | |
| htm_set = {"html", "htm", "url", "mht", "torrent"} | |
| scr_set = {"scr", "lnk", "vbs", "hta", "pif", "ps1", "wsf", "reg"} | |
| vid_set = {"mkv", "mp4", "avi", "ts", "m2ts", "wmv", "mov", "webm", "flv", "mpg", "mpeg", "m4v", "vob", "ogv", "rmvb", "3gp", "asf", "divx"} | |
| bd_game_benign = {"vcdiff", "apk", "bdmv", "clpi", "mpls", "ifo", "bup", "vob", "npa", "vpk", "pck", "umd", "pak", "xp3", "rgss3a", "wolf", "nsp", "xci", "wbfs", "rpa", "rpy", "rpyb"} | |
| side[0] = sum(1 for e in f_exts_str if e in ebk_set) / n_f | |
| side[1] = sum(1 for e in f_exts_str if e in pdf_set) / n_f | |
| side[2] = sum(1 for e in f_exts_str if e in m4b_set) / n_f | |
| side[3] = sum(1 for e in f_exts_str if e in com_set) / n_f | |
| side[4] = sum(1 for e in f_exts_str if e in con_set) / n_f | |
| side[5] = sum(1 for e in f_exts_str if e in app_set) / n_f | |
| vc = bool(_SIDE_VID_CLAIM_RE.search(name) or _SIDE_ANIME_KW_RE.search(name) or has_sub_grp or has_dub_grp) | |
| has_renpy_structure = not vc and any( | |
| p_i.replace("\\", "/").lower().endswith((".rpa", ".rpy", ".rpyb")) | |
| or "/renpy/" in "/" + p_i.replace("\\", "/").lower() | |
| for p_i, _ in items | |
| ) | |
| renpy_say_re = re.compile(r"(?i)(?:^|/)lib/(?:py\d+-)?windows-[^/]+/say\.vbs$") | |
| n_real_exec_dll = 0 | |
| has_real_exe = False | |
| has_dll = False | |
| has_scr_trap = False | |
| has_oversized_lnk = False | |
| has_root_launcher = False | |
| has_unconditional_trap_ext = False | |
| has_any_scr_ext = False | |
| vid_depths: List[int] = [] | |
| for (p_i, _), e_str, s_b, d_i, w_i in zip(items, f_exts_str, sizes, depths, words_list): | |
| p_posix = p_i.replace("\\", "/") | |
| if has_renpy_structure and renpy_say_re.search(p_posix): | |
| continue | |
| if e_str in scr_set: | |
| has_any_scr_ext = True | |
| if e_str in {"scr", "vbs", "vbe", "hta", "pif", "wsf", "wsh", "cpl", "one"}: | |
| has_unconditional_trap_ext = True | |
| p_tok_h = _extract_token_hashes(p_i) | |
| is_benign_stub = (e_str == "exe") and (s_b < 15 or 16570 in w_i or bool(p_tok_h & _BENIGN_README_EXE_H)) | |
| if e_str in exe_dll_set and not is_benign_stub: | |
| n_real_exec_dll += 1 | |
| if e_str == "exe" and not is_benign_stub and s_b >= 15: | |
| has_real_exe = True | |
| if d_i == 0: | |
| has_root_launcher = True | |
| elif e_str == "dll": | |
| has_dll = True | |
| if e_str in {"scr", "lnk", "hta", "vbs", "pif", "ps1", "wsf", "cmd", "com"} and s_b >= 12: | |
| has_scr_trap = True | |
| if d_i == 0: | |
| has_root_launcher = True | |
| if e_str == "lnk" and s_b >= 15: | |
| has_oversized_lnk = True | |
| if e_str in vid_set: | |
| vid_depths.append(d_i) | |
| side[6] = n_real_exec_dll / n_f | |
| side[7] = sum(1 for e in f_exts_str if e in iso_set) / n_f | |
| side[8] = sum(1 for e in f_exts_str if e in arc_set) / n_f | |
| side[9] = sum(1 for e in f_exts_str if e in htm_set) / n_f | |
| side[10] = 1.0 if has_any_scr_ext else 0.0 | |
| is_sw_or_game = bool( | |
| has_game_grp | |
| or has_sw_grp | |
| or (not vc and _SIDE_SW_APP_TITLE_RE.search(name)) | |
| or any(e in bd_game_benign for e in f_exts_str) | |
| ) | |
| vid_share = base_stats[2] | |
| flagged = has_unconditional_trap_ext | |
| if not is_sw_or_game: | |
| if vc and has_real_exe and has_dll: | |
| flagged = True | |
| elif vc and len(vid_depths) >= 1 and (has_real_exe or has_root_launcher or has_scr_trap): | |
| flagged = True | |
| elif (vc or len(vid_depths) > 0) and has_oversized_lnk: | |
| flagged = True | |
| elif vc and vid_share == 0.0 and (has_real_exe or has_scr_trap): | |
| flagged = True | |
| elif len(items) <= 2 and any(e in ("zip", "zipx", "rar", "7z") for e in f_exts_str) and vid_share == 0.0: | |
| if _SIDE_EP_ZIP_RE.search(name) and not _SIDE_BENIGN_ZIP_RE.search(name): | |
| flagged = True | |
| elif len(items) <= 2 and any(e in ("iso", "img", "vhd", "vhdx", "udf") for e in f_exts_str) and vid_share == 0.0: | |
| name_stem = re.sub(r"\.(?:iso|img|vhd|vhdx|udf|dmg)$", "", name.strip(), flags=re.IGNORECASE) | |
| if _SIDE_EP_ZIP_RE.search(name_stem) and not re.search(r"(?i)\b(?:dvd|bd25|bd50|remux|untouched|pal|ntsc|iso)\b", name_stem): | |
| flagged = True | |
| if flagged or _SIDE_VPN_TRAP_RE.search(name) or (vc and vid_share == 0.0 and (side[6] > 0 or side[9] > 0 or side[10] > 0)): | |
| side[11] = 1.0 | |
| if vc and vid_share > 0 and 0 < base_stats[1] < 14.22: | |
| side[12] = 1.0 | |
| ag = bool(_SIDE_ANIME_KW_RE.search(name)) or has_sub_grp or has_dub_grp | |
| if ag: | |
| side[15] = 1.0 | |
| clean_audio_name = _SIDE_DECEPTIVE_SUB_STRIP_RE.sub(" ", name) | |
| clean_tok_h = _extract_token_hashes(clean_audio_name) | |
| ad = bool(_SIDE_ANIME_DUB_KW_RE.search(clean_audio_name)) or (grp_h in _DUAL_DUB_GRP_H) or bool(clean_tok_h & _DUAL_DUB_GRP_H) | |
| if ad: | |
| side[16] = 1.0 | |
| if (grp_h in _SUB_ONLY_GRP_H) and not ad: | |
| side[14] = 1.0 | |
| if has_game_grp: | |
| side[17] = 1.0 | |
| if has_sw_grp and not _SIDE_CJK_RE.search(name): | |
| side[18] = 1.0 | |
| if _SIDE_COURSE_RE.search(name) and not ag: | |
| side[19] = 1.0 | |
| if _SIDE_BOOK_COMIC_KW_RE.search(name) or has_book_grp: | |
| side[20] = 1.0 | |
| lang_str = (row.get("language") or "").strip().lower() | |
| if lang_str in ("ja", "ru", "fr", "es", "de", "it", "pt", "zh", "ko", "hi", "pl", "nl", "tr", "ar") or _SIDE_CJK_RE.search(name) or ((grp_h in _SUB_ONLY_GRP_H) and not ad): | |
| side[22] = 1.0 | |
| elif lang_str in ("en", "eng", "english") or ad: | |
| side[21] = 1.0 | |
| else: | |
| side[23] = 1.0 | |
| return { | |
| "name_bytes": raw_bytes, | |
| "ext": exts if exts else [0], | |
| "size": sizes if sizes else [0], | |
| "depth": depths if depths else [0], | |
| "words": words_list if words_list else [[0, 0, 0, 0]], | |
| "stats": base_stats + side, | |
| } | |
| def build_onnx_batch_inputs( | |
| rows: Sequence[Mapping[str, Any]], | |
| max_name_len: int = 256, | |
| max_files: int = 64, | |
| ) -> Dict[str, np.ndarray]: | |
| """Collate a sequence of torrent dicts into padded NumPy arrays for ONNX Runtime.""" | |
| encoded = [encode_torrent_features(r, max_name_len=max_name_len, max_files=max_files) for r in rows] | |
| bsz = len(encoded) | |
| max_l = max(len(e["name_bytes"]) for e in encoded) | |
| max_f = max(len(e["ext"]) for e in encoded) | |
| name_b = np.zeros((bsz, max_l), dtype=np.int64) | |
| name_l = np.zeros((bsz,), dtype=np.int64) | |
| ext_t = np.zeros((bsz, max_f), dtype=np.int32) | |
| size_t = np.zeros((bsz, max_f), dtype=np.int64) | |
| depth_t = np.zeros((bsz, max_f), dtype=np.int64) | |
| words_t = np.zeros((bsz, max_f, 4), dtype=np.int32) | |
| stats_t = np.zeros((bsz, 36), dtype=np.float32) | |
| for i, e in enumerate(encoded): | |
| lb = len(e["name_bytes"]) | |
| lf = len(e["ext"]) | |
| name_b[i, :lb] = e["name_bytes"] | |
| name_l[i] = lb | |
| ext_t[i, :lf] = e["ext"] | |
| size_t[i, :lf] = e["size"] | |
| depth_t[i, :lf] = e["depth"] | |
| words_t[i, :lf, :] = e["words"] | |
| stats_t[i, :] = e["stats"] | |
| return { | |
| "name_bytes": name_b, | |
| "name_len": name_l, | |
| "ext": ext_t, | |
| "size": size_t, | |
| "depth": depth_t, | |
| "words": words_t, | |
| "stats": stats_t, | |
| } | |
| def _softmax(logits: np.ndarray) -> np.ndarray: | |
| shifted = logits - np.max(logits, axis=-1, keepdims=True) | |
| exps = np.exp(shifted) | |
| return exps / np.sum(exps, axis=-1, keepdims=True) | |
| class ArmigerStandaloneONNX: | |
| """Self-contained ONNX Runtime classifier for `NorviTech/armiger` and `NorviTech/armiger-ultra`.""" | |
| def __init__( | |
| self, | |
| onnx_path: Optional[str | Path] = None, | |
| vocab_path: Optional[str | Path] = None, | |
| calibration_path: Optional[str | Path] = None, | |
| ) -> None: | |
| import onnxruntime as ort | |
| base = Path(__file__).resolve().parent | |
| if onnx_path is None: | |
| for cand in ("armiger.onnx", "armiger.int8.onnx", "armiger_ultra.fp32.onnx"): | |
| if (base / cand).exists(): | |
| onnx_path = base / cand | |
| break | |
| if onnx_path is None: | |
| raise FileNotFoundError("Could not find armiger.onnx or armiger_ultra.fp32.onnx") | |
| self.onnx_path = Path(onnx_path) | |
| self.vocab_path = Path(vocab_path) if vocab_path else (base / "vocab.json") | |
| self.calibration_path = Path(calibration_path) if calibration_path else (base / "calibration.json") | |
| self.session = ort.InferenceSession(str(self.onnx_path), providers=["CPUExecutionProvider"]) | |
| self.head_names = [o.name for o in self.session.get_outputs()] | |
| def predict_batch(self, rows: Sequence[Mapping[str, Any]]) -> List[Dict[str, Any]]: | |
| feed = build_onnx_batch_inputs(rows) | |
| raw_outs = self.session.run(self.head_names, feed) | |
| logits_by_head = dict(zip(self.head_names, raw_outs)) | |
| results: List[Dict[str, Any]] = [] | |
| for i in range(len(rows)): | |
| item_res: Dict[str, Any] = {"heads": {}, "probabilities": {}} | |
| for h, arr in logits_by_head.items(): | |
| vec = arr[i].astype(np.float64) | |
| probs = _softmax(vec) | |
| classes = NEURAL_HEAD_CLASSES.get(h, [str(k) for k in range(len(probs))]) | |
| idx = int(np.argmax(probs)) | |
| item_res["heads"][h] = classes[idx] if idx < len(classes) else str(idx) | |
| item_res["probabilities"][h] = { | |
| classes[k]: round(float(probs[k]), 6) for k in range(min(len(classes), len(probs))) | |
| } | |
| item_res["category"] = item_res["heads"].get("category", "unknown") | |
| p_junk = item_res["probabilities"].get("junk", {}).get("junk", 0.0) | |
| p_adult = item_res["probabilities"].get("adult", {}).get("adult", 0.0) | |
| p_excl = item_res["probabilities"].get("owner_scope", {}).get("excluded", 0.0) | |
| item_res["p_junk"] = p_junk | |
| item_res["mondrian_gates"] = { | |
| "adult_flagged": bool(p_adult >= 0.5451), | |
| "junk_flagged": bool(p_junk >= 0.1010), | |
| "scope_excluded": bool(p_excl >= 0.4770), | |
| "passed_all": bool(p_adult < 0.5451 and p_junk < 0.1010 and p_excl < 0.4770), | |
| } | |
| results.append(item_res) | |
| return results | |
| def predict(self, row: Mapping[str, Any]) -> Dict[str, Any]: | |
| return self.predict_batch([row])[0] | |
| ArmigerONNXClassifier = ArmigerStandaloneONNX | |