everydaytok commited on
Commit
7c05a72
·
verified ·
1 Parent(s): e810bf8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -125
app.py CHANGED
@@ -1,134 +1,120 @@
1
  import os
2
  import time
3
- import math
4
  import collections
5
  import threading
6
- from flask import Flask, jsonify, request, send_file
7
- from flask_cors import CORS
 
 
 
8
 
9
- app = Flask(__name__)
10
- CORS(app)
 
 
 
 
 
 
11
 
12
  class SimEngine:
13
  def __init__(self):
14
  self.nodes = {}
15
- self.cells =[]
16
  self.buffer = collections.deque()
17
  self.running = False
18
-
19
- # State & Toggles
20
  self.mode = 'inference'
21
  self.distribution = 'uniform'
22
  self.problem_type = 'add'
23
  self.asymmetric = False
24
-
25
- # Dataset Batch Processor tracking
26
  self.batch_queue = collections.deque()
27
- self.batch_results =[]
 
28
  self.current_target = None
29
-
30
  self.reset()
31
 
32
  def reset(self):
 
33
  self.nodes = {
34
- 'A': {'x': 2.0, 'y': 1.0, 'z': 0.0, 'anchored': False, 'k': 1.0},
35
- 'B': {'x': 3.0, 'y': -1.0, 'z': 0.0, 'anchored': False, 'k': 0.8},
36
- 'C': {'x': 10.0, 'y': 0.0, 'z': 1.0, 'anchored': True, 'k': 1.0}
37
  }
38
- self.cells =[{'id': 'Cell_1', 'a': 'A', 'b': 'B', 'c': 'C'}]
39
  self.buffer.clear()
40
  self.batch_queue.clear()
41
- self.logs =[]
42
  self.iteration = 0
 
43
 
44
  def add_log(self, msg):
45
  self.logs.insert(0, f"[{self.iteration}]: {msg}")
46
- if len(self.logs) > 60: self.logs.pop()
47
 
48
  def set_problem(self, target_value):
49
  self.current_target = target_value
50
  self.nodes['C']['x'] = float(target_value)
51
- self.nodes['C']['anchored'] = True
52
-
53
- # In Training: C is goal. A and B are anchor/hints forcing structural (K) changes.
54
- if self.mode == 'training':
55
- self.nodes['A']['anchored'] = True
56
- self.nodes['B']['anchored'] = True
57
- else: # Inference: C is goal. A and B float structurally to 'find' the factors
58
- self.nodes['A']['anchored'] = False
59
- self.nodes['B']['anchored'] = False
60
-
61
- self.add_log(f"Loading Problem C={target_value} ({self.mode.upper()})")
62
  self.trigger_cells()
63
 
64
- def generate_batch(self, size, start_range, end_range):
65
- """Generates a dataset of Target C problems"""
66
- self.batch_queue.clear()
67
- self.batch_results.clear()
68
- import random
69
- for _ in range(size):
70
- self.batch_queue.append(round(random.uniform(start_range, end_range), 2))
71
-
72
- self.add_log(f"=== BATCH CREATED: {size} Problems ===")
73
- self.load_next_batch_item()
74
-
75
- def load_next_batch_item(self):
76
- if len(self.batch_queue) > 0:
77
- next_c = self.batch_queue.popleft()
78
- # Slight random offset so system resets dynamically between batch steps
79
- self.nodes['A']['x'] += 0.01
80
- self.set_problem(next_c)
81
- self.running = True
82
- else:
83
- self.running = False
84
- self.add_log("=== BATCH RUN COMPLETE ===")
85
-
86
  def trigger_cells(self):
87
  for cell in self.cells:
88
  na, nb, nc = self.nodes[cell['a']], self.nodes[cell['b']], self.nodes[cell['c']]
89
-
90
  valA, valB, valC = na['x'], nb['x'], nc['x']
91
- predictedC = (valA + valB) if self.problem_type == 'add' else (valA * valB)
92
 
93
- error = predictedC - valC
 
 
94
 
95
- if abs(error) > 0.05:
96
- # Network splits pressure
97
- self.buffer.append({'target': cell['a'], 'error_vector': error, 'cell': cell})
98
- self.buffer.append({'target': cell['b'], 'error_vector': error, 'cell': cell})
 
 
 
 
 
 
 
99
 
100
  def physics_step(self):
101
- # Handle Batch Loading if Equilibrium Reached
102
- if len(self.buffer) == 0:
103
- if self.current_target is not None and self.running:
104
- self.add_log(f"Equilibrium found for C={self.current_target}.")
105
  self.current_target = None
106
- time.sleep(0.5) # small visualization pause between batch items
107
- self.load_next_batch_item()
 
 
 
108
  return False
109
 
110
  event = self.buffer.popleft()
111
- t_id, err = event['target'], event['error_vector']
112
- t_node = self.nodes[t_id]
113
 
114
  if t_node['anchored'] and self.mode != 'training': return True
115
-
116
- # Asymmetric Retroactive Force
117
- direction_damper = 0.4 if self.asymmetric else 1.0
118
 
119
  if self.mode == 'inference':
120
- base_force = (-err * 0.02 * direction_damper)
121
- if self.distribution == 'uniform':
122
- t_node['x'] += base_force
123
- t_node['y'] -= base_force * 0.08
124
- elif self.distribution == 'individual':
125
- t_node['x'] += base_force * t_node['k']
 
126
 
127
  elif self.mode == 'training':
128
- base_grad = abs(err) * 0.01 * direction_damper
129
  if self.distribution == 'individual':
130
- t_node['k'] -= base_grad
131
- t_node['k'] = max(0.001, min(t_node['k'], 5.0)) # bounding constraints for coefficients
132
 
133
  self.trigger_cells()
134
  self.iteration += 1
@@ -139,61 +125,61 @@ engine = SimEngine()
139
  def run_loop():
140
  while True:
141
  if engine.running: engine.physics_step()
142
- time.sleep(0.02)
143
 
144
  threading.Thread(target=run_loop, daemon=True).start()
145
 
146
- # --- HOSTING ENDPOINTS ---
147
- @app.route('/')
148
- def home():
149
- """Hugging Face Space loads this UI natively"""
150
- return send_file("index.html")
151
 
152
- @app.route('/state', methods=['GET'])
153
- def get_state():
154
- return jsonify({
155
  'nodes': engine.nodes,
156
- 'buffer_size': len(engine.buffer),
157
  'iteration': engine.iteration,
158
  'logs': engine.logs,
159
- 'batch_size': len(engine.batch_queue)
160
- })
161
-
162
- @app.route('/apply_config', methods=['POST'])
163
- def config():
164
- data = request.json
165
- engine.mode = data.get('mode', engine.mode)
166
- engine.distribution = data.get('distribution', engine.distribution)
167
- engine.problem_type = data.get('problem_type', engine.problem_type)
168
- engine.asymmetric = data.get('asymmetric', engine.asymmetric)
169
- engine.add_log(f"CONFIG UPDATED: mode={engine.mode}")
170
- return jsonify(success=True)
171
-
172
- @app.route('/single_run', methods=['POST'])
173
- def single_run():
174
- data = request.json
175
- engine.set_problem(float(data.get('target', 10.0)))
 
 
 
 
176
  engine.running = True
177
- return jsonify(success=True)
178
 
179
- @app.route('/batch_run', methods=['POST'])
180
- def batch_run():
181
- data = request.json
182
- engine.running = False
183
- size = int(data.get('batch_size', 10))
184
- vmin = float(data.get('val_min', -50.0))
185
- vmax = float(data.get('val_max', 50.0))
186
- engine.generate_batch(size, vmin, vmax)
187
- return jsonify(success=True)
188
-
189
- @app.route('/halt', methods=['POST'])
190
- def halt_sys():
191
- engine.running = False
192
- engine.buffer.clear()
193
  engine.batch_queue.clear()
194
- engine.add_log("=== HARD HALT EXEC === Queues Cleared.")
195
- return jsonify(success=True)
 
 
 
 
 
 
 
 
 
196
 
197
- if __name__ == '__main__':
198
- # Binds correctly to hugging face's public 7860 Port Space Requirements
199
- app.run(host='0.0.0.0', port=7860)
 
1
  import os
2
  import time
 
3
  import collections
4
  import threading
5
+ import random
6
+ from fastapi import FastAPI, Request
7
+ from fastapi.responses import HTMLResponse, FileResponse
8
+ from fastapi.middleware.cors import CORSMiddleware
9
+ from pydantic import BaseModel
10
 
11
+ app = FastAPI()
12
+
13
+ app.add_middleware(
14
+ CORSMiddleware,
15
+ allow_origins=["*"],
16
+ allow_methods=["*"],
17
+ allow_headers=["*"],
18
+ )
19
 
20
  class SimEngine:
21
  def __init__(self):
22
  self.nodes = {}
23
+ self.cells = []
24
  self.buffer = collections.deque()
25
  self.running = False
 
 
26
  self.mode = 'inference'
27
  self.distribution = 'uniform'
28
  self.problem_type = 'add'
29
  self.asymmetric = False
 
 
30
  self.batch_queue = collections.deque()
31
+ self.logs = []
32
+ self.iteration = 0
33
  self.current_target = None
34
+ self.current_error = 0.0
35
  self.reset()
36
 
37
  def reset(self):
38
+ # Initializing within a visible range (0-10)
39
  self.nodes = {
40
+ 'A': {'x': random.uniform(0, 5), 'y': 1.0, 'z': 0.0, 'anchored': False, 'k': 1.0, 'force': 0.0},
41
+ 'B': {'x': random.uniform(0, 5), 'y': -1.0, 'z': 0.0, 'anchored': False, 'k': 0.8, 'force': 0.0},
42
+ 'C': {'x': 10.0, 'y': 0.0, 'z': 0.0, 'anchored': True, 'k': 1.0, 'force': 0.0}
43
  }
44
+ self.cells = [{'id': 'Cell_1', 'a': 'A', 'b': 'B', 'c': 'C'}]
45
  self.buffer.clear()
46
  self.batch_queue.clear()
47
+ self.logs = []
48
  self.iteration = 0
49
+ self.current_error = 0.0
50
 
51
  def add_log(self, msg):
52
  self.logs.insert(0, f"[{self.iteration}]: {msg}")
53
+ if len(self.logs) > 30: self.logs.pop()
54
 
55
  def set_problem(self, target_value):
56
  self.current_target = target_value
57
  self.nodes['C']['x'] = float(target_value)
58
+ # Randomize A and B slightly to prevent getting stuck in a local zero
59
+ self.nodes['A']['x'] = random.uniform(0, target_value/2)
60
+ self.nodes['B']['x'] = random.uniform(0, target_value/2)
61
+ self.add_log(f"New Target Load: {target_value}")
 
 
 
 
 
 
 
62
  self.trigger_cells()
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  def trigger_cells(self):
65
  for cell in self.cells:
66
  na, nb, nc = self.nodes[cell['a']], self.nodes[cell['b']], self.nodes[cell['c']]
 
67
  valA, valB, valC = na['x'], nb['x'], nc['x']
 
68
 
69
+ # Logic calculation
70
+ pred = (valA + valB) if self.problem_type == 'add' else (valA * valB)
71
+ self.current_error = pred - valC
72
 
73
+ # If error is high, generate tension (Forces)
74
+ if abs(self.current_error) > 0.01:
75
+ # Calculating the specific force for this step
76
+ force_mag = -self.current_error * 0.05
77
+ self.nodes['A']['force'] = force_mag
78
+ self.nodes['B']['force'] = force_mag
79
+ self.buffer.append({'target': cell['a'], 'f': force_mag})
80
+ self.buffer.append({'target': cell['b'], 'f': force_mag})
81
+ else:
82
+ self.nodes['A']['force'] = 0
83
+ self.nodes['B']['force'] = 0
84
 
85
  def physics_step(self):
86
+ if not self.buffer:
87
+ if self.current_target is not None and self.running and abs(self.current_error) < 0.05:
88
+ self.add_log(f"SUCCESS: C={self.current_target} Solved.")
 
89
  self.current_target = None
90
+ if self.batch_queue:
91
+ time.sleep(0.5)
92
+ self.set_problem(self.batch_queue.popleft())
93
+ else:
94
+ self.running = False
95
  return False
96
 
97
  event = self.buffer.popleft()
98
+ t_node = self.nodes[event['target']]
 
99
 
100
  if t_node['anchored'] and self.mode != 'training': return True
101
+
102
+ # Dampening to prevent the explosion you saw
103
+ damper = 0.2 if self.asymmetric else 0.5
104
 
105
  if self.mode == 'inference':
106
+ move = event['f'] * damper
107
+ if self.distribution == 'individual':
108
+ move *= t_node['k']
109
+
110
+ t_node['x'] += move
111
+ # CLAMPING: Prevent numbers from flying to 40,000
112
+ t_node['x'] = max(-1000, min(t_node['x'], 1000))
113
 
114
  elif self.mode == 'training':
115
+ # In training, we adjust the K coefficient based on the force
116
  if self.distribution == 'individual':
117
+ t_node['k'] = max(0.01, min(t_node['k'] - (abs(self.current_error) * 0.001), 2.0))
 
118
 
119
  self.trigger_cells()
120
  self.iteration += 1
 
125
  def run_loop():
126
  while True:
127
  if engine.running: engine.physics_step()
128
+ time.sleep(0.03)
129
 
130
  threading.Thread(target=run_loop, daemon=True).start()
131
 
132
+ # --- ROUTES (FastAPI) ---
133
+ @app.get("/", response_class=HTMLResponse)
134
+ async def get_ui():
135
+ return FileResponse("index.html")
 
136
 
137
+ @app.get("/state")
138
+ async def get_state():
139
+ return {
140
  'nodes': engine.nodes,
141
+ 'error': engine.current_error,
142
  'iteration': engine.iteration,
143
  'logs': engine.logs,
144
+ 'batch_count': len(engine.batch_queue)
145
+ }
146
+
147
+ class ConfigModel(BaseModel):
148
+ mode: str
149
+ distribution: str
150
+ problem_type: str
151
+ asymmetric: bool
152
+
153
+ @app.post("/apply_config")
154
+ async def apply_config(cfg: ConfigModel):
155
+ engine.mode = cfg.mode
156
+ engine.distribution = cfg.distribution
157
+ engine.problem_type = cfg.problem_type
158
+ engine.asymmetric = cfg.asymmetric
159
+ engine.add_log("Config Updated.")
160
+ return {"success": True}
161
+
162
+ @app.post("/single_run")
163
+ async def single_run(data: dict):
164
+ engine.set_problem(float(data['target']))
165
  engine.running = True
166
+ return {"success": True}
167
 
168
+ @app.post("/batch_run")
169
+ async def batch_run(data: dict):
 
 
 
 
 
 
 
 
 
 
 
 
170
  engine.batch_queue.clear()
171
+ for _ in range(int(data['batch_size'])):
172
+ engine.batch_queue.append(round(random.uniform(float(data['val_min']), float(data['val_max'])), 2))
173
+ engine.set_problem(engine.batch_queue.popleft())
174
+ engine.running = True
175
+ return {"success": True}
176
+
177
+ @app.post("/halt")
178
+ async def halt():
179
+ engine.running = False
180
+ engine.reset()
181
+ return {"success": True}
182
 
183
+ if __name__ == "__main__":
184
+ import uvicorn
185
+ uvicorn.run(app, host="0.0.0.0", port=7860)