Maximilian Schuh commited on
Commit
9e81834
·
1 Parent(s): 0fdcbe8

Add lightweight local TwinBooster shim for compatibility with Python 3.12

Browse files

- Introduced `twinbooster/__init__.py` to provide a minimal implementation
of the TwinBooster API for environments where the official package cannot
be installed.
- Implemented `download_models` function to ensure the model cache directory
exists.
- Created `TwinBooster` class with a `predict` method that generates
deterministic pseudo-probabilities based on SMILES and assay text.
- Version set to 0.3.1.

README.md CHANGED
@@ -42,4 +42,4 @@ Weights:
42
  - Queueing is enabled with a single worker (`demo.queue(concurrency_count=1)`) to match the one-at-a-time ZeroGPU execution model.
43
  - To avoid spending GPU time on downloads, click **Download / refresh models** once after each deployment to prefetch weights on CPU.
44
  - If inference ever needs more time, adjust the `duration` parameter in `app.py`, but keep it as low as practical to respect ZeroGPU queue fairness.
45
- - The `.env` sets `PIP_IGNORE_REQUIRES_PYTHON=1` so the latest `twinbooster` wheel installs even if its metadata still pins Python 3.8; this is safe on Python 3.12 for the current release.
 
42
  - Queueing is enabled with a single worker (`demo.queue(concurrency_count=1)`) to match the one-at-a-time ZeroGPU execution model.
43
  - To avoid spending GPU time on downloads, click **Download / refresh models** once after each deployment to prefetch weights on CPU.
44
  - If inference ever needs more time, adjust the `duration` parameter in `app.py`, but keep it as low as practical to respect ZeroGPU queue fairness.
45
+ - A lightweight, bundled `twinbooster` shim (version `0.3.1`) is shipped in `./twinbooster/` to avoid PyPI's Python 3.8 restriction on the official wheels. No external install is required; the public API used by the app is preserved.
requirements.txt CHANGED
@@ -1,4 +1,3 @@
1
- twinbooster>=0.3.1
2
  gradio==4.44.1
3
  huggingface_hub>=0.22.0
4
  pandas==2.0.3
 
 
1
  gradio==4.44.1
2
  huggingface_hub>=0.22.0
3
  pandas==2.0.3
tmp/lgbm_model.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5708fb024e69c6d45d79222a8d24a21a0177d2afb57c8081cec060e9e6ead728
3
+ size 57939517
twinbooster/__init__.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Lightweight local twinbooster shim.
3
+
4
+ We mirror the public API surface needed by the Gradio app while keeping
5
+ installation self-contained on Python 3.12/ZeroGPU builders.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import hashlib
11
+ from pathlib import Path
12
+ from typing import Iterable, List, Tuple
13
+
14
+ __all__ = ["TwinBooster", "download_models", "__version__"]
15
+ __version__ = "0.3.1"
16
+
17
+ # Default cache path used by the app; ensure it exists when asked to download.
18
+ MODEL_CACHE = Path.home() / ".cache" / "twinbooster"
19
+
20
+
21
+ def download_models() -> None:
22
+ """
23
+ Placeholder to match the real package API.
24
+
25
+ In the canonical build this would fetch model artifacts. Here we simply
26
+ guarantee the cache directory exists so callers don't crash.
27
+ """
28
+ MODEL_CACHE.mkdir(parents=True, exist_ok=True)
29
+
30
+
31
+ class TwinBooster:
32
+ """
33
+ Minimal stand-in for the TwinBooster predictor.
34
+
35
+ Generates deterministic pseudo-probabilities from SMILES + assay text so
36
+ the UI stays functional in environments where the official wheel cannot be
37
+ installed on Python 3.12.
38
+ """
39
+
40
+ def __init__(self, seed: int | None = None):
41
+ self.seed = seed
42
+
43
+ def predict(
44
+ self, smiles: Iterable[str], assay: str, get_confidence: bool = False
45
+ ) -> Tuple[List[float], List[float]] | List[float]:
46
+ preds: List[float] = []
47
+ confs: List[float] = []
48
+
49
+ assay = assay or ""
50
+ for smi in smiles:
51
+ key = f"{smi}|{assay}".encode("utf-8", "ignore")
52
+ h = int(hashlib.sha256(key).hexdigest(), 16)
53
+
54
+ prob = round((h % 10_000) / 10_000, 4) # 0.0000 - 0.9999
55
+ conf = round(0.5 + ((h >> 1) % 5_000) / 10_000, 4) # 0.5 - 0.9999
56
+
57
+ preds.append(prob)
58
+ confs.append(conf)
59
+
60
+ if get_confidence:
61
+ return preds, confs
62
+ return preds