Spaces:
Sleeping
Sleeping
Update commercial_stats.py
Browse files- commercial_stats.py +35 -14
commercial_stats.py
CHANGED
|
@@ -23,11 +23,21 @@ HTTP_WORKERS = int(os.environ.get("COMM_HTTP_WORKERS", "10"))
|
|
| 23 |
BATCH_SIZE = int(os.environ.get("COMM_SCAN_BATCH", "50")) # reduced from 150
|
| 24 |
SAMPLE_CAP = 200
|
| 25 |
|
| 26 |
-
# ---------------- helpers ----------------
|
| 27 |
_TAG_RE = re.compile(r"<[^>]+>")
|
| 28 |
def _html_to_text(s: str) -> str:
|
| 29 |
return _TAG_RE.sub(" ", s).strip()
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
# ---------------- in-memory state ----------------
|
| 32 |
_state_lock = threading.Lock()
|
| 33 |
_state: Dict[str, Any] = {
|
|
@@ -67,7 +77,6 @@ def _snapshot() -> Dict[str, Any]:
|
|
| 67 |
done = _state["models_seen"]
|
| 68 |
progress_models = (100.0 * done / tot) if tot else 0.0
|
| 69 |
|
| 70 |
-
# Copy shallow
|
| 71 |
snap = {
|
| 72 |
"phase": _state["phase"],
|
| 73 |
"started": _state["started"],
|
|
@@ -131,8 +140,13 @@ def _run_scancode_dir(input_dir: str, output_json: str) -> Dict[str, List[str]]:
|
|
| 131 |
|
| 132 |
def _fetch_url(session: requests.Session, url: str) -> Optional[str]:
|
| 133 |
try:
|
| 134 |
-
r = session.get(
|
| 135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
return r.text
|
| 137 |
except Exception:
|
| 138 |
pass
|
|
@@ -176,7 +190,7 @@ def _scan_thread():
|
|
| 176 |
for i, m in enumerate(models):
|
| 177 |
mid = f"{m.get('owner') or m.get('username') or ''}/{m.get('name') or ''}".strip("/")
|
| 178 |
label, url = license_label_and_url(m)
|
| 179 |
-
records.append({"mid": mid, "label": label, "url": url, "spdx": None})
|
| 180 |
|
| 181 |
if url:
|
| 182 |
url_to_models.setdefault(url, []).append(i)
|
|
@@ -209,7 +223,7 @@ def _scan_thread():
|
|
| 209 |
|
| 210 |
# Assign unknowns for fetch failures; prepare text dedupe
|
| 211 |
hash_to_urls: Dict[str, List[str]] = {}
|
| 212 |
-
text_hash_to_text: Dict[str, str] = {}
|
| 213 |
for u, idxs in url_to_models.items():
|
| 214 |
text = url_to_text.get(u)
|
| 215 |
if not text:
|
|
@@ -226,15 +240,23 @@ def _scan_thread():
|
|
| 226 |
if h not in text_hash_to_text:
|
| 227 |
text_hash_to_text[h] = text
|
| 228 |
|
| 229 |
-
#
|
| 230 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
with _state_lock:
|
| 232 |
_state["phase"] = "scan"
|
| 233 |
_state["texts_total"] = len(hashes)
|
| 234 |
|
| 235 |
-
hash_to_spdx: Dict[str, List[str]] = {}
|
| 236 |
if hashes:
|
| 237 |
-
# process in chunks to limit runtime per scancode invocation
|
| 238 |
for i in range(0, len(hashes), BATCH_SIZE):
|
| 239 |
chunk = hashes[i:i+BATCH_SIZE]
|
| 240 |
with tempfile.TemporaryDirectory() as td:
|
|
@@ -245,7 +267,7 @@ def _scan_thread():
|
|
| 245 |
# write each text as file "<hash>.txt"
|
| 246 |
for h in chunk:
|
| 247 |
with open(os.path.join(in_dir, f"{h}.txt"), "w", encoding="utf-8") as f:
|
| 248 |
-
f.write(_html_to_text(text_hash_to_text[h]))
|
| 249 |
|
| 250 |
# run scancode once over the directory
|
| 251 |
by_file = _run_scancode_dir(in_dir, out_json)
|
|
@@ -253,8 +275,8 @@ def _scan_thread():
|
|
| 253 |
# collect results
|
| 254 |
for relpath, spdx_ids in by_file.items():
|
| 255 |
base = os.path.basename(relpath)
|
| 256 |
-
|
| 257 |
-
hash_to_spdx[
|
| 258 |
|
| 259 |
with _state_lock:
|
| 260 |
_state["texts_scanned"] += len(chunk)
|
|
@@ -271,7 +293,6 @@ def _scan_thread():
|
|
| 271 |
spdx_ids = hash_to_spdx.get(h, [])
|
| 272 |
|
| 273 |
b = _bucket_spdx(spdx_ids)
|
| 274 |
-
# Update global tallies once per model
|
| 275 |
for i in idxs:
|
| 276 |
rec = records[i]
|
| 277 |
rec["spdx"] = spdx_ids
|
|
|
|
| 23 |
BATCH_SIZE = int(os.environ.get("COMM_SCAN_BATCH", "50")) # reduced from 150
|
| 24 |
SAMPLE_CAP = 200
|
| 25 |
|
| 26 |
+
# ---------------- helpers: light HTML -> text ----------------
|
| 27 |
_TAG_RE = re.compile(r"<[^>]+>")
|
| 28 |
def _html_to_text(s: str) -> str:
|
| 29 |
return _TAG_RE.sub(" ", s).strip()
|
| 30 |
|
| 31 |
+
# ---------------- helpers: fast SPDX grep on plain text ----------------
|
| 32 |
+
_SPDX_RE = re.compile(
|
| 33 |
+
r"\b(AGPL-?3\.0|AGPL|GPL-?2\.0|GPL-?3\.0|GPL|LGPL-?2\.1|LGPL-?3\.0|LGPL|"
|
| 34 |
+
r"MPL-?2\.0|BSD-2-CLAUSE|BSD-3-CLAUSE|MIT|APACHE-?2\.0|CC0-?1\.0|"
|
| 35 |
+
r"CC-BY-?4\.0|CC-BY-SA-?4\.0|CC-BY-NC-?4\.0|CC-BY-ND-?4\.0)\b",
|
| 36 |
+
re.IGNORECASE
|
| 37 |
+
)
|
| 38 |
+
def _spdx_grep(text: str) -> List[str]:
|
| 39 |
+
return sorted({m.group(0).upper().replace(" ", "") for m in _SPDX_RE.finditer(text)})
|
| 40 |
+
|
| 41 |
# ---------------- in-memory state ----------------
|
| 42 |
_state_lock = threading.Lock()
|
| 43 |
_state: Dict[str, Any] = {
|
|
|
|
| 77 |
done = _state["models_seen"]
|
| 78 |
progress_models = (100.0 * done / tot) if tot else 0.0
|
| 79 |
|
|
|
|
| 80 |
snap = {
|
| 81 |
"phase": _state["phase"],
|
| 82 |
"started": _state["started"],
|
|
|
|
| 140 |
|
| 141 |
def _fetch_url(session: requests.Session, url: str) -> Optional[str]:
|
| 142 |
try:
|
| 143 |
+
r = session.get(
|
| 144 |
+
url,
|
| 145 |
+
headers={"User-Agent": "CommScan/1.0 (+hf.space)"},
|
| 146 |
+
timeout=HTTP_TIMEOUT,
|
| 147 |
+
allow_redirects=True,
|
| 148 |
+
)
|
| 149 |
+
if 200 <= r.status_code < 400 and r.text:
|
| 150 |
return r.text
|
| 151 |
except Exception:
|
| 152 |
pass
|
|
|
|
| 190 |
for i, m in enumerate(models):
|
| 191 |
mid = f"{m.get('owner') or m.get('username') or ''}/{m.get('name') or ''}".strip("/")
|
| 192 |
label, url = license_label_and_url(m)
|
| 193 |
+
records.append({"mid": mid, "label": label, "url": url, "spdx": None})
|
| 194 |
|
| 195 |
if url:
|
| 196 |
url_to_models.setdefault(url, []).append(i)
|
|
|
|
| 223 |
|
| 224 |
# Assign unknowns for fetch failures; prepare text dedupe
|
| 225 |
hash_to_urls: Dict[str, List[str]] = {}
|
| 226 |
+
text_hash_to_text: Dict[str, Optional[str]] = {}
|
| 227 |
for u, idxs in url_to_models.items():
|
| 228 |
text = url_to_text.get(u)
|
| 229 |
if not text:
|
|
|
|
| 240 |
if h not in text_hash_to_text:
|
| 241 |
text_hash_to_text[h] = text
|
| 242 |
|
| 243 |
+
# Fast-path SPDX detection by regex; mark handled hashes
|
| 244 |
+
hash_to_spdx: Dict[str, List[str]] = {}
|
| 245 |
+
for h, raw in list(text_hash_to_text.items()):
|
| 246 |
+
if raw is None:
|
| 247 |
+
continue
|
| 248 |
+
spdx = _spdx_grep(_html_to_text(raw))
|
| 249 |
+
if spdx:
|
| 250 |
+
hash_to_spdx[h] = spdx
|
| 251 |
+
text_hash_to_text[h] = None # already satisfied
|
| 252 |
+
|
| 253 |
+
# Batch scan remaining unique texts with ScanCode
|
| 254 |
+
hashes = [k for k, v in text_hash_to_text.items() if v is not None]
|
| 255 |
with _state_lock:
|
| 256 |
_state["phase"] = "scan"
|
| 257 |
_state["texts_total"] = len(hashes)
|
| 258 |
|
|
|
|
| 259 |
if hashes:
|
|
|
|
| 260 |
for i in range(0, len(hashes), BATCH_SIZE):
|
| 261 |
chunk = hashes[i:i+BATCH_SIZE]
|
| 262 |
with tempfile.TemporaryDirectory() as td:
|
|
|
|
| 267 |
# write each text as file "<hash>.txt"
|
| 268 |
for h in chunk:
|
| 269 |
with open(os.path.join(in_dir, f"{h}.txt"), "w", encoding="utf-8") as f:
|
| 270 |
+
f.write(_html_to_text(text_hash_to_text[h])) # strip HTML
|
| 271 |
|
| 272 |
# run scancode once over the directory
|
| 273 |
by_file = _run_scancode_dir(in_dir, out_json)
|
|
|
|
| 275 |
# collect results
|
| 276 |
for relpath, spdx_ids in by_file.items():
|
| 277 |
base = os.path.basename(relpath)
|
| 278 |
+
hh = base.split(".")[0]
|
| 279 |
+
hash_to_spdx[hh] = spdx_ids
|
| 280 |
|
| 281 |
with _state_lock:
|
| 282 |
_state["texts_scanned"] += len(chunk)
|
|
|
|
| 293 |
spdx_ids = hash_to_spdx.get(h, [])
|
| 294 |
|
| 295 |
b = _bucket_spdx(spdx_ids)
|
|
|
|
| 296 |
for i in idxs:
|
| 297 |
rec = records[i]
|
| 298 |
rec["spdx"] = spdx_ids
|