File size: 3,684 Bytes
3865888
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
"""Local model registry (V6 phase_02): every entry is measured, never claimed.

Tasks: TEXT_MODEL | VISION_MODEL | IMAGE_MODEL | STT_MODEL | TTS_MODEL |
EMBEDDING_MODEL. A model is VERIFIED only after load + inference/encode
evidence exists (see diagnostics/v6/*_verification.json).
"""
import hashlib
import json
import os
from typing import Any, Dict, List, Optional

REGISTRY_PATH = os.path.join("models", "registry.json")

# Default acquisition candidates (pinned revisions where known).
DEFAULTS: List[Dict[str, Any]] = [
    {"id": "Qwen/Qwen3-0.6B-GGUF", "task": "TEXT_MODEL",
     "file": "Qwen3-0.6B-Q8_0.gguf", "revision": "main",
     "license": "Apache-2.0", "backend": "llama_cpp",
     "precision": "Q8_0", "memory_estimate_mb": 700},
    {"id": "sentence-transformers/all-MiniLM-L6-v2", "task": "EMBEDDING_MODEL",
     "revision": "main", "license": "Apache-2.0", "backend": "sentence_transformers",
     "precision": "fp32", "memory_estimate_mb": 120},
    {"id": "openai/whisper-small", "task": "STT_MODEL",
     "revision": "main", "license": "Apache-2.0", "backend": "transformers",
     "precision": "fp32", "memory_estimate_mb": 1000},
    {"id": "hexgrad/Kokoro-82M", "task": "TTS_MODEL",
     "revision": "main", "license": "Apache-2.0", "backend": "kokoro",
     "precision": "fp32", "memory_estimate_mb": 400},
    {"id": "Lykon/dreamshaper-8-lcm", "task": "IMAGE_MODEL",
     "revision": "main", "license": "CreativeML Open RAIL-M", "backend": "diffusers",
     "precision": "fp16-cpu-fp32", "memory_estimate_mb": 4500},
]


def _sha256(path: str) -> Optional[str]:
    if not os.path.exists(path):
        return None
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(65536), b""):
            h.update(chunk)
    return h.hexdigest()


def task_dir(task: str) -> str:
    return os.path.join("models", task.lower())


def scan_local() -> List[Dict[str, Any]]:
    """Inspect models/ and report per-file measured facts (size, sha)."""
    entries = []
    for cand in DEFAULTS:
        d = task_dir(cand["task"])
        local = None
        if os.path.isdir(d):
            cands = []
            for fn in sorted(os.listdir(d)):
                p = os.path.join(d, fn)
                if not os.path.isfile(p):
                    continue
                if cand.get("file") and fn != cand["file"]:
                    continue
                if fn.split(".")[-1] not in ("gguf", "safetensors", "bin", "onnx", "pt"):
                    continue
                cands.append((p, os.path.getsize(p)))
            if cands:
                # prefer safetensors, then largest weight file
                cands.sort(key=lambda t: (0 if t[0].endswith(".safetensors") else 1,
                                          -t[1]))
                p, size = cands[0]
                local = {"path": p, "size": size}
        entry = dict(cand)
        entry["local_path"] = local["path"] if local else None
        entry["file_size"] = local["size"] if local else None
        entry["sha256"] = _sha256(local["path"]) if local else None
        entry["present"] = local is not None
        entry["verified"] = False  # set True only by verification scripts
        entries.append(entry)
    return entries


def write_registry(verified: Optional[Dict[str, bool]] = None) -> List[Dict[str, Any]]:
    entries = scan_local()
    if verified:
        for e in entries:
            if e["id"] in verified:
                e["verified"] = bool(verified[e["id"]])
    os.makedirs(os.path.dirname(REGISTRY_PATH), exist_ok=True)
    json.dump(entries, open(REGISTRY_PATH, "w", encoding="utf-8"), indent=2)
    return entries