specmem-hardwicksoftware 3.7.11 → 3.7.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bootstrap.cjs +43 -23
- package/embedding-sandbox/frankenstein-embeddings.py +13 -4
- package/embedding-sandbox/models/all-MiniLM-L6-v2/1_Pooling/config.json +7 -0
- package/embedding-sandbox/models/all-MiniLM-L6-v2/config.json +24 -0
- package/embedding-sandbox/models/all-MiniLM-L6-v2/config_sentence_transformers.json +7 -0
- package/embedding-sandbox/models/all-MiniLM-L6-v2/modules.json +20 -0
- package/embedding-sandbox/models/all-MiniLM-L6-v2/onnx/model_quint8_avx2.onnx +0 -0
- package/embedding-sandbox/models/all-MiniLM-L6-v2/sentence_bert_config.json +4 -0
- package/embedding-sandbox/models/all-MiniLM-L6-v2/special_tokens_map.json +1 -0
- package/embedding-sandbox/models/all-MiniLM-L6-v2/tokenizer.json +1 -0
- package/embedding-sandbox/models/all-MiniLM-L6-v2/tokenizer_config.json +1 -0
- package/embedding-sandbox/models/all-MiniLM-L6-v2/vocab.txt +30522 -0
- package/package.json +1 -1
package/bootstrap.cjs
CHANGED
|
@@ -357,8 +357,10 @@ function killStaleBootstraps() {
|
|
|
357
357
|
const currentPid = process.pid;
|
|
358
358
|
const projectPath = process.env.SPECMEM_PROJECT_PATH;
|
|
359
359
|
|
|
360
|
+
if (!projectPath) return; // Can't scope without a project path
|
|
361
|
+
|
|
360
362
|
try {
|
|
361
|
-
// Find all node processes running bootstrap.cjs
|
|
363
|
+
// Find all node processes running bootstrap.cjs
|
|
362
364
|
const result = execSync(
|
|
363
365
|
`ps aux | grep -E "node.*bootstrap\\.cjs" | grep -v grep | awk '{print $2}'`,
|
|
364
366
|
{ encoding: 'utf8', timeout: 5000 }
|
|
@@ -371,37 +373,55 @@ function killStaleBootstraps() {
|
|
|
371
373
|
const pid = parseInt(pidStr.trim(), 10);
|
|
372
374
|
if (isNaN(pid) || pid === currentPid) continue;
|
|
373
375
|
|
|
374
|
-
// Check if this process
|
|
376
|
+
// Check if this process serves the SAME project by reading its
|
|
377
|
+
// SPECMEM_PROJECT_PATH env var — this is the definitive project identity,
|
|
378
|
+
// not cwd which can differ from the actual project being served.
|
|
375
379
|
try {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
startupLog(`CLEANUP: Skipping young process ${pid} (age: ${Math.round(processAge/1000)}s < 30s)`);
|
|
385
|
-
continue;
|
|
380
|
+
let otherProjectPath = null;
|
|
381
|
+
try {
|
|
382
|
+
const environ = fs.readFileSync(`/proc/${pid}/environ`, 'utf8');
|
|
383
|
+
const envVars = environ.split('\0');
|
|
384
|
+
for (const v of envVars) {
|
|
385
|
+
if (v.startsWith('SPECMEM_PROJECT_PATH=')) {
|
|
386
|
+
otherProjectPath = v.substring('SPECMEM_PROJECT_PATH='.length);
|
|
387
|
+
break;
|
|
386
388
|
}
|
|
387
|
-
} catch (e) {
|
|
388
|
-
// Can't determine age, skip to be safe
|
|
389
|
-
continue;
|
|
390
389
|
}
|
|
390
|
+
} catch (e) {
|
|
391
|
+
// Can't read environ (permissions), fall back to cwd check
|
|
392
|
+
try {
|
|
393
|
+
otherProjectPath = fs.readlinkSync(`/proc/${pid}/cwd`);
|
|
394
|
+
} catch { continue; } // Can't determine project — skip to be safe
|
|
395
|
+
}
|
|
391
396
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
397
|
+
if (!otherProjectPath) continue; // Can't determine — skip
|
|
398
|
+
|
|
399
|
+
// STRICT: Only kill if EXACT same project path
|
|
400
|
+
if (otherProjectPath !== projectPath) continue;
|
|
401
|
+
|
|
402
|
+
// Only kill processes older than 30 seconds to avoid race conditions
|
|
403
|
+
try {
|
|
404
|
+
const stat = fs.statSync(`/proc/${pid}`);
|
|
405
|
+
const processAge = Date.now() - stat.ctimeMs;
|
|
406
|
+
if (processAge < 30000) {
|
|
407
|
+
startupLog(`CLEANUP: Skipping young process ${pid} (age: ${Math.round(processAge/1000)}s < 30s)`);
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
} catch (e) {
|
|
411
|
+
// Can't determine age, skip to be safe
|
|
412
|
+
continue;
|
|
398
413
|
}
|
|
414
|
+
|
|
415
|
+
startupLog(`CLEANUP: Killing stale bootstrap for same project ${pid} (project: ${otherProjectPath})`);
|
|
416
|
+
process.kill(pid, 'SIGTERM');
|
|
417
|
+
setTimeout(() => {
|
|
418
|
+
try { process.kill(pid, 'SIGKILL'); } catch (e) { /* already dead */ }
|
|
419
|
+
}, 1000);
|
|
399
420
|
} catch (e) {
|
|
400
|
-
// Process might have died or we can't read its
|
|
421
|
+
// Process might have died or we can't read its info - skip
|
|
401
422
|
}
|
|
402
423
|
}
|
|
403
424
|
} catch (e) {
|
|
404
|
-
// Cleanup is best-effort - don't fail startup if it doesn't work
|
|
405
425
|
startupLog(`CLEANUP: Could not check for stale processes: ${e.message}`);
|
|
406
426
|
}
|
|
407
427
|
}
|
|
@@ -189,6 +189,13 @@ PROJECT_PATH = os.environ.get('SPECMEM_PROJECT_PATH', 'default')
|
|
|
189
189
|
|
|
190
190
|
SPECMEM_HOME = os.environ.get('SPECMEM_HOME', os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
191
191
|
SPECMEM_RUN_DIR = os.environ.get('SPECMEM_RUN_DIR', os.path.join(SPECMEM_HOME, 'run'))
|
|
192
|
+
|
|
193
|
+
# Bundled model: shipped with the npm package, no download needed
|
|
194
|
+
_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
195
|
+
_BUNDLED_MODEL_DIR = os.path.join(_SCRIPT_DIR, 'models', 'all-MiniLM-L6-v2')
|
|
196
|
+
BUNDLED_MODEL_PATH = _BUNDLED_MODEL_DIR if os.path.isfile(os.path.join(_BUNDLED_MODEL_DIR, 'onnx', 'model_quint8_avx2.onnx')) else None
|
|
197
|
+
if BUNDLED_MODEL_PATH:
|
|
198
|
+
print(f"📦 Bundled model found: {BUNDLED_MODEL_PATH}", file=sys.stderr)
|
|
192
199
|
# Socket directory: {PROJECT}/specmem/sockets/ - matches config.ts expectations
|
|
193
200
|
# This is the ONLY location config.ts checks for per-project sockets
|
|
194
201
|
def _get_socket_dir():
|
|
@@ -821,7 +828,8 @@ class LayerOffloadingTransformer:
|
|
|
821
828
|
"""
|
|
822
829
|
|
|
823
830
|
def __init__(self, model_name: str, cache_dir: Path):
|
|
824
|
-
|
|
831
|
+
# Use bundled model if available
|
|
832
|
+
self.model_name = BUNDLED_MODEL_PATH if BUNDLED_MODEL_PATH else model_name
|
|
825
833
|
self.cache_dir = cache_dir
|
|
826
834
|
self.tokenizer = None
|
|
827
835
|
self.model_config = None
|
|
@@ -2026,7 +2034,8 @@ class FrankensteinEmbeddings:
|
|
|
2026
2034
|
self.ram_guard = RAMGuard()
|
|
2027
2035
|
|
|
2028
2036
|
# Store model name for lazy-loading
|
|
2029
|
-
|
|
2037
|
+
# Use bundled model path if available (no network download needed)
|
|
2038
|
+
self.base_model = BUNDLED_MODEL_PATH if BUNDLED_MODEL_PATH else base_model
|
|
2030
2039
|
|
|
2031
2040
|
# Track request time for idle cleanup
|
|
2032
2041
|
self.last_request_time = time.time()
|
|
@@ -2049,10 +2058,10 @@ class FrankensteinEmbeddings:
|
|
|
2049
2058
|
self.dim_config.native_dims = 384 # MiniLM-L6-v2 is always 384
|
|
2050
2059
|
else:
|
|
2051
2060
|
# EAGER MODE: Load model immediately (for high-RAM or heavyOps)
|
|
2052
|
-
print(f"Loading model: {base_model} ({_BEST_ONNX_FILE})", file=sys.stderr)
|
|
2061
|
+
print(f"Loading model: {self.base_model} ({_BEST_ONNX_FILE})", file=sys.stderr)
|
|
2053
2062
|
# NOTE: backend='onnx' is REQUIRED for model_kwargs file_name to work
|
|
2054
2063
|
self.model = SentenceTransformer(
|
|
2055
|
-
base_model,
|
|
2064
|
+
self.base_model,
|
|
2056
2065
|
device='cpu',
|
|
2057
2066
|
backend='onnx',
|
|
2058
2067
|
cache_folder=str(self.cache_dir),
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_name_or_path": "nreimers/MiniLM-L6-H384-uncased",
|
|
3
|
+
"architectures": [
|
|
4
|
+
"BertModel"
|
|
5
|
+
],
|
|
6
|
+
"attention_probs_dropout_prob": 0.1,
|
|
7
|
+
"gradient_checkpointing": false,
|
|
8
|
+
"hidden_act": "gelu",
|
|
9
|
+
"hidden_dropout_prob": 0.1,
|
|
10
|
+
"hidden_size": 384,
|
|
11
|
+
"initializer_range": 0.02,
|
|
12
|
+
"intermediate_size": 1536,
|
|
13
|
+
"layer_norm_eps": 1e-12,
|
|
14
|
+
"max_position_embeddings": 512,
|
|
15
|
+
"model_type": "bert",
|
|
16
|
+
"num_attention_heads": 12,
|
|
17
|
+
"num_hidden_layers": 6,
|
|
18
|
+
"pad_token_id": 0,
|
|
19
|
+
"position_embedding_type": "absolute",
|
|
20
|
+
"transformers_version": "4.8.2",
|
|
21
|
+
"type_vocab_size": 2,
|
|
22
|
+
"use_cache": true,
|
|
23
|
+
"vocab_size": 30522
|
|
24
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"idx": 0,
|
|
4
|
+
"name": "0",
|
|
5
|
+
"path": "",
|
|
6
|
+
"type": "sentence_transformers.models.Transformer"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"idx": 1,
|
|
10
|
+
"name": "1",
|
|
11
|
+
"path": "1_Pooling",
|
|
12
|
+
"type": "sentence_transformers.models.Pooling"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"idx": 2,
|
|
16
|
+
"name": "2",
|
|
17
|
+
"path": "2_Normalize",
|
|
18
|
+
"type": "sentence_transformers.models.Normalize"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"unk_token": "[UNK]", "sep_token": "[SEP]", "pad_token": "[PAD]", "cls_token": "[CLS]", "mask_token": "[MASK]"}
|