VISHAL18for4 commited on
Commit
d1c8abb
·
verified ·
1 Parent(s): 5d72472

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -687
app.py DELETED
@@ -1,687 +0,0 @@
1
- import gradio as gr
2
- import threading, time, json
3
- from datetime import datetime, UTC
4
- from collections import deque
5
- from pathlib import Path
6
-
7
- from neural_network import LivingNetwork, CATEGORIES as TEXT_CATS, KNOWLEDGE_FILE
8
- from data_fetcher import DataFetcher
9
- from image_fetcher import ImageFetcher, IMAGE_DIR, CATEGORIES as IMG_CATS
10
- from image_model import LivingImageNetwork
11
- from chatbot import RAGChatbot
12
-
13
- # ── globals ──────────────────────────────────────────────────────────────────
14
- network = LivingNetwork()
15
- fetcher = DataFetcher()
16
- img_fetcher = ImageFetcher()
17
- img_network = LivingImageNetwork()
18
- chatbot = RAGChatbot()
19
-
20
- app_log = deque(maxlen=300)
21
- is_alive = False
22
- img_alive = False
23
-
24
- def log(msg):
25
- app_log.appendleft(f"[{datetime.now(UTC).strftime('%H:%M:%S')}] {msg}")
26
-
27
- log("🧠 Text network ready")
28
- log("👁️ Image CNN ready")
29
- kf = network.get_knowledge_file_stats()
30
- if kf['exists']: log(f"📚 Restored {kf['lines']} articles from knowledge.jsonl")
31
- if network.epoch: log(f"✅ Text model: epoch {network.epoch:,}")
32
- if img_network.epoch: log(f"✅ Image CNN: epoch {img_network.epoch:,}")
33
-
34
- # ── background loops ─────────────────────────────────────────────────────────
35
- def text_loop():
36
- global is_alive
37
- lf = ls = 0
38
- log("🚀 Text network LIVE")
39
- while is_alive:
40
- now = time.time()
41
- if now - lf >= 40:
42
- try:
43
- items = fetcher.fetch_round()
44
- for it in items:
45
- network.ingest(it['text'], it['category'], source=it.get('source','web'))
46
- kf2 = network.get_knowledge_file_stats()
47
- log(f"📡 +{len(items)} articles | knowledge: {kf2['lines']}")
48
- lf = now
49
- except Exception as e:
50
- log(f"⚠ fetch: {str(e)[:50]}")
51
- if network.stats['buffer_size'] >= 32 and network.vocab.is_built:
52
- r = network.train_n_steps(80)
53
- if r['steps']:
54
- s = network.stats
55
- log(f"📝 Epoch {s['epoch']:,} loss {s['loss']} acc {s['accuracy']}%")
56
- else:
57
- log(f"⏳ need {max(0,32-network.stats['buffer_size'])} more items")
58
- if now - ls >= 180:
59
- network.save_checkpoint(); log("💾 saved"); ls = now
60
- time.sleep(2)
61
- log("⏹ text stopped")
62
-
63
- def image_loop():
64
- global img_alive
65
- lf = ls = 0
66
- log("🚀 Image CNN LIVE")
67
- while img_alive:
68
- now = time.time()
69
- if now - lf >= 60:
70
- try:
71
- r = img_fetcher.fetch_round()
72
- log(f"🖼️ +{r['downloaded']} images | total {r['total']}")
73
- lf = now
74
- except Exception as e:
75
- log(f"⚠ img fetch: {str(e)[:50]}")
76
- if img_fetcher.get_stats()['total'] >= 16:
77
- r = img_network.train_n_steps(IMAGE_DIR, 20)
78
- if r['steps']:
79
- s = img_network.stats
80
- log(f"👁️ CNN epoch {s['epoch']:,} loss {s['loss']} acc {s['accuracy']}%")
81
- else:
82
- log(f"⏳ img CNN needs {max(0,16-img_fetcher.get_stats()['total'])} more images")
83
- if now - ls >= 180:
84
- img_network._save_checkpoint(); log("💾 img saved"); ls = now
85
- time.sleep(3)
86
- log("⏹ image stopped")
87
-
88
- # ── controls ──────────────────────────────────────────────────────────────────
89
- def start_text():
90
- global is_alive
91
- if is_alive: return "⚠ already running"
92
- is_alive = True
93
- threading.Thread(target=text_loop, daemon=True).start()
94
- return "🟢 text network LIVE"
95
-
96
- def stop_text():
97
- global is_alive; is_alive = False
98
- network.save_checkpoint(); return "🔴 stopped + saved"
99
-
100
- def start_img():
101
- global img_alive
102
- if img_alive: return "⚠ already running"
103
- img_alive = True
104
- threading.Thread(target=image_loop, daemon=True).start()
105
- return "🟢 image CNN LIVE"
106
-
107
- def stop_img():
108
- global img_alive; img_alive = False
109
- img_network._save_checkpoint(); return "🔴 stopped + saved"
110
-
111
- def do_fetch_text():
112
- items = fetcher.fetch_round()
113
- for it in items: network.ingest(it['text'], it['category'], source=it.get('source','web'))
114
- return f"✅ +{len(items)} articles"
115
-
116
- def do_fetch_img():
117
- r = img_fetcher.fetch_round()
118
- return f"✅ +{r['downloaded']} images"
119
-
120
- def do_train_text(n):
121
- r = network.train_n_steps(int(n))
122
- return f"✅ {r['steps']} steps · loss {r['avg_loss']}" if r['steps'] else "⚠ need more data"
123
-
124
- def do_train_img(n):
125
- r = img_network.train_n_steps(IMAGE_DIR, int(n))
126
- return f"✅ {r['steps']} steps · loss {r['avg_loss']}" if r['steps'] else "⚠ need more images"
127
-
128
- # ── stats fns ─────────────────────────────────────────────────────────────────
129
- def status_bar():
130
- s = network.stats; si = img_network.stats
131
- kf2 = network.get_knowledge_file_stats(); ig = img_fetcher.get_stats()
132
- return (f"{'🟢' if is_alive else '🔴'} TEXT ep{s['epoch']:,} loss{s['loss']} acc{s['accuracy']}% | "
133
- f"{'🟢' if img_alive else '🔴'} CNN ep{si['epoch']:,} loss{si['loss']} acc{si['accuracy']}% | "
134
- f"📚{kf2['lines']} articles 🖼️{ig['total']} images")
135
-
136
- def text_stats():
137
- s=network.stats; fs=fetcher.get_stats(); cc=network.category_counts
138
- hist=network.loss_history[-30:]
139
- spark=''.join(' ▁▂▃▄▅▆▇█'[min(8,int(((v-min(hist))/(max(hist)-min(hist)+1e-9))*8))] for v in hist) if len(hist)>=2 else '…'
140
- rows='\n'.join(f"|{c}|{cc.get(c,0)}|" for c in TEXT_CATS)
141
- return f"""### 📝 Text Network
142
- |Metric|Value|
143
- |---|---|
144
- |Epoch|{s['epoch']:,}|Loss|{s['loss']}|
145
- |Accuracy|{s['accuracy']}%|Samples|{s['total_samples']:,}|
146
- |Knowledge|{s['knowledge_count']} articles|Vocab|{s['vocab_size']:,}|
147
- |LR|{s['lr']}|Buffer|{s['buffer_size']}|
148
-
149
- Loss `{spark}`
150
-
151
- ### Sources — {fs['total_fetched']} total
152
- RSS·{fs['sources']['rss']} Reddit·{fs['sources']['reddit']} Wiki·{fs['sources']['wikipedia']} HN·{fs['sources']['hackernews']}
153
-
154
- ### Categories
155
- |Cat|Count|
156
- |---|---|
157
- {rows}
158
- > _{s['last_text']}_"""
159
-
160
- def img_stats():
161
- s=img_network.stats; ifs=img_fetcher.get_stats()
162
- hist=img_network.loss_history[-30:]
163
- spark=''.join(' ▁▂▃▄▅▆▇█'[min(8,int(((v-min(hist))/(max(hist)-min(hist)+1e-9))*8))] for v in hist) if len(hist)>=2 else '…'
164
- rows='\n'.join(f"|{c}|{ifs['by_category'].get(c,0)}|" for c in IMG_CATS)
165
- return f"""### 👁️ Image CNN
166
- |Metric|Value|
167
- |---|---|
168
- |Epoch|{s['epoch']:,}|Loss|{s['loss']}|
169
- |Accuracy|{s['accuracy']}%|Images|{s['total_images']:,}|
170
- |On Disk|{ifs['total']}|Disk|{ifs['disk_mb']} MB|
171
-
172
- Loss `{spark}`
173
-
174
- ### By Category
175
- |Cat|Count|
176
- |---|---|
177
- {rows}
178
-
179
- **What each block learns:**
180
- Block 1 → edges & colours · Block 2 → shapes & textures · Block 3 → objects & parts"""
181
-
182
- def get_log(): return '\n'.join(list(app_log)[:60])
183
- def get_feed():
184
- items=fetcher.get_recent_items(10)
185
- if not items: return "_No data yet_"
186
- return '\n\n---\n\n'.join(f"**[{i['source'].upper()}]** `{i['category'].upper()}`\n{i['text'][:130]}…" for i in items)
187
-
188
- def get_knowledge():
189
- kf2=network.get_knowledge_file_stats(); items=network.get_recent_knowledge(20)
190
- if not kf2['exists'] or not items: return "### 📭 Empty — start text network"
191
- rows=[]
192
- for it in items:
193
- rows.append(f"**`{it.get('category','?').upper()}`** `{it.get('source','?')}` `{it.get('timestamp','')[:10]}`\n> {it.get('text','')[:130]}…")
194
- return f"### 📚 {kf2['lines']} articles · {kf2['size_kb']} KB\n\n---\n\n"+'\n\n---\n\n'.join(rows)
195
-
196
- def predict_text(txt):
197
- if not txt.strip(): return "Enter text."
198
- r=network.predict(txt)
199
- if 'error' in r: return f"⚠ {r['error']}"
200
- bars=''.join(f"`{c:<15}` {'█'*int(p/5)}{'░'*(20-int(p/5))} **{p:.1f}%**\n\n" for c,p in sorted(r['all_probs'].items(),key=lambda x:-x[1]))
201
- return f"## → {r['prediction'].upper()}\n**{r['confidence']}% confidence**\n\n{bars}"
202
-
203
- def predict_img(path):
204
- if not path: return "Upload image."
205
- r=img_network.predict_image(path)
206
- if 'error' in r: return f"⚠ {r['error']}"
207
- bars=''.join(f"`{c:<15}` {'█'*int(p/5)}{'░'*(20-int(p/5))} **{p:.1f}%**\n\n" for c,p in sorted(r['all_probs'].items(),key=lambda x:-x[1]))
208
- return f"## → {r['prediction'].upper()}\n**{r['confidence']}% confidence**\n\n{bars}"
209
-
210
- def chat_fn(msg, history):
211
- return chatbot.chat(msg, history or [])
212
-
213
- # ── 3D VIZ — fully animated with signal pulses ────────────────────────────────
214
- def build_viz(state_json: str) -> str:
215
- return """<!DOCTYPE html><html><head><meta charset="UTF-8">
216
- <style>
217
- *{margin:0;padding:0;box-sizing:border-box}
218
- body{background:#030610;overflow:hidden;font-family:monospace}
219
- #c{width:100vw;height:100vh;display:block}
220
- #hud{position:fixed;top:12px;left:14px;color:#00f5c4;font-size:11px;line-height:2;pointer-events:none;text-shadow:0 0 8px #00f5c466}
221
- #tip{position:fixed;bottom:12px;left:50%;transform:translateX(-50%);font-size:10px;color:#2a3a5a}
222
- </style></head><body>
223
- <canvas id="c"></canvas>
224
- <div id="hud">
225
- <div id="h1">■ LOADING...</div>
226
- <div id="h2"></div><div id="h3"></div><div id="h4"></div>
227
- </div>
228
- <div id="tip">drag to rotate · scroll to zoom · signals travel left→right every 800ms</div>
229
- <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
230
- <script>
231
- // ── initial state from Python ──
232
- const INIT = """ + state_json + """;
233
-
234
- // ── renderer ──
235
- const canvas = document.getElementById('c');
236
- const renderer = new THREE.WebGLRenderer({canvas, antialias:true, alpha:false});
237
- renderer.setPixelRatio(Math.min(devicePixelRatio,2));
238
- renderer.setSize(innerWidth, innerHeight);
239
- renderer.shadowMap.enabled = true;
240
-
241
- const scene = new THREE.Scene();
242
- scene.background = new THREE.Color(0x030610);
243
- scene.fog = new THREE.FogExp2(0x030610, 0.010);
244
-
245
- const camera = new THREE.PerspectiveCamera(52, innerWidth/innerHeight, 0.1, 600);
246
- camera.position.set(0,1,26);
247
-
248
- // ── lights ──
249
- scene.add(new THREE.AmbientLight(0x0a1020, 4));
250
- const kl = new THREE.PointLight(0x00f5c4, 8, 80); kl.position.set(0,10,8); scene.add(kl);
251
- const bl = new THREE.PointLight(0x5b6fff, 4, 50); bl.position.set(-12,-6,4); scene.add(bl);
252
- const rl = new THREE.PointLight(0xff6b35, 2, 40); rl.position.set(12,-4,-2); scene.add(rl);
253
-
254
- // ── orbit ──
255
- let rX=0.18, rY=0, zoom=26, drag=false, last={x:0,y:0};
256
- canvas.addEventListener('mousedown', e=>{drag=true;last={x:e.clientX,y:e.clientY}});
257
- window.addEventListener('mouseup', ()=>drag=false);
258
- window.addEventListener('mousemove', e=>{
259
- if(!drag)return;
260
- rY += (e.clientX-last.x)*0.011;
261
- rX += (e.clientY-last.y)*0.007;
262
- rX = Math.max(-1.1, Math.min(1.1, rX));
263
- last = {x:e.clientX, y:e.clientY};
264
- });
265
- canvas.addEventListener('wheel', e=>{zoom=Math.max(7,Math.min(45,zoom+e.deltaY*0.025));e.preventDefault();},{passive:false});
266
- let lt=null;
267
- canvas.addEventListener('touchstart',e=>{lt=e.touches[0];},{passive:true});
268
- canvas.addEventListener('touchmove',e=>{
269
- if(!lt)return; const t=e.touches[0];
270
- rY+=(t.clientX-lt.clientX)*0.011; rX+=(t.clientY-lt.clientY)*0.007;
271
- lt=t; e.preventDefault();
272
- },{passive:false});
273
-
274
- // ── starfield ──
275
- const sg=new THREE.BufferGeometry();
276
- const sp=new Float32Array(600*3);
277
- for(let i=0;i<sp.length;i++) sp[i]=(Math.random()-0.5)*120;
278
- sg.setAttribute('position',new THREE.BufferAttribute(sp,3));
279
- scene.add(new THREE.Points(sg, new THREE.PointsMaterial({color:0x0d1a33,size:0.06})));
280
-
281
- // ── build network from state ──
282
- const group = new THREE.Group();
283
- scene.add(group);
284
-
285
- const sizes = INIT.layer_sizes || [64,256,128,64,8];
286
- const nL = sizes.length;
287
- const LGAP = 5.8;
288
- const startX = -(nL-1)*LGAP/2;
289
- const MAX_N = 12;
290
- const acts = INIT.activations || {};
291
- const aKeys = Object.keys(acts);
292
-
293
- function getAct(li, ni){
294
- const k=aKeys[li]; if(!k) return Math.random()*0.4+0.1;
295
- const a=acts[k];
296
- return (a&&a[ni]!=null) ? Math.max(0,Math.min(1,a[ni])) : Math.random()*0.3;
297
- }
298
-
299
- // Shared geometries
300
- const nGeo = new THREE.SphereGeometry(0.22, 18, 18);
301
- const gGeo = new THREE.SphereGeometry(0.34, 8, 8);
302
-
303
- const LAYER_NAMES = ['INPUT','HIDDEN-1','HIDDEN-2','HIDDEN-3','OUTPUT',
304
- 'CONV-1','CONV-2','FC-1','FC-2'];
305
-
306
- // Store neuron meshes for animation
307
- const neurons = []; // neurons[layerIdx] = [{mesh, glowMesh, baseAct, fireTimer, pos}]
308
- const connections = []; // {from, to, line, fromIdx, toIdx, lFromIdx, lToIdx}
309
-
310
- for(let li=0;li<nL;li++){
311
- const show = Math.min(sizes[li], MAX_N);
312
- const yGap = Math.min(1.9, 11/show);
313
- const yStart= -(show-1)*yGap/2;
314
- const layer = [];
315
-
316
- for(let ni=0;ni<show;ni++){
317
- const act = getAct(li,ni);
318
- const x = startX + li*LGAP;
319
- const y = yStart + ni*yGap;
320
- const z = (Math.random()-0.5)*0.5;
321
-
322
- // Neuron colour based on activation
323
- const r=Math.floor(act*240), g=Math.floor(act*200), b=Math.floor(60+act*100);
324
- const col = new THREE.Color(`rgb(${r},${g},${b})`);
325
-
326
- const mat = new THREE.MeshStandardMaterial({
327
- color: col, emissive: col,
328
- emissiveIntensity: 0.3+act*1.8,
329
- roughness:0.2, metalness:0.9,
330
- });
331
- const mesh = new THREE.Mesh(nGeo, mat);
332
- mesh.position.set(x,y,z);
333
- group.add(mesh);
334
-
335
- // Glow halo
336
- const gMat = new THREE.MeshBasicMaterial({
337
- color:0x00f5c4, transparent:true,
338
- opacity: act>0.4?(act-0.4)*0.5:0,
339
- wireframe:true
340
- });
341
- const gMesh = new THREE.Mesh(gGeo, gMat);
342
- gMesh.position.set(x,y,z);
343
- group.add(gMesh);
344
-
345
- layer.push({mesh, gMesh, baseAct:act, fireTimer:0, pos:new THREE.Vector3(x,y,z)});
346
- }
347
-
348
- // Layer label
349
- const lc=document.createElement('canvas');
350
- lc.width=256; lc.height=40;
351
- const lx=lc.getContext('2d');
352
- lx.fillStyle='rgba(0,245,196,0.5)';
353
- lx.font='bold 18px monospace'; lx.textAlign='center';
354
- lx.fillText(LAYER_NAMES[li]||`L${li}`, 128, 28);
355
- const lbl = new THREE.Mesh(
356
- new THREE.PlaneGeometry(2.6,0.45),
357
- new THREE.MeshBasicMaterial({map:new THREE.CanvasTexture(lc),transparent:true,side:THREE.DoubleSide})
358
- );
359
- lbl.position.set(startX+li*LGAP, yStart-2.0, 0);
360
- group.add(lbl);
361
- neurons.push(layer);
362
- }
363
-
364
- // Build connections between adjacent layers
365
- let connDrawn = 0;
366
- const MAX_CONN = 160;
367
- for(let li=0;li<nL-1&&connDrawn<MAX_CONN;li++){
368
- const fromL=neurons[li], toL=neurons[li+1];
369
- for(let fi=0;fi<fromL.length&&connDrawn<MAX_CONN;fi++){
370
- for(let ti=0;ti<toL.length&&connDrawn<MAX_CONN;ti++){
371
- const sig=(fromL[fi].baseAct+toL[ti].baseAct)/2;
372
- if(sig<0.05&&Math.random()>0.3) continue;
373
- const positive=Math.random()>0.35;
374
- const col=positive?0x00f5c4:0xff6b35;
375
- const pts=[fromL[fi].pos.clone(), toL[ti].pos.clone()];
376
- const geo=new THREE.BufferGeometry().setFromPoints(pts);
377
- const mat=new THREE.LineBasicMaterial({color:col,transparent:true,opacity:0.04+sig*0.35});
378
- const line=new THREE.Line(geo,mat);
379
- group.add(line);
380
- connections.push({from:fromL[fi],to:toL[ti],line,mat,lFromIdx:li,lToIdx:li+1,fi,ti});
381
- connDrawn++;
382
- }
383
- }
384
- }
385
-
386
- // ── SIGNAL PARTICLE SYSTEM ────────────────────────────────────────────────────
387
- // This is what makes the network look ALIVE — glowing orbs traveling between neurons
388
- const signals = [];
389
- const sigGeo = new THREE.SphereGeometry(0.12, 8, 8);
390
-
391
- function spawnSignal(fromNeuron, toNeuron, color=0x00f5c4){
392
- const mat = new THREE.MeshBasicMaterial({color, transparent:true, opacity:0.95});
393
- const mesh = new THREE.Mesh(sigGeo, mat);
394
- mesh.position.copy(fromNeuron.pos);
395
- scene.add(mesh); // add to scene not group so it stays in world space
396
-
397
- // Trail
398
- const trailMat = new THREE.MeshBasicMaterial({color, transparent:true, opacity:0.4});
399
- const trail = new THREE.Mesh(new THREE.SphereGeometry(0.07,6,6), trailMat);
400
- scene.add(trail);
401
-
402
- signals.push({
403
- mesh, trail, mat, trailMat,
404
- from: fromNeuron.pos.clone(),
405
- to: toNeuron.pos.clone(),
406
- toNeuron,
407
- t: 0,
408
- speed: 0.028 + Math.random()*0.015,
409
- color,
410
- });
411
- }
412
-
413
- function fireNeuron(layerIdx, neuronIdx, cascade=true){
414
- if(layerIdx>=neurons.length || neuronIdx>=neurons[layerIdx].length) return;
415
- const n = neurons[layerIdx][neuronIdx];
416
- n.fireTimer = 1.0;
417
-
418
- // Spawn signals to next layer
419
- if(cascade && layerIdx < nL-1){
420
- const nextL = neurons[layerIdx+1];
421
- const count = Math.min(nextL.length, 2+Math.floor(Math.random()*3));
422
- const shuffled = [...nextL].sort(()=>Math.random()-0.5).slice(0, count);
423
- shuffled.forEach(target => {
424
- spawnSignal(n, target, layerIdx===0?0x00f5c4:0x5b9fff);
425
- });
426
- }
427
- }
428
-
429
- // Every 800ms: fire random input neurons → cascade through the network
430
- let fireTimer = 0;
431
- function triggerFiring(){
432
- if(neurons.length===0) return;
433
- const inputLayer = neurons[0];
434
- const count = 1+Math.floor(Math.random()*3);
435
- for(let i=0;i<count;i++){
436
- const ni = Math.floor(Math.random()*inputLayer.length);
437
- fireNeuron(0, ni, true);
438
- }
439
- }
440
-
441
- // ── LOSS HISTORY GRAPH ───────────────────────────────────────────────────────
442
- (function(){
443
- const hist = INIT.loss_history||[];
444
- if(hist.length<3) return;
445
- const gc=document.createElement('canvas');
446
- gc.width=200; gc.height=50;
447
- gc.style.cssText='position:fixed;bottom:14px;right:14px;border:1px solid #1a2240;border-radius:6px;background:rgba(11,15,30,0.8)';
448
- const ctx=gc.getContext('2d');
449
- const mn=Math.min(...hist), mx=Math.max(...hist), rng=mx-mn||1;
450
- // fill
451
- ctx.beginPath();
452
- hist.forEach((v,i)=>{const x=(i/(hist.length-1))*200,y=50-4-((v-mn)/rng)*42; i===0?ctx.moveTo(x,50):ctx.lineTo(x,y)});
453
- ctx.lineTo(200,50); ctx.closePath();
454
- ctx.fillStyle='rgba(0,245,196,0.08)'; ctx.fill();
455
- // line
456
- ctx.beginPath();
457
- hist.forEach((v,i)=>{const x=(i/(hist.length-1))*200,y=50-4-((v-mn)/rng)*42; i===0?ctx.moveTo(x,y):ctx.lineTo(x,y)});
458
- ctx.strokeStyle='#00f5c4'; ctx.lineWidth=1.5; ctx.stroke();
459
- document.body.appendChild(gc);
460
- const lb=document.createElement('div');
461
- lb.style.cssText='position:fixed;bottom:68px;right:14px;font-size:9px;color:#2a3a5a;font-family:monospace';
462
- lb.textContent='LOSS ↓'; document.body.appendChild(lb);
463
- })();
464
-
465
- // ── HUD ──────────────────────────────────────────────────────────────────────
466
- const st = INIT.stats||{};
467
- const isImg = INIT.type==='cnn';
468
- document.getElementById('h1').textContent = (isImg?'👁️ IMAGE CNN':'📝 TEXT NETWORK')+' — LIVE';
469
- document.getElementById('h2').textContent = `EPOCH ${(st.epoch||0).toLocaleString()}`;
470
- document.getElementById('h3').textContent = `LOSS ${st.loss||'—'}`;
471
- document.getElementById('h4').textContent = `ACC ${st.accuracy||'—'}%`;
472
-
473
- // ── ANIMATE ──────────────────────────────────────────────────────────────────
474
- let frame = 0;
475
- const clock = new THREE.Clock();
476
-
477
- function animate(){
478
- requestAnimationFrame(animate);
479
- const dt = clock.getDelta();
480
- const elaps = clock.getElapsedTime();
481
- frame++;
482
-
483
- // ① Auto-fire every 800ms
484
- fireTimer += dt;
485
- if(fireTimer > 0.8){
486
- triggerFiring();
487
- fireTimer = 0;
488
- }
489
-
490
- // ② Update neurons — pulse and fire glow
491
- neurons.forEach((layer, li)=>{
492
- layer.forEach((n, ni)=>{
493
- // Base sinusoidal pulse — each neuron breathes at its own rate
494
- const phase = li*0.7 + ni*0.3;
495
- const pulse = Math.sin(elaps*2.1+phase)*0.15 + Math.sin(elaps*0.9+phase*2)*0.08;
496
- const act = Math.max(0, Math.min(1, n.baseAct + pulse + n.fireTimer*0.6));
497
-
498
- const r=Math.floor(act*240), g=Math.floor(act*200), b=Math.floor(60+act*100);
499
- n.mesh.material.emissive.setRGB(r/255, g/255, b/255);
500
- n.mesh.material.emissiveIntensity = 0.3 + act*2.2;
501
- n.mesh.scale.setScalar(1 + n.fireTimer*0.6 + pulse*0.05);
502
-
503
- // Glow halo
504
- n.gMesh.material.opacity = n.fireTimer>0 ? n.fireTimer*0.7 : Math.max(0,(act-0.45)*0.4);
505
- n.gMesh.scale.setScalar(1 + n.fireTimer*1.0);
506
-
507
- // Decay fire
508
- if(n.fireTimer > 0) n.fireTimer = Math.max(0, n.fireTimer - dt*1.8);
509
- });
510
- });
511
-
512
- // ③ Update connection lines — flash when signals pass
513
- connections.forEach(conn=>{
514
- const sig=(conn.from.baseAct+conn.to.baseAct)/2;
515
- const flash = conn.from.fireTimer*0.5;
516
- conn.mat.opacity = Math.min(0.9, 0.04 + sig*0.3 + flash);
517
- });
518
-
519
- // ④ Move signal particles
520
- for(let i=signals.length-1;i>=0;i--){
521
- const s=signals[i];
522
- s.t += s.speed;
523
- if(s.t>=1){
524
- scene.remove(s.mesh); scene.remove(s.trail);
525
- signals.splice(i,1);
526
- // Fire destination neuron (next layer cascade)
527
- s.toNeuron.fireTimer = 0.8;
528
- // If not at output, cascade further
529
- const lIdx = neurons.findIndex(l=>l.includes(s.toNeuron));
530
- if(lIdx>=0 && lIdx<nL-1){
531
- const nextL=neurons[lIdx+1];
532
- if(Math.random()>0.3){
533
- const t2=nextL[Math.floor(Math.random()*nextL.length)];
534
- spawnSignal(s.toNeuron, t2, 0x5b9fff);
535
- }
536
- }
537
- } else {
538
- s.mesh.position.lerpVectors(s.from, s.to, s.t);
539
- s.trail.position.lerpVectors(s.from, s.to, Math.max(0,s.t-0.08));
540
- // Fade out near end
541
- s.mat.opacity = s.t<0.8 ? 0.95 : (1-s.t)*4.75;
542
- s.trailMat.opacity = s.t<0.8 ? 0.35 : (1-s.t)*1.75;
543
- }
544
- }
545
-
546
- // ⑤ Camera orbit + gentle network bob
547
- const autoY = elaps * 0.12;
548
- camera.position.x = Math.sin(rY + autoY)*zoom;
549
- camera.position.y = Math.sin(rX)*zoom*0.45 + 1;
550
- camera.position.z = Math.cos(rY + autoY)*zoom;
551
- camera.lookAt(0, 0, 0);
552
-
553
- kl.intensity = 7 + Math.sin(elaps*1.5)*2;
554
- bl.intensity = 3 + Math.cos(elaps*2.3)*1;
555
- kl.position.x = Math.sin(elaps*0.4)*6;
556
- group.position.y = Math.sin(elaps*0.6)*0.15;
557
-
558
- renderer.render(scene, camera);
559
- }
560
- animate();
561
-
562
- window.addEventListener('resize',()=>{
563
- camera.aspect=innerWidth/innerHeight;
564
- camera.updateProjectionMatrix();
565
- renderer.setSize(innerWidth,innerHeight);
566
- });
567
- </script></body></html>"""
568
-
569
- def get_text_viz():
570
- s = network.get_viz_state(); s['type']='text'
571
- h = build_viz(json.dumps(s))
572
- e = h.replace('"','&quot;').replace('\n','&#10;')
573
- return f'<iframe srcdoc="{e}" style="width:100%;height:650px;border:none;border-radius:12px"></iframe>'
574
-
575
- def get_img_viz():
576
- s = img_network.get_viz_state()
577
- h = build_viz(json.dumps(s))
578
- e = h.replace('"','&quot;').replace('\n','&#10;')
579
- return f'<iframe srcdoc="{e}" style="width:100%;height:650px;border:none;border-radius:12px"></iframe>'
580
-
581
- # ── UI ────────────────────────────────────────────────────────────────────────
582
- with gr.Blocks(title="Living Neural Network") as demo:
583
- gr.Markdown("# 🧠 Living Neural Network\n*Two AIs training on live internet data — one reads, one looks*")
584
-
585
- sbar = gr.Textbox(label="", value=status_bar(), interactive=False, lines=2)
586
-
587
- with gr.Tabs():
588
-
589
- # CONTROL
590
- with gr.Tab("🎛️ Control"):
591
- gr.Markdown("### 📝 Text Network")
592
- with gr.Row():
593
- gr.Button("▶ Start Text", variant="primary").click(start_text, outputs=gr.Textbox(label="",lines=1,interactive=False))
594
- gr.Button("⏹ Stop Text", variant="stop" ).click(stop_text, outputs=gr.Textbox(label="",lines=1,interactive=False))
595
- gr.Button("📡 Fetch Text" ).click(do_fetch_text, outputs=gr.Textbox(label="",lines=1,interactive=False))
596
- with gr.Row():
597
- ts=gr.Slider(10,500,100,step=10,label="Steps")
598
- gr.Button("🔥 Train Text").click(do_train_text,inputs=ts,outputs=gr.Textbox(label="",lines=1,interactive=False))
599
- gr.Markdown("---\n### 👁️ Image CNN")
600
- with gr.Row():
601
- gr.Button("▶ Start Images",variant="primary").click(start_img, outputs=gr.Textbox(label="",lines=1,interactive=False))
602
- gr.Button("⏹ Stop Images",variant="stop" ).click(stop_img, outputs=gr.Textbox(label="",lines=1,interactive=False))
603
- gr.Button("🖼️ Fetch Images" ).click(do_fetch_img, outputs=gr.Textbox(label="",lines=1,interactive=False))
604
- with gr.Row():
605
- is_=gr.Slider(5,100,20,step=5,label="Steps")
606
- gr.Button("🔥 Train CNN").click(do_train_img,inputs=is_,outputs=gr.Textbox(label="",lines=1,interactive=False))
607
-
608
- # STATS
609
- with gr.Tab("📊 Stats"):
610
- with gr.Row():
611
- tmd=gr.Markdown(value=text_stats())
612
- imd=gr.Markdown(value=img_stats())
613
- lbox=gr.Textbox(label="Log",value=get_log(),interactive=False,lines=12)
614
-
615
- # 3D TEXT VIZ
616
- with gr.Tab("🔮 Text Network 3D"):
617
- gr.Markdown("**Neurons fire & signals travel left→right in real time.** Drag=rotate Scroll=zoom")
618
- tvb=gr.Button("🔄 Refresh",variant="primary")
619
- tvo=gr.HTML('<div style="height:650px;background:#030610;border-radius:12px;display:flex;align-items:center;justify-content:center;color:#00f5c4;font-family:monospace;font-size:14px">Click 🔄 Refresh to load the 3D network</div>')
620
- tvb.click(get_text_viz,outputs=tvo)
621
-
622
- # 3D IMAGE VIZ
623
- with gr.Tab("👁️ Image CNN 3D"):
624
- gr.Markdown("**Conv layers visualised in 3D.** Each block learns progressively deeper features.")
625
- ivb=gr.Button("🔄 Refresh",variant="primary")
626
- ivo=gr.HTML('<div style="height:650px;background:#030610;border-radius:12px;display:flex;align-items:center;justify-content:center;color:#00f5c4;font-family:monospace;font-size:14px">Click 🔄 Refresh to load CNN visualization</div>')
627
- ivb.click(get_img_viz,outputs=ivo)
628
-
629
- # CHAT
630
- with gr.Tab("💬 Chat with my AI"):
631
- gr.Markdown(
632
- "### Talk to your AI — it answers from what it has actually learned\n"
633
- "The more articles it collects, the smarter the answers.\n"
634
- "Type `stats` to see what it knows. Type `help` for tips."
635
- )
636
- chatbox = gr.Chatbot(label="", height=480, type="messages")
637
- with gr.Row():
638
- msg_in = gr.Textbox(label="", placeholder="Ask anything — e.g. 'What's happening in AI?'", scale=5)
639
- send_b = gr.Button("Send", variant="primary", scale=1)
640
- send_b.click(chat_fn, inputs=[msg_in, chatbox], outputs=chatbox)
641
- msg_in.submit(chat_fn, inputs=[msg_in, chatbox], outputs=chatbox)
642
- gr.Examples(
643
- [["What's happening in AI and technology?"],
644
- ["Tell me about recent science discoveries"],
645
- ["What's in the news about sports?"],
646
- ["stats"],["help"]],
647
- inputs=msg_in
648
- )
649
-
650
- # KNOWLEDGE
651
- with gr.Tab("📚 Knowledge Base"):
652
- gr.Markdown("Everything the AI has read — saved to `knowledge.jsonl` instantly")
653
- kmd=gr.Markdown(value=get_knowledge())
654
-
655
- # DATA FEED
656
- with gr.Tab("📰 Data Feed"):
657
- fmd=gr.Markdown(value=get_feed())
658
-
659
- # PREDICT TEXT
660
- with gr.Tab("🔍 Classify Text"):
661
- gr.Markdown("Test your trained text model")
662
- pt=gr.Textbox(label="Text",lines=3,placeholder="Scientists discover...")
663
- pb=gr.Button("Classify",variant="primary")
664
- po=gr.Markdown()
665
- pb.click(predict_text,inputs=pt,outputs=po)
666
-
667
- # PREDICT IMAGE
668
- with gr.Tab("🖼️ Classify Image"):
669
- gr.Markdown("Test your trained image CNN")
670
- pi=gr.Image(label="Upload image",type="filepath")
671
- pib=gr.Button("Classify",variant="primary")
672
- pio=gr.Markdown()
673
- pib.click(predict_img,inputs=pi,outputs=pio)
674
-
675
- # timers
676
- t3=gr.Timer(3); t5=gr.Timer(5); t8=gr.Timer(8); t12=gr.Timer(12)
677
- t3.tick(status_bar,outputs=sbar)
678
- t3.tick(get_log,outputs=lbox)
679
- t5.tick(text_stats,outputs=tmd)
680
- t5.tick(img_stats,outputs=imd)
681
- t8.tick(get_knowledge,outputs=kmd)
682
- t8.tick(get_feed,outputs=fmd)
683
- t12.tick(get_text_viz,outputs=tvo)
684
- t12.tick(get_img_viz,outputs=ivo)
685
-
686
- if __name__=="__main__":
687
- demo.launch(server_name="0.0.0.0", server_port=7860, share=True, ssr_mode=False)