coredipper commited on
Commit
1652936
Β·
verified Β·
1 Parent(s): 15f8184

Upload folder using huggingface_hub

Browse files
Files changed (4) hide show
  1. README.md +22 -6
  2. __pycache__/app.cpython-314.pyc +0 -0
  3. app.py +436 -0
  4. requirements.txt +2 -0
README.md CHANGED
@@ -1,12 +1,28 @@
1
  ---
2
- title: Operon Oscillator
3
- emoji: πŸ“‰
4
- colorFrom: red
5
- colorTo: purple
6
  sdk: gradio
7
- sdk_version: 6.5.1
8
  app_file: app.py
9
  pinned: false
 
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Operon Biological Oscillators
3
+ emoji: πŸ”ƒ
4
+ colorFrom: purple
5
+ colorTo: blue
6
  sdk: gradio
7
+ sdk_version: "6.5.1"
8
  app_file: app.py
9
  pinned: false
10
+ license: mit
11
+ short_description: Biological oscillator patterns and waveform visualization
12
  ---
13
 
14
+ # πŸ”ƒ Biological Oscillator Patterns
15
+
16
+ Compute and visualize oscillator waveforms (sine, square, sawtooth, triangle, pulse) with damping, plus explore biological oscillator phase structures.
17
+
18
+ ## Features
19
+
20
+ - **Tab 1 β€” Waveform Explorer**: 5 waveform types with configurable frequency, amplitude, damping, and cycles
21
+ - **Tab 2 β€” Biological Oscillators**: Circadian (day/night), Heartbeat (BPM), and Cell Cycle (G1/S/G2/M) phase breakdowns
22
+ - **8 presets**: Sine wave, square pulse, damped sine, fast triangle, sawtooth, circadian, heartbeat, cell division
23
+
24
+ ## How It Works
25
+
26
+ Waveforms are computed mathematically (matching `oscillator.py` internals) without starting background threads. Biological oscillators show phase structures that map to real-world patterns like circadian rhythms and cell division cycles.
27
+
28
+ [GitHub](https://github.com/coredipper/operon) | [PyPI](https://pypi.org/project/operon-ai/)
__pycache__/app.cpython-314.pyc ADDED
Binary file (19.4 kB). View file
 
app.py ADDED
@@ -0,0 +1,436 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Operon Biological Oscillator Patterns -- Interactive Gradio Demo
3
+ ================================================================
4
+
5
+ Two-tab demo: compute and display waveform shapes (sine, square, sawtooth,
6
+ triangle, pulse) with damping, plus show biological oscillator phase
7
+ structures (Circadian, Heartbeat, CellCycle).
8
+
9
+ CRITICAL: Oscillators use background threads. We do NOT call start()/stop().
10
+ Waveform values are computed mathematically via _compute_waveform_value().
11
+
12
+ Run locally:
13
+ pip install gradio
14
+ python space-oscillator/app.py
15
+
16
+ Deploy to HuggingFace Spaces:
17
+ Copy this directory to a new HF Space with sdk=gradio.
18
+ """
19
+
20
+ import math
21
+ import sys
22
+ from pathlib import Path
23
+
24
+ import gradio as gr
25
+
26
+ # Allow importing operon_ai from the repo root when running locally
27
+ _repo_root = Path(__file__).resolve().parent.parent
28
+ if str(_repo_root) not in sys.path:
29
+ sys.path.insert(0, str(_repo_root))
30
+
31
+ from operon_ai import WaveformType
32
+
33
+ # ── Waveform computation (matches oscillator.py lines 413-433) ────────────
34
+
35
+
36
+ def _compute_waveform_value(waveform: WaveformType, phase: float) -> float:
37
+ """Compute waveform output for a given phase in [0, 1]."""
38
+ if waveform == WaveformType.SINE:
39
+ return math.sin(2 * math.pi * phase)
40
+ elif waveform == WaveformType.SQUARE:
41
+ return 1.0 if phase < 0.5 else -1.0
42
+ elif waveform == WaveformType.SAWTOOTH:
43
+ return 2.0 * phase - 1.0
44
+ elif waveform == WaveformType.TRIANGLE:
45
+ return 4.0 * phase - 1.0 if phase < 0.5 else 3.0 - 4.0 * phase
46
+ elif waveform == WaveformType.PULSE:
47
+ return 1.0 if phase < 0.1 else 0.0
48
+ return 0.0
49
+
50
+
51
+ # ── Tab 1: Waveform Presets ───────────────────────────────────────────────
52
+
53
+ WAVEFORM_PRESETS: dict[str, dict] = {
54
+ "(custom)": {
55
+ "description": "Configure your own waveform parameters.",
56
+ "waveform": "sine",
57
+ "frequency": 1.0,
58
+ "amplitude": 1.0,
59
+ "damping": 0.0,
60
+ "cycles": 2,
61
+ },
62
+ "Sine wave": {
63
+ "description": "Classic sinusoidal oscillation β€” the fundamental waveform.",
64
+ "waveform": "sine",
65
+ "frequency": 1.0,
66
+ "amplitude": 1.0,
67
+ "damping": 0.0,
68
+ "cycles": 2,
69
+ },
70
+ "Square pulse": {
71
+ "description": "Binary on/off switching at 2 Hz β€” digital clock behavior.",
72
+ "waveform": "square",
73
+ "frequency": 2.0,
74
+ "amplitude": 1.0,
75
+ "damping": 0.0,
76
+ "cycles": 3,
77
+ },
78
+ "Damped sine": {
79
+ "description": "Sine wave with exponential decay β€” models energy dissipation.",
80
+ "waveform": "sine",
81
+ "frequency": 1.0,
82
+ "amplitude": 1.0,
83
+ "damping": 0.1,
84
+ "cycles": 5,
85
+ },
86
+ "Fast triangle": {
87
+ "description": "High-frequency triangle wave β€” linear ramps up and down.",
88
+ "waveform": "triangle",
89
+ "frequency": 5.0,
90
+ "amplitude": 1.0,
91
+ "damping": 0.0,
92
+ "cycles": 3,
93
+ },
94
+ "Sawtooth": {
95
+ "description": "Linear ramp from -1 to +1 β€” used in synthesis and scanning.",
96
+ "waveform": "sawtooth",
97
+ "frequency": 1.0,
98
+ "amplitude": 1.0,
99
+ "damping": 0.0,
100
+ "cycles": 3,
101
+ },
102
+ }
103
+
104
+
105
+ def _load_waveform_preset(name: str) -> tuple[str, float, float, float, int]:
106
+ p = WAVEFORM_PRESETS.get(name, WAVEFORM_PRESETS["(custom)"])
107
+ return p["waveform"], p["frequency"], p["amplitude"], p["damping"], p["cycles"]
108
+
109
+
110
+ # ── Tab 2: Biological Oscillator Presets ──────────────────────────────────
111
+
112
+ BIO_PRESETS: dict[str, dict] = {
113
+ "Standard circadian": {
114
+ "description": "16-hour day / 8-hour night cycle β€” governs sleep-wake patterns.",
115
+ "type": "circadian",
116
+ "day_hours": 16.0,
117
+ "night_hours": 8.0,
118
+ },
119
+ "Fast heartbeat": {
120
+ "description": "120 BPM heartbeat β€” elevated heart rate during exercise.",
121
+ "type": "heartbeat",
122
+ "bpm": 120.0,
123
+ },
124
+ "Cell division": {
125
+ "description": "24-hour cell cycle: G1 (40%), S (30%), G2 (20%), M (10%).",
126
+ "type": "cell_cycle",
127
+ "cycle_hours": 24.0,
128
+ "phases": {"G1": 0.4, "S": 0.3, "G2": 0.2, "M": 0.1},
129
+ },
130
+ }
131
+
132
+
133
+ # ── Tab 1: Waveform computation ──────────────────────────────────────────
134
+
135
+
136
+ def run_waveform(
137
+ preset_name: str,
138
+ waveform_name: str,
139
+ frequency: float,
140
+ amplitude: float,
141
+ damping: float,
142
+ cycles: int,
143
+ ) -> tuple[str, str, str]:
144
+ """Compute waveform samples.
145
+
146
+ Returns (config_banner_html, sample_table_md, stats_md).
147
+ """
148
+ waveform = WaveformType(waveform_name)
149
+ cycles = int(cycles)
150
+
151
+ # Config banner
152
+ banner = (
153
+ f'<div style="padding:10px 14px;border-radius:8px;background:#f0f9ff;'
154
+ f'border:1px solid #bae6fd;margin-bottom:8px">'
155
+ f'<span style="font-weight:700;font-size:1.1em">{waveform.value.upper()}</span> '
156
+ f'<span style="color:#666"> | freq={frequency} Hz | amp={amplitude} | '
157
+ f'damping={damping} | cycles={cycles}</span></div>'
158
+ )
159
+
160
+ # Compute samples (50 samples per cycle)
161
+ samples_per_cycle = 50
162
+ total_samples = samples_per_cycle * cycles
163
+ period = 1.0 / frequency if frequency > 0 else 1.0
164
+
165
+ rows = [
166
+ "| # | Time (s) | Phase | Cycle | Amplitude | Value |",
167
+ "| ---: | ---: | ---: | ---: | ---: | ---: |",
168
+ ]
169
+
170
+ values = []
171
+ for i in range(total_samples + 1):
172
+ t = i * (cycles * period) / total_samples
173
+ # Phase within current cycle
174
+ cycle_time = t / period
175
+ current_cycle = int(cycle_time)
176
+ phase = cycle_time - current_cycle
177
+ if phase < 0:
178
+ phase = 0.0
179
+ if current_cycle >= cycles:
180
+ current_cycle = cycles - 1
181
+ phase = 1.0
182
+
183
+ # Apply damping: amplitude decays exponentially
184
+ damped_amp = amplitude * math.exp(-damping * t) if damping > 0 else amplitude
185
+ raw = _compute_waveform_value(waveform, phase)
186
+ value = raw * damped_amp
187
+ values.append(value)
188
+
189
+ # Show every 5th sample to keep table manageable
190
+ if i % 5 == 0 or i == total_samples:
191
+ rows.append(
192
+ f"| {i} | {t:.4f} | {phase:.3f} | {current_cycle + 1} "
193
+ f"| {damped_amp:.4f} | {value:.4f} |"
194
+ )
195
+
196
+ table_md = "\n".join(rows)
197
+
198
+ # Stats
199
+ min_val = min(values)
200
+ max_val = max(values)
201
+ mean_val = sum(values) / len(values)
202
+ zero_crossings = sum(
203
+ 1 for i in range(1, len(values))
204
+ if (values[i] >= 0) != (values[i - 1] >= 0)
205
+ )
206
+
207
+ stats = f"""### Waveform Statistics
208
+
209
+ | Metric | Value |
210
+ | :--- | :--- |
211
+ | Samples computed | {len(values)} |
212
+ | Min value | {min_val:.4f} |
213
+ | Max value | {max_val:.4f} |
214
+ | Mean value | {mean_val:.4f} |
215
+ | Zero crossings | {zero_crossings} |
216
+ | Period | {period:.4f} s |
217
+ | Total duration | {cycles * period:.4f} s |
218
+
219
+ ### Waveform Guide
220
+
221
+ - **SINE**: Smooth continuous oscillation. Most natural biological rhythm.
222
+ - **SQUARE**: Binary switching. Models on/off states (gene expression toggle).
223
+ - **SAWTOOTH**: Linear ramp with sharp reset. Models gradual buildup + sudden release.
224
+ - **TRIANGLE**: Symmetric linear ramp. Models gradual charge/discharge cycles.
225
+ - **PULSE**: Brief spike. Models action potentials and trigger signals.
226
+ """
227
+
228
+ return banner, table_md, stats
229
+
230
+
231
+ # ── Tab 2: Biological oscillator display ─────────────────────────────────
232
+
233
+ PHASE_COLORS = {
234
+ "Day": "#fbbf24",
235
+ "Night": "#1e40af",
236
+ "Systole": "#ef4444",
237
+ "Diastole": "#3b82f6",
238
+ "G1": "#22c55e",
239
+ "S": "#3b82f6",
240
+ "G2": "#a855f7",
241
+ "M": "#ef4444",
242
+ }
243
+
244
+
245
+ def run_bio_oscillator(preset_name: str) -> tuple[str, str, str]:
246
+ """Display biological oscillator phase structure.
247
+
248
+ Returns (type_banner_html, phase_table_md, explanation_md).
249
+ """
250
+ p = BIO_PRESETS.get(preset_name)
251
+ if not p:
252
+ return "<p>Select a biological oscillator preset.</p>", "", ""
253
+
254
+ osc_type = p["type"]
255
+
256
+ if osc_type == "circadian":
257
+ day_h = p["day_hours"]
258
+ night_h = p["night_hours"]
259
+ total = day_h + night_h
260
+ banner = (
261
+ f'<div style="padding:10px 14px;border-radius:8px;background:#fffbeb;'
262
+ f'border:1px solid #fde68a">'
263
+ f'<span style="font-weight:700;font-size:1.1em">CIRCADIAN OSCILLATOR</span> '
264
+ f'<span style="color:#666"> | {total}h cycle = {day_h}h day + {night_h}h night</span></div>'
265
+ )
266
+
267
+ phases = [
268
+ ("Day", day_h, day_h / total),
269
+ ("Night", night_h, night_h / total),
270
+ ]
271
+
272
+ explanation = f"""### Circadian Rhythm
273
+
274
+ The circadian oscillator governs the sleep-wake cycle across a {total}-hour period.
275
+
276
+ - **Day phase** ({day_h}h, {day_h / total * 100:.0f}%): Active metabolism, high gene expression for repair enzymes, elevated cortisol
277
+ - **Night phase** ({night_h}h, {night_h / total * 100:.0f}%): Reduced metabolism, memory consolidation, growth hormone release
278
+
279
+ In agent systems, circadian oscillators can gate when expensive operations are allowed (day = active processing, night = background maintenance).
280
+ """
281
+
282
+ elif osc_type == "heartbeat":
283
+ bpm = p["bpm"]
284
+ period_ms = 60000 / bpm
285
+ systole_ms = period_ms * 0.35
286
+ diastole_ms = period_ms * 0.65
287
+ banner = (
288
+ f'<div style="padding:10px 14px;border-radius:8px;background:#fef2f2;'
289
+ f'border:1px solid #fecaca">'
290
+ f'<span style="font-weight:700;font-size:1.1em">HEARTBEAT OSCILLATOR</span> '
291
+ f'<span style="color:#666"> | {bpm} BPM | period={period_ms:.0f}ms</span></div>'
292
+ )
293
+
294
+ phases = [
295
+ ("Systole", systole_ms / 1000, 0.35),
296
+ ("Diastole", diastole_ms / 1000, 0.65),
297
+ ]
298
+
299
+ explanation = f"""### Heartbeat Rhythm
300
+
301
+ The heartbeat oscillator at {bpm} BPM has a period of {period_ms:.0f}ms.
302
+
303
+ - **Systole** ({systole_ms:.0f}ms, 35%): Contraction phase β€” pumping output. In agents: burst processing, sending responses.
304
+ - **Diastole** ({diastole_ms:.0f}ms, 65%): Relaxation phase β€” refilling. In agents: gathering input, buffering requests.
305
+
306
+ At {bpm} BPM, the system processes {bpm} pulse cycles per minute, each with a work burst followed by a collection period.
307
+ """
308
+
309
+ else: # cell_cycle
310
+ cycle_h = p["cycle_hours"]
311
+ phase_pcts = p["phases"]
312
+ banner = (
313
+ f'<div style="padding:10px 14px;border-radius:8px;background:#f0fdf4;'
314
+ f'border:1px solid #bbf7d0">'
315
+ f'<span style="font-weight:700;font-size:1.1em">CELL CYCLE OSCILLATOR</span> '
316
+ f'<span style="color:#666"> | {cycle_h}h total cycle</span></div>'
317
+ )
318
+
319
+ phases = [
320
+ (name, cycle_h * pct, pct)
321
+ for name, pct in phase_pcts.items()
322
+ ]
323
+
324
+ explanation = f"""### Cell Division Cycle
325
+
326
+ The cell cycle oscillator spans {cycle_h} hours with four distinct phases:
327
+
328
+ - **G1** ({cycle_h * 0.4:.1f}h, 40%): Gap 1 β€” cell growth, organelle duplication. In agents: planning and resource allocation.
329
+ - **S** ({cycle_h * 0.3:.1f}h, 30%): Synthesis β€” DNA replication. In agents: core work/computation phase.
330
+ - **G2** ({cycle_h * 0.2:.1f}h, 20%): Gap 2 β€” error checking, preparation for division. In agents: validation and testing.
331
+ - **M** ({cycle_h * 0.1:.1f}h, 10%): Mitosis β€” actual division. In agents: spawning sub-agents or forking work.
332
+
333
+ Checkpoints between phases ensure quality: G1/S checkpoint (commit to replication?), G2/M checkpoint (ready to divide?).
334
+ """
335
+
336
+ # Phase breakdown table
337
+ table_lines = [
338
+ "| Phase | Duration | Fraction | Visual |",
339
+ "| :--- | ---: | ---: | :--- |",
340
+ ]
341
+ for name, duration, fraction in phases:
342
+ color = PHASE_COLORS.get(name, "#888")
343
+ bar_width = max(5, int(fraction * 300))
344
+ duration_str = f"{duration:.2f}h" if duration >= 0.01 else f"{duration * 3600:.0f}s"
345
+ table_lines.append(
346
+ f"| **{name}** | {duration_str} | {fraction * 100:.0f}% | "
347
+ f'<span style="display:inline-block;width:{bar_width}px;height:16px;'
348
+ f'background:{color};border-radius:3px"></span> |'
349
+ )
350
+ table_md = "\n".join(table_lines)
351
+
352
+ return banner, table_md, explanation
353
+
354
+
355
+ # ── Gradio UI ──────────────────────────────────────────────────────────────
356
+
357
+
358
+ def build_app() -> gr.Blocks:
359
+ with gr.Blocks(title="Biological Oscillators") as app:
360
+ gr.Markdown(
361
+ "# πŸ”ƒ Biological Oscillator Patterns\n"
362
+ "Explore waveform shapes and biological oscillator phase "
363
+ "structures β€” computed mathematically, no threads needed."
364
+ )
365
+
366
+ with gr.Tabs():
367
+ # ── Tab 1: Waveform Explorer ──────────────────────────────
368
+ with gr.TabItem("Waveform Explorer"):
369
+ with gr.Row():
370
+ wave_preset_dd = gr.Dropdown(
371
+ choices=list(WAVEFORM_PRESETS.keys()),
372
+ value="Sine wave",
373
+ label="Preset",
374
+ scale=2,
375
+ )
376
+ wave_btn = gr.Button("Compute Waveform", variant="primary", scale=1)
377
+
378
+ with gr.Row():
379
+ waveform_dd = gr.Dropdown(
380
+ choices=[w.value for w in WaveformType],
381
+ value="sine",
382
+ label="Waveform",
383
+ )
384
+ freq_sl = gr.Slider(0.1, 10.0, value=1.0, step=0.1, label="Frequency (Hz)")
385
+ amp_sl = gr.Slider(0.1, 2.0, value=1.0, step=0.1, label="Amplitude")
386
+
387
+ with gr.Row():
388
+ damp_sl = gr.Slider(0.0, 0.5, value=0.0, step=0.01, label="Damping factor")
389
+ cycles_sl = gr.Slider(1, 10, value=2, step=1, label="Cycles")
390
+
391
+ wave_banner = gr.HTML(label="Configuration")
392
+ with gr.Row():
393
+ with gr.Column(scale=2):
394
+ wave_table = gr.Markdown(label="Samples")
395
+ with gr.Column(scale=1):
396
+ wave_stats = gr.Markdown(label="Statistics")
397
+
398
+ wave_preset_dd.change(
399
+ fn=_load_waveform_preset,
400
+ inputs=[wave_preset_dd],
401
+ outputs=[waveform_dd, freq_sl, amp_sl, damp_sl, cycles_sl],
402
+ )
403
+
404
+ wave_btn.click(
405
+ fn=run_waveform,
406
+ inputs=[wave_preset_dd, waveform_dd, freq_sl, amp_sl, damp_sl, cycles_sl],
407
+ outputs=[wave_banner, wave_table, wave_stats],
408
+ )
409
+
410
+ # ── Tab 2: Biological Oscillators ─────────────────────────
411
+ with gr.TabItem("Biological Oscillators"):
412
+ with gr.Row():
413
+ bio_preset_dd = gr.Dropdown(
414
+ choices=list(BIO_PRESETS.keys()),
415
+ value="Standard circadian",
416
+ label="Biological Oscillator",
417
+ scale=2,
418
+ )
419
+ bio_btn = gr.Button("Show Phases", variant="primary", scale=1)
420
+
421
+ bio_banner = gr.HTML(label="Oscillator Type")
422
+ bio_table = gr.Markdown(label="Phase Breakdown")
423
+ bio_explanation = gr.Markdown(label="Explanation")
424
+
425
+ bio_btn.click(
426
+ fn=run_bio_oscillator,
427
+ inputs=[bio_preset_dd],
428
+ outputs=[bio_banner, bio_table, bio_explanation],
429
+ )
430
+
431
+ return app
432
+
433
+
434
+ if __name__ == "__main__":
435
+ app = build_app()
436
+ app.launch(theme=gr.themes.Soft())
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio>=4.0
2
+ operon-ai