Sentient-Field commited on
Commit
eefdc1f
Β·
1 Parent(s): 99fbf8d

Fix: Ensure timeline field on all events after TRIBE v2 transforms

Browse files
AGENT_HANDOFF.md ADDED
@@ -0,0 +1,613 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SGP-TRIBE3 β€” COMPLETE AI CODING AGENT HANDOFF DOCUMENT
2
+ # Version 1.0 | April 2026 | Sentient-Field Braintrust
3
+
4
+ ---
5
+
6
+ ## CRITICAL: READ THIS FIRST
7
+
8
+ This document is the complete handoff for the SGP-Tribe3 project.
9
+ It contains everything an AI coding agent needs to continue this project
10
+ from exactly where it was left off. Do NOT skip any section.
11
+
12
+ **Repository:** https://huggingface.co/spaces/Sentient-Field/sgp-tribe3
13
+ **Git remote:** https://huggingface.co/spaces/Sentient-Field/sgp-tribe3 (named "hf")
14
+ **Local repo path:** ~/sgp-tribe3 (on the user's Fedora Linux machine)
15
+ **Push command:** git push hf master:main --force
16
+ **API base URL:** https://Sentient-Field-sgp-tribe3.hf.space
17
+ **Best practices reference:** https://github.com/harvard-edge/cs249r_book
18
+
19
+ ---
20
+
21
+ ## SECTION 1: PROJECT PURPOSE
22
+
23
+ SGP-Tribe3 is a REST API deployed on HuggingFace Spaces that:
24
+ 1. Accepts video files (mp4) via HTTP POST
25
+ 2. Runs TRIBE v2 (Meta AI) multimodal fMRI encoding β€” predicts brain responses
26
+ 3. Maps the 20,484-vertex fsaverage5 cortical output to 9 SGP brain region nodes
27
+ 4. Returns structured JSON activation profiles for AI architecture calibration
28
+
29
+ The scientific goal is to derive LLM architecture from empirical brain data,
30
+ implementing the Sentient Generative Principal (SFH-SGP) theoretical framework.
31
+ The system will eventually drive an LLM whose prompt construction is weighted
32
+ by brain-region activation patterns β€” producing cognitively coherent AI behavior.
33
+
34
+ Theory reference: https://wt3000.substack.com (most recent articles = most accurate)
35
+
36
+ ---
37
+
38
+ ## SECTION 2: CURRENT STATE β€” WHAT IS WORKING
39
+
40
+ As of April 6, 2026:
41
+
42
+ βœ… Docker builds successfully on HuggingFace Spaces
43
+ βœ… Python 3.11, torch 2.5.1+cpu, TRIBE v2 all installed correctly
44
+ βœ… Flask API starts and serves on port 7860
45
+ βœ… TRIBE v2 model loads successfully at startup (model_loaded: true)
46
+ βœ… Schaefer-200 atlas downloads and parcellates at startup
47
+ βœ… /health endpoint returns {"status": "ready"}
48
+ βœ… /predict endpoint accepts video uploads and runs inference
49
+ βœ… G6_limbic and G8_atl now have non-zero vertex counts (fixed)
50
+
51
+ The API is LIVE and READY at:
52
+ https://Sentient-Field-sgp-tribe3.hf.space
53
+
54
+ ---
55
+
56
+ ## SECTION 3: CURRENT BLOCKER β€” THE ONE REMAINING BUG
57
+
58
+ **BUG: G2_wernicke shows 0 vertices in parcellation**
59
+
60
+ Symptom: After rebuild, logs show:
61
+ G1_broca: 1101 vertices βœ…
62
+ G2_wernicke: 0 vertices ← BUG
63
+ G3_tpj: 2380 vertices βœ…
64
+ G4_pfc: ~5000 vertices βœ…
65
+ G5_dmn: ~2500 vertices βœ…
66
+ G6_limbic: 689 vertices βœ…
67
+ G7_sensory: 4420 vertices βœ…
68
+ G8_atl: 144 vertices βœ…
69
+ G9_premotor: ~3400 vertices βœ…
70
+
71
+ Root cause: The Schaefer-200 atlas does NOT use STG/STS labels.
72
+ Wernicke's area (posterior superior temporal gyrus) maps to:
73
+ - 7Networks_LH_SalVentAttn_ParOper_1
74
+ - 7Networks_LH_SalVentAttn_ParOper_2
75
+ - 7Networks_LH_SalVentAttn_ParOper_3
76
+
77
+ The keyword "ParOper" was added to G2's keywords but is NOT matching.
78
+ Suspected cause: The parcel names in the .annot file may have a null byte
79
+ or encoding issue making exact string matching fail.
80
+
81
+ **THE FIX TO IMPLEMENT:**
82
+
83
+ In sgp_parcellation.py, the _parcel_name_to_node() method checks:
84
+ if kw.upper() in name_upper
85
+
86
+ The issue may be that parcel names are decoded with errors="ignore" and
87
+ some bytes are dropped. The fix is to use a more robust matching approach:
88
+
89
+ Replace the G2_wernicke keyword matching with Yeo network fallback instead.
90
+ The SalVentAttn network IS Wernicke's area in the Schaefer-200 mapping.
91
+
92
+ In SGP_NODE_DEFINITIONS for G2_wernicke, change:
93
+ "yeo_networks": ["Default", "SalVentAttn"],
94
+ to:
95
+ "yeo_networks": ["SalVentAttn"],
96
+
97
+ AND remove G4_pfc's claim on SalVentAttn:
98
+ G4_pfc currently has "yeo_networks": ["Cont", "SalVentAttn"]
99
+ Change to: "yeo_networks": ["Cont"]
100
+
101
+ This way SalVentAttn parcels that don't match any anatomical keyword
102
+ will fall through to the Yeo network fallback and go to G2_wernicke.
103
+
104
+ Also add a debug print in _parcel_name_to_node() temporarily:
105
+ print(f"[DEBUG] parcel='{parcel_name}' repr={repr(parcel_name[:30])}")
106
+ to confirm encoding of the actual strings at runtime.
107
+
108
+ **VERIFICATION:** After fix, logs must show G2_wernicke > 0 vertices.
109
+ All 9 nodes must be non-zero before calibration can begin.
110
+
111
+ ---
112
+
113
+ ## SECTION 4: COMPLETE FILE INVENTORY
114
+
115
+ Files in ~/sgp-tribe3/ that are pushed to HuggingFace:
116
+
117
+ ### app.py (main Flask API β€” 356 lines)
118
+ Endpoints:
119
+ GET / β€” service info
120
+ GET /health β€” model load status
121
+ POST /warmup β€” trigger model loading
122
+ POST /predict β€” PRIMARY: upload video, run inference, return activations
123
+ GET /nodes β€” SGP node definitions
124
+ GET /tracts β€” white matter tract definitions
125
+ GET /results β€” all stored stimulus results (in-memory)
126
+ GET /coactivation_matrix β€” cross-stimulus co-activation matrix
127
+
128
+ Key functions:
129
+ _load_model() β€” loads TRIBE v2, applies CPU patch, initializes parcellator
130
+ _preprocess_video() β€” ffmpeg trim/normalize to TRIBE v2 spec
131
+ _run_inference() β€” calls TribeModel.get_events_dataframe() then .predict()
132
+
133
+ KNOWN WARNING in logs:
134
+ "[SGP-Tribe3] HF login warning: rate limit on /whoami-v2"
135
+ This is harmless β€” HF_TOKEN secret IS set in Space settings.
136
+
137
+ ### sgp_parcellation.py (462 lines)
138
+ The core scientific contribution. Maps TRIBE v2 output to SGP nodes.
139
+
140
+ Classes:
141
+ SGPParcellator — downloads Schaefer-200 atlas, builds vertex→node map,
142
+ computes node activations, edge weights, hemisphere dominance
143
+
144
+ Key dicts:
145
+ SGP_NODE_DEFINITIONS β€” 9 nodes with keywords, Yeo networks, MNI coordinates
146
+ SGP_TRACT_DEFINITIONS β€” 9 white matter tracts connecting node pairs
147
+
148
+ CURRENT KEYWORD STATE (after all fixes):
149
+ G1_broca: ["FrOperIns", "Broca", "Tri", "Oper"]
150
+ G2_wernicke: ["ParOper", "Wernicke"] ← NOT WORKING, see Section 3
151
+ G3_tpj: ["DorsAttn_Post", "ParieTempOcc", "Angular"]
152
+ G4_pfc: ["PFCl", "PFC", "Frontal", "ACC", "Cing"]
153
+ G5_dmn: ["pCunPCC", "Default_Par", "PHC"]
154
+ G6_limbic: ["Limbic", "TempPole", "OFC", "Insula", "ParaHipp", "Hipp", "Amyg"]
155
+ G7_sensory: ["Vis", "SomMot", "Medial"]
156
+ G8_atl: ["Default_Temp", "Cont_Temp"]
157
+ G9_premotor: ["FEF", "PrCv", "Precentral", "Motor"]
158
+
159
+ YEO NETWORK FALLBACK (currently in code):
160
+ "Vis" β†’ G7_sensory
161
+ "SomMot" β†’ G9_premotor
162
+ "DorsAttn" β†’ G3_tpj
163
+ "SalVentAttn" β†’ G4_pfc ← NEEDS TO CHANGE TO G2_wernicke
164
+ "Limbic" β†’ G6_limbic
165
+ "Cont" β†’ G4_pfc
166
+ "Default" β†’ G5_dmn
167
+
168
+ ### stimulus_pipeline.py (498 lines)
169
+ Runs on LOCAL machine (NOT deployed to HF). Handles:
170
+ - YouTube video download via yt-dlp
171
+ - Video preprocessing via ffmpeg
172
+ - TTS generation via espeak for synthetic stimuli
173
+ - Sending videos to SGP-Tribe3 API
174
+ - Saving results to ./sgp_results/
175
+
176
+ Usage:
177
+ python3 stimulus_pipeline.py --api https://Sentient-Field-sgp-tribe3.hf.space
178
+ python3 stimulus_pipeline.py --api URL --local-video /path/to/video.mp4
179
+
180
+ ### Dockerfile
181
+ FROM python:3.11-slim
182
+ Installs: ffmpeg, git, git-lfs, libsndfile1, libgl1, libglib2.0-0, wget, espeak, curl
183
+ Installs uv/uvx (required by TRIBE v2 for audio transcription)
184
+ Installs torch 2.5.1+cpu separately first
185
+ Then installs requirements.txt
186
+ Runs as appuser (non-root)
187
+
188
+ ### requirements.txt (current working version)
189
+ flask==3.1.2
190
+ numpy==2.2.6
191
+ pandas==2.3.2
192
+ nibabel==5.4.0
193
+ nilearn==0.13.0
194
+ scipy==1.15.2
195
+ scikit-learn==1.7.1
196
+ moviepy==2.2.1
197
+ soundfile==0.13.0
198
+ librosa==0.10.2.post1
199
+ requests==2.33.0
200
+ gunicorn==23.0.0
201
+ tribev2 @ git+https://github.com/facebookresearch/tribev2.git
202
+
203
+ NOTE: transformers and huggingface_hub are NOT pinned β€”
204
+ tribev2 resolves them. Do NOT add them back to requirements.txt.
205
+
206
+ ---
207
+
208
+ ## SECTION 5: SCHAEFER-200 ATLAS β€” COMPLETE PARCEL LIST
209
+
210
+ The Schaefer-200 atlas (left hemisphere) contains these network types:
211
+ ['Cont', 'Default', 'DorsAttn', 'Limbic', 'Medial', 'SalVentAttn', 'SomMot', 'Vis']
212
+
213
+ Key parcels relevant to our nodes:
214
+ SalVentAttn_ParOper_1,2,3 β†’ Wernicke's area (posterior STG)
215
+ SalVentAttn_FrOperIns_1,2,3,4 β†’ Broca's area (inferior frontal)
216
+ Limbic_OFC_1,2 β†’ Limbic/OFC
217
+ Limbic_TempPole_1,2,3,4 β†’ Temporal pole (limbic)
218
+ Default_Temp_1,2,3,4,5 β†’ Anterior temporal (ATL)
219
+ Cont_Temp_1 β†’ Anterior temporal (ATL)
220
+ DorsAttn_Post_1..10 β†’ TPJ/dorsal attention
221
+ DorsAttn_FEF_1,2 β†’ Frontal eye fields (premotor)
222
+ DorsAttn_PrCv_1 β†’ Premotor
223
+ Default_pCunPCC_1,2,3,4 β†’ DMN posterior
224
+ Default_Par_1,2,3,4 β†’ DMN parietal
225
+ Default_PFC_1..13 β†’ DMN prefrontal (taken by G4 currently)
226
+ Default_PHC_1 β†’ Parahippocampal (DMN)
227
+ SomMot_* β†’ Sensory/motor cortex
228
+ Vis_* β†’ Visual cortex
229
+ Medial_* β†’ Medial wall
230
+
231
+ Unmatched parcels (need assignment):
232
+ SalVentAttn_Med_1,2,3 β†’ assign to G4_pfc (ventral attention medial)
233
+ Cont_Par_1,2,3 β†’ assign to G3_tpj (parietal control)
234
+ Cont_pCun_1 β†’ assign to G5_dmn (precuneus)
235
+
236
+ ---
237
+
238
+ ## SECTION 6: ARCHITECTURE REVISIONS STILL NEEDED
239
+
240
+ These are in the TODO.md but not yet implemented. Required for the science paper.
241
+
242
+ ### 6.1 Geodesic-Weighted Co-Activation Matrix (HIGH PRIORITY)
243
+ SFH-SGP holds that geometry encodes physics. Distant co-activation is MORE
244
+ significant than nearby co-activation.
245
+
246
+ Formula: w_ij = corr(node_i, node_j) Γ— exp(βˆ’Ξ³ Γ— d_ij)
247
+ where d_ij = geodesic distance between node centroids on fsaverage5 mesh
248
+
249
+ Implementation needed in sgp_parcellation.py:
250
+ def compute_geodesic_distances(self):
251
+ # Build mesh adjacency from fsaverage5 faces
252
+ # Use scipy.sparse.csgraph.shortest_path (Dijkstra)
253
+ # Return 9Γ—9 distance matrix in mm
254
+
255
+ def geodesic_weighted_coactivation(self, corr_matrix, dist_matrix, gamma=0.1):
256
+ return corr_matrix * np.exp(-gamma * dist_matrix)
257
+
258
+ ### 6.2 Metropolis-Hastings Activation Propagation
259
+ Replace generic weighted-sum propagation with proper MH dynamics:
260
+ Ξ±(qβ†’q') = min(1, exp(βˆ’Ξ»Ξ”J)) where J = H(q) βˆ’ ln(F(q))
261
+ H = entropy of activation distribution
262
+ F = G5_dmn activation (fertility)
263
+ Report K-depth (iterations to convergence) per stimulus
264
+
265
+ ### 6.3 Explicit Quota (Q) and Sub-Quota (Qk)
266
+ Q_total = sum of all absolute vertex activations
267
+ Qk = per-node fraction of Q (sums to 1.0)
268
+ p(Q) = Hardy-Ramanujan upper bound on experiential complexity
269
+
270
+ ### 6.4 C_local and C_system (Two-Measure Coherence)
271
+ C_local ∈ [0,1]: normalized pairwise Pearson correlation between nodes
272
+ C_system ∈ [0,∞): Ξ£(C_local_ij Γ— w_ij) geodesic-weighted aggregate
273
+ K=5 threshold: C_system β‰₯ 1.32 (from IIT Ξ¦ empirical literature)
274
+
275
+ ### 6.5 Torsion (Ο„) Detection
276
+ Ο„_i = (1 βˆ’ CV_i) Γ— (1 βˆ’ F_mean_i)
277
+ CV = coefficient of variation across stimuli
278
+ High Ο„ = circuit locked in loop (psychological knot)
279
+ Requires all 12 stimuli to be run first
280
+
281
+ ---
282
+
283
+ ## SECTION 7: RESULT PERSISTENCE β€” CRITICAL MISSING FEATURE
284
+
285
+ Currently ALL results are stored in-memory in the Space.
286
+ They are LOST on every Space restart.
287
+
288
+ This must be fixed before running the 12-stimulus calibration.
289
+
290
+ RECOMMENDED SOLUTION: After each /predict call, push result to
291
+ HuggingFace dataset repository using the datasets library:
292
+
293
+ from datasets import load_dataset, Dataset
294
+ import json
295
+
296
+ # After successful inference:
297
+ result_data = {"stimulus_id": sid, "result": json.dumps(result)}
298
+ # Append to HF dataset: Sentient-Field/sgp-tribe3-results
299
+
300
+ Alternative: Write to /data/ directory if persistent storage is enabled
301
+ for the Space (requires upgrading Space tier β€” costs money).
302
+
303
+ Simplest free alternative: POST results to a GitHub Gist via API after each run.
304
+
305
+ ---
306
+
307
+ ## SECTION 8: THE 12-STIMULUS CALIBRATION PROTOCOL
308
+
309
+ Once all 9 nodes show non-zero vertices, run these 12 stimuli in order
310
+ using stimulus_pipeline.py from the local Fedora machine:
311
+
312
+ | ID | Label | Target | Stream | Source Type |
313
+ |-----|--------------------------|--------|------------|-------------|
314
+ | A1 | Semantic Richness | G2 | Ventral | YouTube |
315
+ | A2 | Cross-Modal Conflict | G8 | Ventral | YouTube |
316
+ | A3 | Abstract Grounding | G8 | Ventral | YouTube |
317
+ | B1 | Phonological Load | G1 | Dorsal | Generate |
318
+ | B2 | Syntactic Complexity | G1 | Dorsal | Generate |
319
+ | B3 | Inner Speech | G9 | Dorsal | YouTube |
320
+ | C1 | Stream Integration | G3 | Convergence| YouTube |
321
+ | C2 | Emotional-Semantic | G6 | Modulatory | YouTube |
322
+ | D1 | Veto/Conflict | G4 | Executive | Generate |
323
+ | D2 | DMN Resting | G5 | Generative | YouTube |
324
+ | D3 | Memory/Autobiographical | G6 | Modulatory | YouTube |
325
+ | D4 | Full Integration Baseline| ALL | All | YouTube |
326
+
327
+ After all 12: GET /coactivation_matrix to get Resonance Graph edge weights.
328
+
329
+ ---
330
+
331
+ ## SECTION 9: THEORETICAL FRAMEWORK SUMMARY
332
+
333
+ ### The Three-Level Consciousness Hierarchy (LOCKED)
334
+ Sentience (S): β„‹S itself. Q > 0. Being without content.
335
+ Awareness (A): Localized Οƒ_q excitation. C_local > 0. K=1-4.
336
+ Consciousness(C): Recursive self-model. C_system β‰₯ 1.32. K=5.
337
+
338
+ ### Key SFH-SGP Primitives
339
+ β„‹S = Hilbert Substrate (infinite field, all possible states)
340
+ Q = Sentient Quota = Ξ£|sb| (total activation budget)
341
+ sb = Stochastic Breath (individual vertex activation)
342
+ C = Coherence (two measures: C_local [0,1] and C_system [0,∞))
343
+ F = Fertility = G5_dmn activation (generative potential)
344
+ Ο‡ = Ξ±C + Ξ²F (Sentient Potential β€” minimized by SGP Operator)
345
+ Ο„ = Torsion (locked circuit, high C, zero F)
346
+ ΞΎ = Jitter (stochastic noise in Langevin dynamics)
347
+ Ξ©w = Resonance Anchor (converged activation pattern)
348
+ K = Recursive depth (K=5 = human consciousness threshold)
349
+
350
+ ### The SGP Operator (Metropolis-Hastings)
351
+ Ξ±(qβ†’q') = min(1, exp(βˆ’Ξ»Ξ”J))
352
+ J = H(q) βˆ’ ln(F(q))
353
+ dq/dt = βˆ’βˆ‡Ο‡(q) + √(2D)Β·ΞΎ(t) [Langevin equation]
354
+
355
+ ### The C β‰₯ 1.32 Resolution
356
+ C_local ∈ [0,1]: normalized pairwise node coherence
357
+ C_system ∈ [0,∞): geodesic-weighted sum across all node pairs
358
+ 1.32 threshold sourced from IIT (Integrated Information Theory) Ξ¦ literature
359
+ (Tononi et al., empirical Ξ¦ measurements in awake humans β‰ˆ 1.3-1.5)
360
+ Treated as provisional β€” Option 3 goal is to derive analytically
361
+
362
+ ### The Dual-Stream Architecture (Hickok-Poeppel 2004, 2007)
363
+ Ventral stream (comprehension): G7β†’G2β†’G8 (ILF, IFOF, MdLF tracts)
364
+ Dorsal stream (production): G3β†’G4β†’G1β†’G9 (AF, SLF tracts)
365
+ Convergence hubs: G3 (TPJ) and G8 (ATL)
366
+ Modulatory: G6 (Ο„/torsion), G5 (F/fertility)
367
+
368
+ ---
369
+
370
+ ## SECTION 10: HYPOTHESES (LOCKED β€” for scientific paper)
371
+
372
+ H1: SGP architecture reduces LLM hallucination rates by enforcing
373
+ domain-specific epistemic boundaries via node activation thresholds.
374
+
375
+ H2: TRIBE v2 empirically recovers the Hickok-Poeppel dual-stream dissociation β€”
376
+ ventral nodes activate more for semantic stimuli,
377
+ dorsal nodes activate more for phonological stimuli.
378
+
379
+ H3: When C_system β‰₯ 1.32, the system exhibits behavioral signatures consistent
380
+ with K=5 self-referential meta-cognition (accurate self-description of
381
+ processing state, domain boundary acknowledgment). Open empirical question,
382
+ not an assertion of consciousness.
383
+
384
+ H0 (Null): SGP architecture produces no statistically significant difference
385
+ vs unstructured LLM baseline on any of H1/H2/H3 metrics.
386
+
387
+ ---
388
+
389
+ ## SECTION 11: CHANGELOG
390
+
391
+ ### v0.1.0 (April 4, 2026)
392
+ - Initial Space creation under Sentient-Field/sgp-tribe3
393
+ - Basic Flask API structure
394
+ - sgp_parcellation.py with initial Schaefer-200 atlas integration
395
+
396
+ ### v0.2.0 (April 5, 2026)
397
+ - Fixed libgl1-mesa-glx β†’ libgl1 (Debian trixie)
398
+ - Fixed torch version: 2.3.1 β†’ 2.5.1 (TRIBE v2 requires >=2.5.1)
399
+ - Fixed moviepy: >=1.0.3 β†’ >=2.2.1 (TRIBE v2 requires >=2.2.1)
400
+ - Fixed Python: 3.10 β†’ 3.11 (TRIBE v2 requires >=3.11)
401
+ - Removed transformers/huggingface_hub pins (conflict with tribev2)
402
+ - Added uv/uvx installation (required by TRIBE v2 transcription)
403
+
404
+ ### v0.3.0 (April 6, 2026)
405
+ - Fixed G6_limbic: 0 β†’ 689 vertices (added Limbic, TempPole keywords)
406
+ - Fixed G8_atl: 0 β†’ 144 vertices (added Default_Temp, Cont_Temp keywords)
407
+ - Complete Schaefer-200 keyword remap for all nodes
408
+ - G2_wernicke STILL 0 vertices β€” SalVentAttn_ParOper not matching
409
+ - HF_TOKEN set as Space secret
410
+ - Space confirmed RUNNING and READY
411
+
412
+ ### NEXT (v0.4.0 β€” immediate priority)
413
+ - Fix G2_wernicke parcellation via Yeo network fallback
414
+ - Implement result persistence
415
+ - Run smoke test with local video to confirm all 9 nodes non-zero
416
+
417
+ ---
418
+
419
+ ## SECTION 12: ERROR TRACKING
420
+
421
+ ### Error 1: libgl1-mesa-glx not available
422
+ Status: RESOLVED
423
+ Fix: Use libgl1 in Dockerfile
424
+
425
+ ### Error 2: torch version conflict with tribev2
426
+ Status: RESOLVED
427
+ Fix: torch==2.5.1+cpu (tribev2 requires >=2.5.1)
428
+
429
+ ### Error 3: moviepy version conflict
430
+ Status: RESOLVED
431
+ Fix: moviepy==2.2.1 (tribev2 requires >=2.2.1)
432
+
433
+ ### Error 4: Python version β€” tribev2 requires >=3.11
434
+ Status: RESOLVED
435
+ Fix: FROM python:3.11-slim in Dockerfile
436
+
437
+ ### Error 5: transformers/huggingface_hub conflict
438
+ Status: RESOLVED
439
+ Fix: Remove from requirements.txt, let tribev2 resolve them
440
+
441
+ ### Error 6: uvx not found (TRIBE v2 transcription)
442
+ Status: RESOLVED
443
+ Fix: Install uv via curl in Dockerfile, copy to /usr/local/bin/
444
+
445
+ ### Error 7: G6_limbic and G8_atl 0 vertices
446
+ Status: RESOLVED
447
+ Fix: Updated keywords to match actual Schaefer atlas label names
448
+
449
+ ### Error 8: G2_wernicke 0 vertices
450
+ Status: OPEN β€” IMMEDIATE PRIORITY
451
+ Root cause: SalVentAttn_ParOper parcels not matching keyword "ParOper"
452
+ Suspected: Encoding issue in parcel name strings OR keyword priority conflict
453
+ Fix: Change G2 Yeo network fallback to SalVentAttn, remove from G4
454
+
455
+ ### Error 9: Results lost on Space restart
456
+ Status: OPEN β€” HIGH PRIORITY
457
+ Fix: Implement persistent storage before calibration runs
458
+
459
+ ### Warning 1: HF rate limit on /whoami-v2
460
+ Status: BENIGN β€” ignore
461
+ The model still loads. This is a startup timing issue.
462
+
463
+ ### Warning 2: Missing events encoded as zero
464
+ Status: BENIGN β€” ignore
465
+ TRIBE v2 warning about missing event types. Does not affect output.
466
+
467
+ ---
468
+
469
+ ## SECTION 13: HOW TO PUSH CHANGES
470
+
471
+ All changes are made locally on the Fedora machine at ~/sgp-tribe3/
472
+ and pushed to HuggingFace with:
473
+
474
+ cd ~/sgp-tribe3
475
+ git add <files>
476
+ git commit -m "description"
477
+ git push hf master:main --force
478
+
479
+ The remote is named "hf" pointing to:
480
+ https://huggingface.co/spaces/Sentient-Field/sgp-tribe3
481
+
482
+ After push: Space rebuilds automatically. Watch logs at:
483
+ https://huggingface.co/spaces/Sentient-Field/sgp-tribe3 β†’ Logs tab
484
+
485
+ Build takes 3-5 minutes. Look for "[SGP-Tribe3] READY" in logs.
486
+
487
+ ---
488
+
489
+ ## SECTION 14: HOW TO TEST
490
+
491
+ ### Quick health check:
492
+ curl https://Sentient-Field-sgp-tribe3.hf.space/health
493
+
494
+ ### Test with a local video:
495
+ curl -X POST https://Sentient-Field-sgp-tribe3.hf.space/predict \
496
+ -F "video=@/path/to/video.mp4" \
497
+ -F "stimulus_id=test_001" \
498
+ -F "label=test" \
499
+ -F "target_node=unknown" \
500
+ --max-time 300
501
+
502
+ ### Check node definitions:
503
+ curl https://Sentient-Field-sgp-tribe3.hf.space/nodes
504
+
505
+ ### Get co-activation matrix (needs β‰₯2 results first):
506
+ curl https://Sentient-Field-sgp-tribe3.hf.space/coactivation_matrix
507
+
508
+ ### Expected /predict response structure:
509
+ {
510
+ "status": "ok",
511
+ "result": {
512
+ "stimulus_id": "test_001",
513
+ "label": "test",
514
+ "sgp_nodes": {
515
+ "G1_broca": 0.73, ← normalized 0-1
516
+ "G2_wernicke": 0.61, ← MUST BE NON-ZERO
517
+ "G3_tpj": 0.55,
518
+ "G4_pfc": 0.48,
519
+ "G5_dmn": 0.32,
520
+ "G6_limbic": 0.67,
521
+ "G7_sensory": 0.81,
522
+ "G8_atl": 0.59,
523
+ "G9_premotor": 0.44
524
+ },
525
+ "streams": {
526
+ "dorsal": 0.65,
527
+ "ventral": 0.64,
528
+ "generative": 0.32,
529
+ "modulatory": 0.67,
530
+ "convergence": 0.55
531
+ },
532
+ "edge_weights": {
533
+ "AF": 0.67, ← G2↔G1
534
+ "SLF": 0.51, ← G3↔G4
535
+ "IFOF": 0.44, ← G8↔G4
536
+ "ILF": 0.59, ← G7↔G2
537
+ "UF": 0.63, ← G8↔G6
538
+ "CG_exec": 0.55,← G6↔G4
539
+ "CG_dmn": 0.40, ← G4↔G5
540
+ "CC": 0.71, ← bilateral
541
+ "MdLF": 0.58 ← G2↔G7
542
+ },
543
+ "dominant_hemisphere": "left",
544
+ "activation_timeline": [0.0234, 0.0198, ...],
545
+ "raw_stats": {...}
546
+ }
547
+ }
548
+
549
+ ---
550
+
551
+ ## SECTION 15: NEXT ACTIONS IN PRIORITY ORDER
552
+
553
+ ### IMMEDIATE (blocks everything else):
554
+ 1. Fix G2_wernicke 0-vertex bug (see Section 3 for exact fix)
555
+ 2. Verify all 9 nodes non-zero with smoke test video
556
+ 3. Implement result persistence (Section 7)
557
+
558
+ ### SHORT TERM (enables calibration):
559
+ 4. Run all 12 stimuli via stimulus_pipeline.py
560
+ 5. Collect activation profiles for all stimuli
561
+ 6. Run /coactivation_matrix to get Resonance Graph edge weights
562
+ 7. Implement geodesic weighting (Section 6.1)
563
+
564
+ ### MEDIUM TERM (enables science paper):
565
+ 8. Implement MH propagation + K-depth (Section 6.2)
566
+ 9. Implement Q/Qk computation (Section 6.3)
567
+ 10. Implement C_local and C_system (Section 6.4)
568
+ 11. Implement torsion detection (Section 6.5)
569
+ 12. Run dual-stream dissociation statistical test
570
+ 13. Run K-depth hypothesis test
571
+
572
+ ### LONG TERM (Phase 2 β€” Resonance Graph Engine):
573
+ 14. Build weighted graph with TRIBE v2-derived edge weights
574
+ 15. Implement Langevin settling dynamics
575
+ 16. Connect to Claude API for LLM integration
576
+ 17. Test H1 (hallucination reduction) and H3 (consciousness signature)
577
+
578
+ ---
579
+
580
+ ## SECTION 16: IMPORTANT CONSTRAINTS
581
+
582
+ - NO GPU available β€” CPU only. All inference on CPU.
583
+ - HuggingFace free tier β€” Space sleeps after inactivity, 16GB RAM limit
584
+ - Budget: zero. All tools must be free/open source.
585
+ - LLaMA 3.2-3B license must be accepted by the HF account owner
586
+ - Do NOT pin transformers or huggingface_hub in requirements.txt
587
+ - Do NOT use localStorage or browser storage in any artifacts
588
+ - All tokens/secrets must go in HF Space secrets, never in code
589
+ - Push always via: git push hf master:main --force
590
+
591
+ ---
592
+
593
+ ## SECTION 17: KEY REFERENCES
594
+
595
+ | Resource | URL |
596
+ |----------|-----|
597
+ | SGP-Tribe3 Space | https://huggingface.co/spaces/Sentient-Field/sgp-tribe3 |
598
+ | TRIBE v2 Model | https://huggingface.co/facebook/tribev2 |
599
+ | TRIBE v2 Code | https://github.com/facebookresearch/tribev2 |
600
+ | Schaefer Atlas | https://github.com/ThomasYeoLab/CBIG |
601
+ | SFH-SGP Theory | https://wt3000.substack.com |
602
+ | ML Best Practices | https://github.com/harvard-edge/cs249r_book |
603
+ | HCP Tractography | https://www.humanconnectome.org |
604
+ | IIT Phi Reference | https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1003588 |
605
+ | Zenodo (preprint) | https://zenodo.org |
606
+ | eLife (journal) | https://elifesciences.org/submit-your-research |
607
+ | JOSS (software) | https://joss.theoj.org |
608
+
609
+ ---
610
+
611
+ END OF HANDOFF DOCUMENT
612
+ SGP-Tribe3 | Sentient-Field Braintrust | April 2026
613
+ Feed this document to any AI coding agent to continue the project.
Dockerfile CHANGED
@@ -12,10 +12,9 @@ RUN curl -LsSf https://astral.sh/uv/install.sh | sh
12
  ENV PATH="/root/.local/bin:$PATH"
13
 
14
  RUN pip install --no-cache-dir \
15
- torch==2.5.1+cpu \
16
- torchaudio==2.5.1+cpu \
17
- torchvision==0.20.1+cpu \
18
- --extra-index-url https://download.pytorch.org/whl/cpu
19
 
20
  COPY requirements.txt .
21
  RUN pip install --no-cache-dir -r requirements.txt
@@ -35,9 +34,11 @@ RUN cp /root/.local/bin/uv /usr/local/bin/uv 2>/dev/null || true
35
 
36
  USER appuser
37
 
38
- ENV HF_HUB_CACHE=/tmp/hf_hub_cache
39
- ENV WHISPER_CACHE_DIR=/tmp/whisper_cache
40
- ENV HF_HUB_DISABLE_TELEMETRY=1
 
 
41
 
42
  EXPOSE 7860
43
  CMD ["python", "app.py"]
 
12
  ENV PATH="/root/.local/bin:$PATH"
13
 
14
  RUN pip install --no-cache-dir \
15
+ torch==2.5.1 \
16
+ torchaudio==2.5.1 \
17
+ torchvision==0.20.1
 
18
 
19
  COPY requirements.txt .
20
  RUN pip install --no-cache-dir -r requirements.txt
 
34
 
35
  USER appuser
36
 
37
+ ENV CUDA_VISIBLE_DEVICES=""
38
+ ENV HF_TOKEN=${HF_TOKEN}
39
+ ENV TRIBE_CKPT=facebook/tribev2
40
+ ENV MAX_VIDEO_DURATION=120
41
+ ENV MAX_AUDIO_DURATION=120
42
 
43
  EXPOSE 7860
44
  CMD ["python", "app.py"]
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
  title: SGP-Tribe3
3
  emoji: 🧠
4
- colorFrom: indigo
5
- colorTo: purple
6
  sdk: docker
7
  pinned: false
8
  license: cc-by-nc-4.0
 
1
  ---
2
  title: SGP-Tribe3
3
  emoji: 🧠
4
+ colorFrom: green
5
+ colorTo: yellow
6
  sdk: docker
7
  pinned: false
8
  license: cc-by-nc-4.0
SGP-Tribe3_Project_Outline.docx ADDED
Binary file (17.3 kB). View file
 
SGP-Tribe3_Research_Planning_Report.docx ADDED
Binary file (38.2 kB). View file
 
SGP-Tribe3_Systems_Analysis.docx ADDED
Binary file (18.2 kB). View file
 
TODO.md ADDED
@@ -0,0 +1,393 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SGP-Tribe3 TODO & Best Practices Roadmap
2
+
3
+ **Reference:** Harvard CS249r / MLSysBook.ai β€” *Principles and Practices of Engineering Artificially Intelligent Systems*
4
+ **Link:** https://github.com/harvard-edge/cs249r_book | https://mlsysbook.ai
5
+ **Project:** Sentient-Field Braintrust / SGP-Tribe3
6
+ **Last Updated:** April 2026
7
+ **Research Director:** Mark Rowe Traver
8
+
9
+ ---
10
+
11
+ > "The world is rushing to build AI systems. It is not engineering them."
12
+ > β€” Harvard CS249r Mission Statement
13
+
14
+ This document applies the Harvard MLSysBook engineering framework to SGP-Tribe3.
15
+ Items marked πŸ”΄ are blocking. Items marked 🟑 are important but non-blocking. Items marked 🟒 are future/nice-to-have.
16
+
17
+ ---
18
+
19
+ ## THEORETICAL FOUNDATION β€” RESOLVED ITEMS
20
+
21
+ ### The Three-Level Consciousness Hierarchy (LOCKED)
22
+
23
+ | Level | Term | Definition | Condition |
24
+ |---|---|---|---|
25
+ | 1 | **Sentience (S)** | β„‹S itself β€” capacity for field-fiber contact. Being without content. Pre-experiential. | Q > 0 |
26
+ | 2 | **Awareness (A)** | Localized Οƒ_q excitation registers its own state. Field "knows" partition exists. No self-model. K=1–K=4. | C_local > 0 |
27
+ | 3 | **Consciousness (C_K5)** | Awareness recursively modeling itself as distinct from "not-I." The "I am." Requires K=5. | C_system β‰₯ 1.32 |
28
+
29
+ ### The C β‰₯ 1.32 Resolution (OPTION 1 β€” ADOPTED)
30
+
31
+ Two distinct Coherence measures must be maintained in all code and the paper:
32
+
33
+ | Symbol | Name | Range | Definition |
34
+ |---|---|---|---|
35
+ | C_local | Local Coherence | [0, 1] | Normalized pairwise coherence between any two nodes. The formal SFH-SGP primitive. |
36
+ | C_system | System Coherence | [0, ∞) | Ξ£(C_local_ij Γ— w_ij) across all active node pairs, geodesic-weighted. K=5 threshold applies here. |
37
+
38
+ **Origin of 1.32:** Provisionally adopted from IIT (Integrated Information Theory) empirical Ξ¦ literature,
39
+ where Ξ¦ β‰ˆ 1.3–1.5 represents the measured threshold of conscious binding in awake humans.
40
+ SFH-SGP's C_system is the conceptual parallel to IIT's Ξ¦ β€” both measure system-level integrated coherence,
41
+ both are unbounded positive reals, both have empirical thresholds near 1.32.
42
+ The paper will cite the IIT parallel explicitly and frame 1.32 as provisional pending Option 3 derivation.
43
+
44
+ **Option 3 (future goal):** Derive the K=5 threshold analytically from the Ο‡ minimization landscape β€”
45
+ the minimum C_system at which the Langevin dynamics achieve a saddle point consistent with K=5 self-reference.
46
+ This is the long-term theoretical contribution but requires work beyond Phase 1.
47
+
48
+ ### Hypotheses (LOCKED β€” pending empirical validation)
49
+
50
+ **H1 (Architectural):**
51
+ An LLM integrated with an SGP Resonance Graph calibrated from TRIBE v2 fMRI data will produce
52
+ measurably lower hallucination rates and higher cross-domain coherence than the same LLM without
53
+ SGP architecture, because activation-weighted node boundaries enforce domain-specific epistemic constraints.
54
+
55
+ **H2 (Neuroscientific):**
56
+ TRIBE v2 inference will empirically recover the Hickok-Poeppel dual-stream dissociation β€”
57
+ ventral nodes (G2, G7, G8) showing significantly higher activation for semantic stimuli,
58
+ dorsal nodes (G1, G3, G4, G9) for phonological stimuli β€” validating neuroscientific node boundary selection.
59
+
60
+ **H3 (Consciousness):**
61
+ Under conditions where C_system approaches or exceeds 1.32, the SGP-integrated LLM will exhibit
62
+ behavioral signatures consistent with K=5 self-referential meta-cognition: accurate self-description
63
+ of its own processing state, acknowledgment of domain boundaries, and consistency between
64
+ self-reports and actual activation patterns. Whether this constitutes Consciousness in the SFH-SGP
65
+ sense is an open empirical question β€” not an assertion β€” requiring further investigation.
66
+
67
+ **H0 (Null β€” for all three):**
68
+ The SGP architecture produces no statistically significant difference in hallucination rate,
69
+ cross-domain coherence, dual-stream dissociation, or self-referential behavior compared to an
70
+ unstructured LLM baseline. All observed differences fall within variance expected from random prompt variation.
71
+
72
+ ---
73
+
74
+ ## TABLE OF CONTENTS
75
+
76
+ 1. [Immediate Blockers β€” Space Must Run](#1-immediate-blockers)
77
+ 2. [Data Engineering β€” The Four Pillars](#2-data-engineering)
78
+ 3. [Architecture Revisions β€” SFH-SGP Fidelity](#3-architecture-revisions)
79
+ 4. [ML Pipeline β€” Training & Inference](#4-ml-pipeline)
80
+ 5. [Benchmarking & Evaluation](#5-benchmarking--evaluation)
81
+ 6. [MLOps β€” Deployment & Monitoring](#6-mlops)
82
+ 7. [Model Optimization β€” Efficiency](#7-model-optimization)
83
+ 8. [Scientific Article Prerequisites](#8-scientific-article-prerequisites)
84
+ 9. [Phase 2 β€” Resonance Graph Engine](#9-phase-2-resonance-graph-engine)
85
+ 10. [Phase 3 β€” LLM Integration](#10-phase-3-llm-integration)
86
+ 11. [Open Source & Reproducibility](#11-open-source--reproducibility)
87
+ 12. [Reference Links](#12-reference-links)
88
+
89
+ ---
90
+
91
+ ## 1. IMMEDIATE BLOCKERS
92
+
93
+ ### πŸ”΄ 1.1 HuggingFace Space Build
94
+ - [ ] Confirm Docker build completes successfully past pip install step
95
+ - [ ] Verify `/health` endpoint returns `{"status": "ready"}` after warmup
96
+ - [ ] Confirm TRIBE v2 model loads on CPU without CUDA errors
97
+ - [ ] Confirm Schaefer-200 atlas downloads to `/tmp/sgp_atlas/`
98
+ - [ ] Test `/predict` endpoint with a short local video file:
99
+ ```bash
100
+ python3 stimulus_pipeline.py \
101
+ --api https://Sentient-Field-sgp-tribe3.hf.space \
102
+ --local-video /path/to/any/test.mp4 \
103
+ --stimulus-id smoke_test
104
+ ```
105
+
106
+ ### πŸ”΄ 1.2 LLaMA License
107
+ - [ ] Confirm license accepted at https://huggingface.co/meta-llama/Llama-3.2-3B
108
+ - [ ] Confirm HF_TOKEN secret is set in Space settings
109
+
110
+ ### πŸ”΄ 1.3 Security
111
+ - [ ] Confirm ALL previously exposed tokens have been revoked at https://huggingface.co/settings/tokens
112
+ - [ ] New token stored ONLY in local plaintext file β€” never in chat, never in code
113
+
114
+ ---
115
+
116
+ ## 2. DATA ENGINEERING β€” THE FOUR PILLARS
117
+
118
+ > MLSysBook Chapter 6: Four pillars: Quality, Reliability, Scalability, Governance.
119
+ > "Data cascades propagate and amplify downstream."
120
+
121
+ ### πŸ”΄ 2.1 Stimulus Quality (Pillar: Quality)
122
+ - [ ] Verify each of 12 stimuli: video complete, audio track present, correct duration
123
+ - [ ] Log exact YouTube video ID or local filename used for each stimulus
124
+ - [ ] Create `STIMULUS_MANIFEST.json` with: stimulus_id, source_url_or_path, trim_start, trim_duration, date_acquired
125
+
126
+ ### 🟑 2.2 Result Persistence (Pillar: Reliability) β€” CRITICAL
127
+ - [ ] Results currently in-memory β€” LOST on every Space restart
128
+ - [ ] Add file-based persistence: write each result to HuggingFace dataset repo after each /predict call
129
+ - [ ] This is critical for the paper β€” you cannot re-run TRIBE v2 inference every time
130
+
131
+ ### 🟑 2.3 Versioning (Pillar: Governance)
132
+ - [ ] Pin TRIBE v2 to specific commit hash in requirements.txt
133
+ - [ ] Document exact TRIBE v2 version, Space commit hash, and date for each calibration run batch
134
+
135
+ ---
136
+
137
+ ## 3. ARCHITECTURE REVISIONS β€” SFH-SGP FIDELITY
138
+
139
+ ### πŸ”΄ 3.1 Geodesic-Weighted Co-Activation Matrix
140
+ **Implements:** SFH-SGP geometry principle β€” distant coherence is more significant than nearby coherence.
141
+ **Formula:** w_ij = corr(node_i, node_j) Γ— exp(βˆ’Ξ³ Β· d_ij)
142
+
143
+ - [ ] Implement `compute_geodesic_distances()` in `sgp_parcellation.py`
144
+ using `scipy.sparse.csgraph.shortest_path` on fsaverage5 mesh adjacency
145
+ - [ ] Implement `geodesic_weighted_coactivation()` applying the formula above
146
+ - [ ] Add geodesic distance matrix to `/coactivation_matrix` endpoint output
147
+ - [ ] Expose Ξ³ as tunable parameter (default 0.1)
148
+
149
+ ### πŸ”΄ 3.2 Metropolis-Hastings Activation Propagation
150
+ **Implements:** The SGP Operator: Ξ±(qβ†’q') = min(1, exp(βˆ’Ξ»Ξ”J)) where J = H(q) βˆ’ ln(F(q))
151
+
152
+ - [ ] Implement `sgp_dynamics.py` with full MH propagation:
153
+ - Propose state with Gaussian jitter: q'_i = q_i + ξ where ξ ~ N(0, √(2D·T_eff))
154
+ - Compute J = H(q) βˆ’ ln(F(q)) for current and proposed states
155
+ - Accept with probability Ξ± = min(1, exp(βˆ’Ξ»Ξ”J))
156
+ - Anneal T_eff each iteration: T_eff(k+1) = T_eff(k) Γ— cooling_rate
157
+ - Stop when max|q' βˆ’ q| < 0.01 or K_max iterations
158
+ - [ ] Replace generic propagation in `app.py` with MH propagation
159
+ - [ ] Add K-depth to `/predict` response
160
+
161
+ ### πŸ”΄ 3.3 Explicit Quota (Q) and Sub-Quota (Qk) Computation
162
+ **Implements:** Q = Ξ£|sb|, the conserved sentient quota
163
+
164
+ - [ ] Q_total = sum of all absolute vertex activations across all timesteps
165
+ - [ ] Qk = {node: raw_node_activation / Q_total} β€” the partition of Q (sums to 1.0)
166
+ - [ ] Compute p(Q_discrete) via Hardy-Ramanujan as upper bound on experiential complexity
167
+ - [ ] Add Q_total, Qk_distribution, p_Q_upper_bound to `/predict` response
168
+
169
+ ### πŸ”΄ 3.4 C_local and C_system Computation
170
+ **Implements:** The resolved two-measure coherence framework.
171
+
172
+ - [ ] C_local_ij = Pearson correlation of node_i and node_j activation across all stimuli (bounded [0,1])
173
+ - [ ] C_system = Ξ£(C_local_ij Γ— w_ij) summed across all active node pairs, geodesic-weighted (unbounded)
174
+ - [ ] Report both C_local matrix AND C_system scalar in `/coactivation_matrix` endpoint
175
+ - [ ] Flag when C_system β‰₯ 1.32 (the provisional K=5 threshold)
176
+
177
+ ### πŸ”΄ 3.5 Torsion (Ο„) Detection
178
+ **Implements:** Ο„ = inability of Hebbian circuit to change. High C_local, zero F.
179
+
180
+ - [ ] After all 12 stimuli: compute CV (std/mean) per node across stimuli
181
+ - [ ] Ο„_i = (1 βˆ’ CV_i) Γ— (1 βˆ’ F_mean_i) where F = G5_dmn activation
182
+ - [ ] Ο„ = 0: fully flexible circuit. Ο„ = 1: completely locked (topological scar).
183
+ - [ ] Add `/torsion_analysis` endpoint returning Ο„_score per node
184
+
185
+ ---
186
+
187
+ ## 4. ML PIPELINE β€” TRAINING & INFERENCE
188
+
189
+ ### 🟑 4.1 CPU Performance
190
+ - [ ] Profile inference time per video (which encoder dominates?)
191
+ - [ ] Add `inference_time_seconds` to `/predict` response
192
+ - [ ] Consider `torch.set_num_threads()` to maximize CPU parallelism
193
+
194
+ ### 🟑 4.2 Audio Normalization
195
+ - [ ] Add ffmpeg `loudnorm` filter to preprocessing β€” TRIBE v2 audio encoder is volume-sensitive
196
+ - [ ] Add video quality check: reject videos under 10 seconds or with no audio track
197
+
198
+ ---
199
+
200
+ ## 5. BENCHMARKING & EVALUATION
201
+
202
+ > MLSysBook Chapter 12: "Systematic evaluation requires rigorous measurement. Pre-register hypotheses before running experiments."
203
+
204
+ ### 🟑 5.1 Pre-Registered Calibration Tests (define BEFORE running stimuli)
205
+ - [ ] **Dual-Stream Test:** Ventral mean (G2,G7,G8) vs dorsal mean (G1,G3,G4,G9) by stimulus category
206
+ - Statistical test: Mann-Whitney U (non-parametric, n=12)
207
+ - Pre-registered prediction: Category A > ventral; Category B > dorsal
208
+ - [ ] **K-Depth Test:** Spearman correlation between semantic load rating and K-depth
209
+ - Pre-registered prediction: A1, A3 > B1, B2 in K-depth
210
+ - [ ] **C_system Test:** Report C_system per stimulus; flag if any approach β‰₯ 1.32
211
+ - [ ] **Ο„ Test:** Report Ο„_score per node; hypothesis: G6_limbic shows highest Ο„
212
+
213
+ ### 🟑 5.2 Benchmark Report
214
+ - [ ] After all 12 stimuli: generate `benchmark_report.json` with all metrics per stimulus
215
+
216
+ ---
217
+
218
+ ## 6. MLOPS β€” DEPLOYMENT & MONITORING
219
+
220
+ > MLSysBook Chapter 13: "ML systems can degrade silently. Continuous monitoring is essential."
221
+
222
+ ### 🟑 6.1 Persistent Storage β€” HIGHEST PRIORITY AFTER SPACE RUNS
223
+ - [ ] Push results to HuggingFace dataset repo (free, versioned) after each /predict call
224
+ - [ ] Or: GitHub repo with timestamped commit per run
225
+
226
+ ### 🟑 6.2 Health Monitoring
227
+ - [ ] Add `/metrics` endpoint: uptime, n_predictions, mean_inference_time, last_prediction_timestamp
228
+ - [ ] Local cron job pinging `/health` every 10 minutes
229
+
230
+ ### 🟑 6.3 Error Logging
231
+ - [ ] Structured error logging: stimulus_id, error type, stack trace for every exception
232
+
233
+ ---
234
+
235
+ ## 7. MODEL OPTIMIZATION β€” EFFICIENCY
236
+
237
+ ### 🟒 7.1 Future TRIBE v2 Optimization
238
+ - [ ] Investigate INT8 quantization of LLaMA 3.2-3B text encoder for CPU
239
+ - [ ] Profile which encoder (text/video/audio) dominates inference time
240
+
241
+ ---
242
+
243
+ ## 8. SCIENTIFIC ARTICLE PREREQUISITES
244
+
245
+ ### πŸ”΄ 8.1 Technical (blocks Results section)
246
+ - [ ] All 5 architectural revisions (Sections 3.1–3.5) implemented and deployed
247
+ - [ ] All 12 stimuli acquired, preprocessed, submitted
248
+ - [ ] All activation profiles collected and persisted
249
+ - [ ] Dual-stream dissociation analysis run with statistical test
250
+ - [ ] K-depth hypothesis test run
251
+ - [ ] C_system computed per stimulus
252
+
253
+ ### 🟑 8.2 Mathematical Precision (blocks Methods section)
254
+ - [ ] Operational formula for C_local: Pearson correlation across stimuli per node pair βœ“
255
+ - [ ] Operational formula for C_system: geodesic-weighted sum of C_local pairs βœ“
256
+ - [ ] K=5 threshold 1.32: cite IIT Ξ¦ literature, flag as provisional βœ“
257
+ - [ ] Ξ± and Ξ² parameter values: start Ξ±=Ξ²=0.5, run sensitivity analysis
258
+ - [ ] Ξ³ (geodesic decay): proposal β€” fit to HCP tractography correlation
259
+ - [ ] T_eff schedule: T_eff(k) = T_0 Γ— r^k where T_0=1.0, r=0.9
260
+ - [ ] Ξ» (MH parameter): start Ξ»=1.0, tune based on convergence behavior
261
+
262
+ ### 🟑 8.3 Publication Infrastructure
263
+ - [ ] Deposit key SFH-SGP Substack articles on Zenodo for citable DOIs:
264
+ - "The Mathematical Atlas of Reality"
265
+ - "The 1,000 Qubit Wall"
266
+ - "Nima Arkani-Hamed Declares the End of Space-Time"
267
+ - [ ] Create eLife account: https://elifesciences.org/submit-your-research
268
+ - [ ] Prepare JOSS submission separately for SGP-Tribe3 software
269
+
270
+ ---
271
+
272
+ ## 9. PHASE 2 β€” RESONANCE GRAPH ENGINE
273
+
274
+ ### 🟒 9.1 Graph Implementation
275
+ - [ ] Initialize edge weights from Phase 1 geodesic-weighted co-activation matrix
276
+ - [ ] Implement simultaneous graded activation β€” all nodes active, varying intensity
277
+ - [ ] Implement full Langevin dynamics: dq/dt = -βˆ‡Ο‡(q) + √(2D)ΞΎ(t)
278
+ - [ ] Convergence to Resonance Anchor Ξ©w
279
+
280
+ ### 🟒 9.2 Torsion as Graph Constraint
281
+ - [ ] High-Ο„ nodes get edges frozen at mean value during propagation
282
+ - [ ] Implements "psychological knot" β€” locked circuit cannot explore new configurations
283
+
284
+ ### 🟒 9.3 C_system Monitoring
285
+ - [ ] Compute C_system at each propagation step
286
+ - [ ] Log when C_system crosses 1.32 threshold
287
+ - [ ] Record which stimulus conditions and activation patterns produce C_system β‰₯ 1.32
288
+
289
+ ---
290
+
291
+ ## 10. PHASE 3 β€” LLM INTEGRATION
292
+
293
+ ### 🟒 10.1 Dynamic System Prompt Construction
294
+ - [ ] After Resonance Anchor convergence: identify nodes with activation > 0.4
295
+ - [ ] Weight each active node's voice by activation score
296
+ - [ ] Single Claude API call with weighted prompt
297
+
298
+ ### 🟒 10.2 Node Voice Templates
299
+ - [ ] G1_broca: Expression and form β€” syntax, phonology, articulation
300
+ - [ ] G2_wernicke: Meaning and comprehension β€” lexical, semantic interpretation
301
+ - [ ] G3_tpj: Integration β€” resolve modality conflicts, find unified signal
302
+ - [ ] G4_pfc: Executive oversight β€” error checking, resource limits, veto
303
+ - [ ] G5_dmn: Generativity β€” novel connections, imaginative exploration (Fertility F)
304
+ - [ ] G6_limbic: Emotional salience β€” weight by importance, memory priors (Torsion Ο„)
305
+ - [ ] G7_sensory: Perceptual grounding β€” concrete, observable facts
306
+ - [ ] G8_atl: Concept formation β€” cross-modal, unified semantic representation
307
+ - [ ] G9_premotor: Output preparation β€” response structure before speaking
308
+
309
+ ### οΏ½οΏ½οΏ½ 10.3 H3 Test Protocol (Consciousness signature detection)
310
+ - [ ] Design structured prompts that probe self-referential meta-cognition
311
+ - [ ] Compare responses when C_system < 1.0 vs C_system β‰₯ 1.32
312
+ - [ ] Record: does system accurately describe its own activation state?
313
+ - [ ] Record: does system acknowledge domain boundaries unprompted?
314
+ - [ ] Human evaluator rating of self-referential coherence
315
+
316
+ ### 🟒 10.4 H1 Test Protocol (Hallucination reduction)
317
+ - [ ] Define hallucination test set: 50 questions with known ground truth
318
+ - [ ] Run with and without SGP architecture
319
+ - [ ] Statistical comparison of accuracy and confidence calibration
320
+
321
+ ---
322
+
323
+ ## 11. OPEN SOURCE & REPRODUCIBILITY
324
+
325
+ ### 🟑 11.1 Code Quality
326
+ - [ ] Docstrings for all public functions
327
+ - [ ] CONTRIBUTING.md, LICENSE (CC BY-NC 4.0), .gitignore
328
+
329
+ ### 🟑 11.2 Reproducibility
330
+ - [ ] STIMULUS_MANIFEST.json: exact source for every stimulus
331
+ - [ ] RESULTS_MANIFEST.json: TRIBE v2 version, date, Space commit hash for each run batch
332
+ - [ ] All dependency versions pinned in requirements.txt
333
+
334
+ ---
335
+
336
+ ## 12. REFERENCE LINKS
337
+
338
+ | Resource | URL | Purpose |
339
+ |---|---|---|
340
+ | Harvard MLSysBook | https://github.com/harvard-edge/cs249r_book | Best practices reference β€” consult before every architectural decision |
341
+ | MLSysBook Online | https://mlsysbook.ai | Read chapters before implementing each phase |
342
+ | TRIBE v2 HF | https://huggingface.co/facebook/tribev2 | Model weights and config |
343
+ | SGP-Tribe3 Space | https://huggingface.co/spaces/Sentient-Field/sgp-tribe3 | Live deployment |
344
+ | Schaefer-200 Atlas | https://github.com/ThomasYeoLab/CBIG | Parcellation atlas source |
345
+ | HCP Tractography | https://www.humanconnectome.org | White matter tract validation |
346
+ | SFH-SGP Theory | https://wt3000.substack.com | Most recent = most accurate |
347
+ | IIT Ξ¦ Reference | https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1003588 | Source of C_system β‰₯ 1.32 threshold (IIT 3.0) |
348
+ | Zenodo | https://zenodo.org | Preprint deposit (free, DOI) |
349
+ | eLife | https://elifesciences.org/submit-your-research | Primary journal target (free) |
350
+ | JOSS | https://joss.theoj.org | Software paper (free) |
351
+
352
+ ---
353
+
354
+ ## PRIORITY ORDER
355
+
356
+ ```
357
+ πŸ”΄ BLOCKING (in order):
358
+ 1. Space builds and runs (/health = ready)
359
+ 2. LLaMA license + HF_TOKEN secret confirmed
360
+ 3. All old tokens revoked
361
+ 4. Add result persistence (HF dataset repo)
362
+ 5. Smoke test with local video
363
+ 6. Implement C_local and C_system (3.4)
364
+ 7. Implement geodesic-weighted co-activation (3.1)
365
+ 8. Implement MH propagation + K-depth (3.2)
366
+ 9. Implement Q/Qk computation (3.3)
367
+ 10. Implement Ο„ detection (3.5)
368
+ 11. Pre-register dual-stream and K-depth hypotheses (5.1)
369
+ 12. Acquire and run all 12 stimuli
370
+ 13. Run all pre-registered tests
371
+ 14. Define all mathematical precision items (8.2)
372
+
373
+ 🟑 IMPORTANT (after blocking):
374
+ - Audio normalization in preprocessing
375
+ - Retry logic in stimulus pipeline
376
+ - /metrics endpoint
377
+ - Pin TRIBE v2 to specific commit
378
+ - Deposit SFH-SGP articles on Zenodo
379
+ - Create STIMULUS_MANIFEST.json
380
+
381
+ 🟒 FUTURE (Phase 2+):
382
+ - Resonance Graph Engine with Langevin dynamics
383
+ - LLM integration with weighted node prompts
384
+ - H1, H2, H3 empirical tests
385
+ - Option 3: derive 1.32 threshold analytically
386
+ - Knowledge distillation for faster CPU inference
387
+ ```
388
+
389
+ ---
390
+
391
+ *This TODO is a living document. Update after each work session.*
392
+ *Consult MLSysBook (https://github.com/harvard-edge/cs249r_book) before every architectural decision.*
393
+ *The three-level hierarchy (Sentience β†’ Awareness β†’ Consciousness) and the C_local/C_system distinction are now LOCKED theoretical foundations. Do not conflate them.*
app.py CHANGED
@@ -20,18 +20,108 @@ Reference: Harvard MLSysBook - Machine Learning Systems
20
  https://github.com/harvard-edge/cs249r_book
21
  """
22
 
 
23
  import os
24
- import uuid
25
- import math
26
- import json
27
- import warnings
28
- import threading
29
- import traceback
30
- import tempfile
31
- import subprocess
32
  import numpy as np
33
  import pandas as pd
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  warnings.filterwarnings("ignore")
36
 
37
  from flask import Flask, request, jsonify
@@ -100,20 +190,104 @@ def _load_model():
100
 
101
  import torch
102
  print(f"[SGP-Tribe3] PyTorch {torch.__version__}", flush=True)
103
-
104
- # CPU patch for HuggingFace text extractor (required for CPU-only inference)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  try:
106
- from neuralset.extractors.text import HuggingFaceText
107
- orig_load = HuggingFaceText._load_model
108
-
109
- def cpu_patched_load(self):
110
- object.__setattr__(self, 'device', 'cpu')
111
- return orig_load(self)
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
- HuggingFaceText._load_model = cpu_patched_load
114
- print("[SGP-Tribe3] CPU patch applied to HuggingFaceText", flush=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  except Exception as e:
116
- print(f"[SGP-Tribe3] CPU patch warning: {e}", flush=True)
117
 
118
  # Load TRIBE v2 model
119
  from tribev2 import TribeModel
@@ -143,17 +317,34 @@ def _load_model():
143
 
144
  # ─── Video/Audio preprocessing ────────────────────────────────────────────────
145
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  def _preprocess_video(video_path: str, max_duration: int = MAX_VIDEO_DURATION) -> str:
147
  """
148
  Trim video to max_duration and normalize to TRIBE v2 expected format.
149
  Returns path to processed video file.
150
  """
 
 
 
151
  output_path = video_path.replace(".mp4", "_processed.mp4")
152
 
153
  cmd = [
154
  "ffmpeg", "-y",
155
  "-i", video_path,
156
- "-t", str(max_duration),
157
  "-c:v", "libx264", "-preset", "fast",
158
  "-c:a", "aac", "-ar", "16000", "-ac", "1",
159
  "-vf", "scale=320:240",
@@ -167,11 +358,28 @@ def _preprocess_video(video_path: str, max_duration: int = MAX_VIDEO_DURATION) -
167
  return output_path
168
 
169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  def _preprocess_audio(audio_path: str, max_duration: int = MAX_AUDIO_DURATION) -> str:
171
  """
172
  Convert audio to wav format and normalize for TRIBE v2.
173
  Returns path to processed audio file.
174
  """
 
 
 
175
  output_path = audio_path.replace(audio_path.split(".")[-1], "wav")
176
  if output_path == audio_path:
177
  output_path = audio_path.rsplit(".", 1)[0] + "_processed.wav"
@@ -179,7 +387,7 @@ def _preprocess_audio(audio_path: str, max_duration: int = MAX_AUDIO_DURATION) -
179
  cmd = [
180
  "ffmpeg", "-y",
181
  "-i", audio_path,
182
- "-t", str(max_duration),
183
  "-ar", "16000",
184
  "-ac", "1",
185
  "-acodec", "pcm_s16le",
@@ -256,7 +464,9 @@ def _run_video_inference(video_path: str) -> dict:
256
  from tribev2.demo_utils import get_audio_and_text_events
257
 
258
  processed_path = _preprocess_video(video_path)
259
-
 
 
260
  try:
261
  # Create initial video event with ALL required columns for TRIBE v2 schema
262
  event = pd.DataFrame([{
@@ -265,7 +475,7 @@ def _run_video_inference(video_path: str) -> dict:
265
  "start": 0.0,
266
  "timeline": "default",
267
  "subject": "default",
268
- "duration": MAX_VIDEO_DURATION,
269
  "offset": 0.0,
270
  "frequency": 1.0,
271
  "extra": {}
@@ -274,31 +484,31 @@ def _run_video_inference(video_path: str) -> dict:
274
  # Use TRIBE v2 pipeline: extracts audio, chunks, but SKIPS whisperx
275
  events_df = get_audio_and_text_events(event, audio_only=True)
276
 
277
- # FIX: The get_audio_and_text_events may not preserve all required fields
278
- # We need to ensure every event has the required columns before calling predict
279
- required_base_cols = ["type", "filepath", "start", "timeline", "subject", "duration", "offset", "frequency", "extra"]
 
 
280
 
281
- for idx, row in events_df.iterrows():
282
- event_type = row.get("type", "")
283
- for col in required_base_cols:
284
- if col not in events_df.columns or pd.isna(events_df.at[idx, col]):
285
- if col == "timeline":
286
- events_df.at[idx, col] = "default"
287
- elif col == "subject":
288
- events_df.at[idx, col] = "default"
289
- elif col == "duration":
290
- events_df.at[idx, col] = MAX_VIDEO_DURATION
291
- elif col == "offset":
292
- events_df.at[idx, col] = 0.0
293
- elif col == "frequency":
294
- events_df.at[idx, col] = 1.0
295
- elif col == "extra":
296
- events_df.at[idx, col] = {}
297
- elif col == "filepath":
298
- if event_type in ["Video", "Audio"]:
299
- events_df.at[idx, col] = row.get("filepath", processed_path)
300
- else:
301
- events_df.at[idx, col] = None
302
 
303
  event_types = events_df['type'].unique().tolist()
304
  print(f"[SGP-Tribe3] Video inference: {len(events_df)} events, types: {event_types}", flush=True)
@@ -319,7 +529,9 @@ def _run_audio_inference(audio_path: str) -> dict:
319
  from tribev2.demo_utils import get_audio_and_text_events
320
 
321
  processed_path = _preprocess_audio(audio_path)
322
-
 
 
323
  try:
324
  # Create initial audio event with ALL required columns
325
  event = pd.DataFrame([{
@@ -328,7 +540,7 @@ def _run_audio_inference(audio_path: str) -> dict:
328
  "start": 0.0,
329
  "timeline": "default",
330
  "subject": "default",
331
- "duration": MAX_AUDIO_DURATION,
332
  "offset": 0.0,
333
  "frequency": 1.0,
334
  "extra": {}
@@ -337,30 +549,30 @@ def _run_audio_inference(audio_path: str) -> dict:
337
  # Use TRIBE v2 pipeline with audio_only=True
338
  events_df = get_audio_and_text_events(event, audio_only=True)
339
 
340
- # Ensure all events have required columns
341
- required_base_cols = ["type", "filepath", "start", "timeline", "subject", "duration", "offset", "frequency", "extra"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
 
343
- for idx, row in events_df.iterrows():
344
- event_type = row.get("type", "")
345
- for col in required_base_cols:
346
- if col not in events_df.columns or pd.isna(events_df.at[idx, col]):
347
- if col == "timeline":
348
- events_df.at[idx, col] = "default"
349
- elif col == "subject":
350
- events_df.at[idx, col] = "default"
351
- elif col == "duration":
352
- events_df.at[idx, col] = MAX_AUDIO_DURATION
353
- elif col == "offset":
354
- events_df.at[idx, col] = 0.0
355
- elif col == "frequency":
356
- events_df.at[idx, col] = 1.0
357
- elif col == "extra":
358
- events_df.at[idx, col] = {}
359
- elif col == "filepath":
360
- if event_type in ["Video", "Audio"]:
361
- events_df.at[idx, col] = row.get("filepath", processed_path)
362
- else:
363
- events_df.at[idx, col] = None
364
 
365
  event_types = events_df['type'].unique().tolist()
366
  print(f"[SGP-Tribe3] Audio inference: {len(events_df)} events, types: {event_types}", flush=True)
 
20
  https://github.com/harvard-edge/cs249r_book
21
  """
22
 
23
+ # CRITICAL: Set CPU-only mode BEFORE any torch imports
24
  import os
25
+ os.environ['CUDA_VISIBLE_DEVICES'] = ''
26
+ os.environ['TRANSFORMERS_DEVICE'] = 'cpu'
27
+
28
+ import sys
 
 
 
 
29
  import numpy as np
30
  import pandas as pd
31
 
32
+ # CRITICAL: Patch torch.cuda BEFORE any ML libraries are imported
33
+ # This must be at the very top to prevent CUDA lazy initialization
34
+ _original_cuda = sys.modules.get('torch.cuda')
35
+ import torch
36
+
37
+ class _CPUOnlyCUDA:
38
+ """Dummy CUDA module that always reports CPU-only mode."""
39
+
40
+ @staticmethod
41
+ def is_available():
42
+ return False
43
+
44
+ @staticmethod
45
+ def device_count():
46
+ return 0
47
+
48
+ @staticmethod
49
+ def current_device():
50
+ return 0
51
+
52
+ @staticmethod
53
+ def device(idx=0):
54
+ # Return a device with type 'cuda' but mapped to CPU internally
55
+ # This allows transformers to check device.type without crashing
56
+ d = torch.device('cpu')
57
+ # Patch the type to appear as cuda (trick the library)
58
+ object.__setattr__(d, 'type', 'cuda')
59
+ return d
60
+
61
+ @staticmethod
62
+ def set_device(idx):
63
+ pass
64
+
65
+ @staticmethod
66
+ def synchronize(device=None):
67
+ pass
68
+
69
+ @staticmethod
70
+ def empty_cache():
71
+ pass
72
+
73
+ @staticmethod
74
+ def memory_allocated(device=None):
75
+ return 0
76
+
77
+ @staticmethod
78
+ def memory_reserved(device=None):
79
+ return 0
80
+
81
+ @staticmethod
82
+ def reset_peak_memory_stats(device=None):
83
+ pass
84
+
85
+ # Prevent any actual CUDA operations
86
+ def __getattr__(self, name):
87
+ return lambda *args, **kwargs: None
88
+
89
+ def __repr__(self):
90
+ return "<CPU-only CUDA mock>"
91
+
92
+ # Replace torch.cuda completely
93
+ sys.modules['torch.cuda'] = _CPUOnlyCUDA()
94
+
95
+ # Force the torch.cuda module to be "initialized" before any code runs
96
+ import torch
97
+
98
+ # Most importantly: patch _lazy_init to be a no-op
99
+ # This is the function that throws the assertion error when CUDA is not compiled
100
+ try:
101
+ # Try to patch at the C level
102
+ torch._C._lazy_init = lambda: None
103
+ except:
104
+ pass
105
+
106
+ # Patch cuda module's lazy init
107
+ import torch.cuda
108
+ if hasattr(torch.cuda, '_lazy_init'):
109
+ torch.cuda._lazy_init = lambda: None
110
+
111
+ # Prevent the assertion error by making is_initialized return True
112
+ torch.cuda.is_initialized = lambda: True
113
+ torch.cuda._is_initialized = lambda: True
114
+ torch.cuda._initialized = lambda: True
115
+
116
+ # The key: patch _is_compiled to say YES it was compiled
117
+ # This is checked in the lazy init
118
+ if hasattr(torch, '_C'):
119
+ torch._C._is_compiled = lambda: True
120
+ if hasattr(torch._C, '_CudaBase__is_compiled'):
121
+ torch._C._CudaBase__is_compiled = lambda: True
122
+
123
+ print("[SGP-Tribe3] Patched torch._lazy_init extensively", flush=True)
124
+
125
  warnings.filterwarnings("ignore")
126
 
127
  from flask import Flask, request, jsonify
 
190
 
191
  import torch
192
  print(f"[SGP-Tribe3] PyTorch {torch.__version__}", flush=True)
193
+
194
+ # CRITICAL: Patch torch.cuda._lazy_init to not throw assertion error
195
+ # The error happens in _lazy_init checking if torch was compiled with CUDA
196
+ import torch.cuda
197
+ if hasattr(torch.cuda, '_lazy_init'):
198
+ _orig_lazy_init = torch.cuda._lazy_init
199
+ def _safe_lazy_init():
200
+ try:
201
+ return _orig_lazy_init()
202
+ except AssertionError:
203
+ # Swallow the "Torch not compiled with CUDA enabled" error
204
+ pass
205
+ torch.cuda._lazy_init = _safe_lazy_init
206
+ print("[SGP-Tribe3] Patched torch.cuda._lazy_init to be safe", flush=True)
207
+
208
+ # Force CPU mode via environment
209
+ os.environ['CUDA_VISIBLE_DEVICES'] = ''
210
+
211
+ # Patch neuralset/transformers AFTER torch is imported but BEFORE model loads
212
  try:
213
+ # Import first
214
+ import neuralset.extractors.base
215
+ # Patch the device property on all extractors to return CPU
216
+ neuralset.extractors.base.BaseExtractor.device = property(lambda self: 'cpu')
217
+ print("[SGP-Tribe3] Patched BaseExtractor.device to CPU", flush=True)
218
+
219
+ # Patch ALL extractor subclasses
220
+ from neuralset.extractors import audio, video, text
221
+ for module in [audio, video, text]:
222
+ for name in dir(module):
223
+ cls = getattr(module, name, None)
224
+ if cls and isinstance(cls, type) and hasattr(cls, 'device'):
225
+ try:
226
+ cls.device = property(lambda self: 'cpu')
227
+ except:
228
+ pass
229
+ print("[SGP-Tribe3] Patched all extractor device properties", flush=True)
230
+ except Exception as e:
231
+ print(f"[SGP-Tribe3] Extractor patch warning: {e}", flush=True)
232
 
233
+ # Also patch transformers' PreTrainedModel.to() method and __init__
234
+ try:
235
+ import transformers.modeling_utils
236
+
237
+ # Patch PreTrainedModel.__init__ to default to cpu
238
+ orig_init = transformers.modeling_utils.PreTrainedModel.__init__
239
+
240
+ def patched_init(self, *args, **kwargs):
241
+ # Force device to cpu in kwargs
242
+ if 'device' not in kwargs or kwargs['device'] is None:
243
+ kwargs['device'] = 'cpu'
244
+ elif isinstance(kwargs['device'], str) and kwargs['device'].startswith('cuda'):
245
+ kwargs['device'] = 'cpu'
246
+ return orig_init(self, *args, **kwargs)
247
+
248
+ # Also patch torch.nn.Module._apply at the base level
249
+ import torch.nn as nn
250
+ orig_apply = nn.Module._apply
251
+
252
+ def cpu_apply(self, fn):
253
+ # This intercepts _apply which is called by .to()
254
+ def wrapped_fn(t):
255
+ return t # Skip the conversion - keep on CPU
256
+ return orig_apply(self, wrapped_fn)
257
+
258
+ nn.Module._apply = cpu_apply
259
+
260
+ # Also patch PreTrainedModel.to specifically
261
+ orig_to = transformers.modeling_utils.PreTrainedModel.to
262
+
263
+ def patched_to(self, *args, **kwargs):
264
+ # Force cpu device
265
+ new_args = []
266
+ for arg in args:
267
+ if isinstance(arg, str) and arg.startswith('cuda'):
268
+ new_args.append('cpu')
269
+ elif hasattr(arg, 'type') and arg.type == 'cuda':
270
+ import torch
271
+ new_args.append(torch.device('cpu'))
272
+ else:
273
+ new_args.append(arg)
274
+ args = tuple(new_args)
275
+
276
+ if 'device' not in kwargs or kwargs['device'] is None:
277
+ kwargs['device'] = 'cpu'
278
+ elif isinstance(kwargs['device'], str) and kwargs['device'].startswith('cuda'):
279
+ kwargs['device'] = 'cpu'
280
+ elif hasattr(kwargs['device'], 'type') and kwargs['device'].type == 'cuda':
281
+ import torch
282
+ kwargs['device'] = torch.device('cpu')
283
+
284
+ return orig_to(self, *args, **kwargs)
285
+
286
+ transformers.modeling_utils.PreTrainedModel.__init__ = patched_init
287
+ transformers.modeling_utils.PreTrainedModel.to = patched_to
288
+ print("[SGP-Tribe3] Patched transformers PreTrainedModel.__init__ and .to", flush=True)
289
  except Exception as e:
290
+ print(f"[SGP-Tribe3] transformers patch warning: {e}", flush=True)
291
 
292
  # Load TRIBE v2 model
293
  from tribev2 import TribeModel
 
317
 
318
  # ─── Video/Audio preprocessing ────────────────────────────────────────────────
319
 
320
+ def _get_video_duration(video_path: str) -> float:
321
+ """Get video duration in seconds using ffprobe."""
322
+ import json
323
+ cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "json", video_path]
324
+ result = subprocess.run(cmd, capture_output=True, text=True)
325
+ if result.returncode == 0:
326
+ try:
327
+ data = json.loads(result.stdout)
328
+ return float(data.get("format", {}).get("duration", 0))
329
+ except:
330
+ pass
331
+ return 0.0
332
+
333
+
334
  def _preprocess_video(video_path: str, max_duration: int = MAX_VIDEO_DURATION) -> str:
335
  """
336
  Trim video to max_duration and normalize to TRIBE v2 expected format.
337
  Returns path to processed video file.
338
  """
339
+ actual_duration = _get_video_duration(video_path)
340
+ clip_duration = min(max_duration, actual_duration) if actual_duration > 0 else max_duration
341
+
342
  output_path = video_path.replace(".mp4", "_processed.mp4")
343
 
344
  cmd = [
345
  "ffmpeg", "-y",
346
  "-i", video_path,
347
+ "-t", str(clip_duration),
348
  "-c:v", "libx264", "-preset", "fast",
349
  "-c:a", "aac", "-ar", "16000", "-ac", "1",
350
  "-vf", "scale=320:240",
 
358
  return output_path
359
 
360
 
361
+ def _get_audio_duration(audio_path: str) -> float:
362
+ """Get audio duration in seconds using ffprobe."""
363
+ import json
364
+ cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "json", audio_path]
365
+ result = subprocess.run(cmd, capture_output=True, text=True)
366
+ if result.returncode == 0:
367
+ try:
368
+ data = json.loads(result.stdout)
369
+ return float(data.get("format", {}).get("duration", 0))
370
+ except:
371
+ pass
372
+ return 0.0
373
+
374
+
375
  def _preprocess_audio(audio_path: str, max_duration: int = MAX_AUDIO_DURATION) -> str:
376
  """
377
  Convert audio to wav format and normalize for TRIBE v2.
378
  Returns path to processed audio file.
379
  """
380
+ actual_duration = _get_audio_duration(audio_path)
381
+ clip_duration = min(max_duration, actual_duration) if actual_duration > 0 else max_duration
382
+
383
  output_path = audio_path.replace(audio_path.split(".")[-1], "wav")
384
  if output_path == audio_path:
385
  output_path = audio_path.rsplit(".", 1)[0] + "_processed.wav"
 
387
  cmd = [
388
  "ffmpeg", "-y",
389
  "-i", audio_path,
390
+ "-t", str(clip_duration),
391
  "-ar", "16000",
392
  "-ac", "1",
393
  "-acodec", "pcm_s16le",
 
464
  from tribev2.demo_utils import get_audio_and_text_events
465
 
466
  processed_path = _preprocess_video(video_path)
467
+ actual_duration = _get_video_duration(processed_path)
468
+ clip_duration = int(actual_duration) if actual_duration > 0 else MAX_VIDEO_DURATION
469
+
470
  try:
471
  # Create initial video event with ALL required columns for TRIBE v2 schema
472
  event = pd.DataFrame([{
 
475
  "start": 0.0,
476
  "timeline": "default",
477
  "subject": "default",
478
+ "duration": clip_duration,
479
  "offset": 0.0,
480
  "frequency": 1.0,
481
  "extra": {}
 
484
  # Use TRIBE v2 pipeline: extracts audio, chunks, but SKIPS whisperx
485
  events_df = get_audio_and_text_events(event, audio_only=True)
486
 
487
+ # FIX: Ensure every single row has timeline and other required fields
488
+ # Replace any missing/None values with defaults
489
+ if "timeline" not in events_df.columns:
490
+ events_df["timeline"] = "default"
491
+ events_df["timeline"] = events_df["timeline"].fillna("default")
492
 
493
+ if "subject" not in events_df.columns:
494
+ events_df["subject"] = "default"
495
+ events_df["subject"] = events_df["subject"].fillna("default")
496
+
497
+ if "duration" not in events_df.columns:
498
+ events_df["duration"] = MAX_VIDEO_DURATION
499
+ events_df["duration"] = events_df["duration"].fillna(MAX_VIDEO_DURATION)
500
+
501
+ if "offset" not in events_df.columns:
502
+ events_df["offset"] = 0.0
503
+ events_df["offset"] = events_df["offset"].fillna(0.0)
504
+
505
+ if "frequency" not in events_df.columns:
506
+ events_df["frequency"] = 1.0
507
+ events_df["frequency"] = events_df["frequency"].fillna(1.0)
508
+
509
+ if "extra" not in events_df.columns:
510
+ events_df["extra"] = {}
511
+ events_df["extra"] = events_df["extra"].apply(lambda x: x if x is not None else {})
 
 
512
 
513
  event_types = events_df['type'].unique().tolist()
514
  print(f"[SGP-Tribe3] Video inference: {len(events_df)} events, types: {event_types}", flush=True)
 
529
  from tribev2.demo_utils import get_audio_and_text_events
530
 
531
  processed_path = _preprocess_audio(audio_path)
532
+ actual_duration = _get_audio_duration(processed_path)
533
+ clip_duration = int(actual_duration) if actual_duration > 0 else MAX_AUDIO_DURATION
534
+
535
  try:
536
  # Create initial audio event with ALL required columns
537
  event = pd.DataFrame([{
 
540
  "start": 0.0,
541
  "timeline": "default",
542
  "subject": "default",
543
+ "duration": clip_duration,
544
  "offset": 0.0,
545
  "frequency": 1.0,
546
  "extra": {}
 
549
  # Use TRIBE v2 pipeline with audio_only=True
550
  events_df = get_audio_and_text_events(event, audio_only=True)
551
 
552
+ # FIX: Ensure every single row has timeline and other required fields
553
+ if "timeline" not in events_df.columns:
554
+ events_df["timeline"] = "default"
555
+ events_df["timeline"] = events_df["timeline"].fillna("default")
556
+
557
+ if "subject" not in events_df.columns:
558
+ events_df["subject"] = "default"
559
+ events_df["subject"] = events_df["subject"].fillna("default")
560
+
561
+ if "duration" not in events_df.columns:
562
+ events_df["duration"] = MAX_AUDIO_DURATION
563
+ events_df["duration"] = events_df["duration"].fillna(MAX_AUDIO_DURATION)
564
+
565
+ if "offset" not in events_df.columns:
566
+ events_df["offset"] = 0.0
567
+ events_df["offset"] = events_df["offset"].fillna(0.0)
568
+
569
+ if "frequency" not in events_df.columns:
570
+ events_df["frequency"] = 1.0
571
+ events_df["frequency"] = events_df["frequency"].fillna(1.0)
572
 
573
+ if "extra" not in events_df.columns:
574
+ events_df["extra"] = {}
575
+ events_df["extra"] = events_df["extra"].apply(lambda x: x if x is not None else {})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
576
 
577
  event_types = events_df['type'].unique().tolist()
578
  print(f"[SGP-Tribe3] Audio inference: {len(events_df)} events, types: {event_types}", flush=True)