dryymatt commited on
Commit
0e1554a
Β·
verified Β·
1 Parent(s): 9ec274d

Upload server.py

Browse files
Files changed (1) hide show
  1. server.py +272 -140
server.py CHANGED
@@ -1,28 +1,206 @@
1
  """
2
  ╔══════════════════════════════════════════════════════╗
3
- β•‘ OMNI-VIBE STUDIO β€” Specialized Swarm Server β•‘
4
- β•‘ Pose Architect Β· Pose Painter Β· Pose Auditor β•‘
5
- β•‘ LiteRT Β· Sub-Second Β· Shadow-Hosting β•‘
 
 
 
 
 
 
 
6
  β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
7
  """
8
 
9
- import json, os, uuid, asyncio, time
10
  from pathlib import Path
11
  from aiohttp import web
12
 
13
- # Import the Omni-Vibe core β€” backward-compatible API
14
- from core import (
15
- state as st, sandbox_validate,
16
- Orchestrator, OmniVibeEngine, ReflectSelect,
17
- PoseArchitect, PosePainter, PoseAuditor,
18
- )
19
- from ghost_deploy import ghost, CANONICAL_REPO, PinggyTunnel
20
-
21
- # ─── VISIBILITY OVERRIDE: Port 7860 hardcoded, 0.0.0.0 binding ───
22
- # Binds strictly to 0.0.0.0:7860. Override via WIZARD_PORT only in dev.
23
  PORT = int(os.environ.get("WIZARD_PORT", 7860))
24
  STATIC = Path(__file__).parent / "static"
25
- WIZARD_HAT_COLOR = "steady-gold" # The Athanor is active
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
 
28
  def _sse(ev, d):
@@ -30,13 +208,13 @@ def _sse(ev, d):
30
 
31
 
32
  async def stream_gen(sid, prompt):
33
- """Omni-Vibe streaming pipeline: Pose β†’ Generate β†’ Audit β†’ Heal β†’ Sandbox"""
34
  session = st.sessions[sid]
35
  session["status"] = "streaming"
36
  st.sandbox[sid] = "building"
37
 
38
  yield _sse("phase", {"phase": "pose", "hat": WIZARD_HAT_COLOR})
39
- await asyncio.sleep(0.05)
40
 
41
  pose_plan = st.engine.pose(prompt)
42
  yield _sse("pose", {
@@ -50,66 +228,58 @@ async def stream_gen(sid, prompt):
50
  })
51
 
52
  yield _sse("phase", {"phase": "generate"})
53
- await asyncio.sleep(0.05)
54
-
55
  t0 = time.time()
56
  code, schema = st.engine.generate(prompt)
57
  elapsed = (time.time() - t0) * 1000
58
 
59
  chunk_size = max(1, len(code) // 30)
60
  for i in range(0, len(code), chunk_size):
61
- chunk = code[i:i + chunk_size]
62
- yield _sse("code", {
63
- "chunk": chunk, "partial": code[:i + chunk_size],
64
- "progress": min(100, int((i + chunk_size) / len(code) * 100)),
65
- })
66
- await asyncio.sleep(0.015)
67
 
68
  st.codes[sid] = code
69
  st.sessions[sid]["schema"] = schema
70
- yield _sse("generated", {"chars": len(code), "elapsed_ms": round(elapsed, 1),
71
- "schema": {k: v for k, v in schema.items() if k != "files_needed"}})
72
 
73
  yield _sse("phase", {"phase": "audit"})
74
- await asyncio.sleep(0.05)
75
  findings = st.engine.auditor.audit(code, schema)
76
  yield _sse("audit", {"findings": len(findings),
77
- "errors": sum(1 for f in findings if f.severity == "ERROR"),
78
- "warnings": sum(1 for f in findings if f.severity == "WARN"),
79
- "details": [{"line": f.line, "severity": f.severity, "message": f.message}
80
- for f in findings[:5]]})
81
 
82
  yield _sse("phase", {"phase": "heal"})
83
  code, auto_fixes = st.engine.auditor.heal_findings(code, findings)
84
  st.codes[sid] = code
85
  healed, found, fixed = st.reflect.heal(code)
86
- total_heals = fixed + auto_fixes
87
  for i in range(15):
 
88
  result = sandbox_validate(healed)
89
  if result["success"]: break
90
  healed, _, extra = st.reflect.heal(healed, result["errors"])
91
- total_heals += extra
92
- st.codes[sid] = healed
93
  await asyncio.sleep(0.01)
94
- yield _sse("heal", {"auto_fixes": auto_fixes, "reflect_fixes": fixed,
95
- "total_heals": total_heals, "loop_iterations": i + 1})
96
 
97
  yield _sse("phase", {"phase": "sandbox"})
 
98
  result = sandbox_validate(healed)
99
  if result["success"]:
100
  st.sandbox[sid] = "stable"; st.publish_ready[sid] = True
101
- yield _sse("sandbox", {"status": "stable", "errors": 0, "hat": "steady-gold"})
102
  else:
103
  st.sandbox[sid] = "error"
104
- yield _sse("sandbox", {"status": "error", "errors": result["errors"]})
105
  session["status"] = "complete"
106
- yield _sse("done", {"status": st.sandbox[sid],
107
- "hat": "steady-gold" if st.sandbox[sid] == "stable" else "red-glow"})
108
 
109
 
110
  async def handle_stream(req):
111
- sid = str(uuid.uuid4())[:8]
 
112
  d = await req.json(); prompt = d.get("prompt", "")
 
113
  st.sessions[sid] = {"id": sid, "prompt": prompt, "status": "init"}
114
  st.sandbox[sid] = "building"; st.publish_ready[sid] = False
115
  resp = web.StreamResponse(status=200, headers={
@@ -125,46 +295,23 @@ async def handle_stream(req):
125
 
126
 
127
  async def handle_publish(req):
 
128
  d = await req.json(); sid = d.get("session_id")
129
- vibe_name = d.get("vibe_name", f"omni-vibe-{sid}")
130
  if not st.publish_ready.get(sid):
131
  return web.json_response({"success":False,"error":"Sandbox not stable"}, status=400)
132
- code = st.codes.get(sid, "")
133
  if not code: return web.json_response({"success":False,"error":"No code"}, status=400)
134
  description = d.get("description", st.sessions.get(sid,{}).get("prompt",""))
135
- result = await ghost.publish(code, vibe_name, description[:200] if description else "", port=PORT)
 
136
  if result.get("success"):
137
  st.sessions[sid]["published"] = True
138
  st.sessions[sid]["deploy_url"] = result.get("space_url")
139
  return web.json_response(result)
140
 
141
 
142
- async def handle_health(req):
143
- return web.json_response({
144
- "status": "alive", "engine": "Omni-Vibe Studio β€” Specialized Swarm",
145
- "protocol": "omni-vibe / tokenless / shadow-hosting",
146
- "registry": CANONICAL_REPO, "lifert": True,
147
- "poses": {"architect": "full-stack + zero-DB + Google OAuth",
148
- "painter": "Liquid Glass design system",
149
- "auditor": "step-by-step verification"},
150
- "hat": WIZARD_HAT_COLOR, "hf_token": bool(os.environ.get("HF_TOKEN")),
151
- "binding": "0.0.0.0:7860",
152
- })
153
-
154
-
155
- async def handle_agent(req):
156
- return web.json_response(ghost.generate_agent_card(
157
- "omni-vibe-studio",
158
- "Omni-Vibe Studio β€” Specialized AI Swarm. 0.0.0.0:7860. Zero-config DB, Google OAuth, Liquid Glass.",
159
- "https://dryymatt-wizard-vibe-studio-v2.hf.space"))
160
-
161
-
162
- async def handle_preview(req):
163
- sid = req.query.get("session_id", "")
164
- return web.Response(text=st.codes.get(sid, "<!-- Omni-Vibe -->"), content_type="text/html")
165
-
166
-
167
  async def handle_status(req):
 
168
  sid = req.query.get("session_id", "")
169
  if sid in st.sessions:
170
  s = st.sessions[sid]
@@ -175,11 +322,13 @@ async def handle_status(req):
175
 
176
 
177
  async def handle_vibes(req):
 
178
  vibes = await ghost.list_vibes()
179
  return web.json_response({"vibes":vibes,"count":len(vibes),"registry":CANONICAL_REPO})
180
 
181
 
182
  async def handle_tunnel(req):
 
183
  try:
184
  url = await ghost.tunnel.up(PORT, timeout=10.0)
185
  return web.json_response({"success":bool(url),"url":url})
@@ -188,104 +337,87 @@ async def handle_tunnel(req):
188
 
189
 
190
  async def handle_schema(req):
 
191
  sid = req.query.get("session_id", "")
192
  return web.json_response(st.sessions.get(sid,{}).get("schema",{}))
193
 
194
 
195
- # ═════════════════ ROOT HANDLER ═════════════════
196
- # Returns valid HTML at / β€” no redirects, no auth.
197
- # aiohttp auto-registers HEAD β†’ 200 OK for health probes.
198
-
199
- async def handle_root_get(req):
200
- fp = STATIC / "index.html"
201
- if fp.exists():
202
- return web.Response(text=fp.read_text(), content_type="text/html")
203
- return web.Response(text=INDEX_FALLBACK, content_type="text/html")
204
-
205
-
206
- INDEX_FALLBACK = """<!DOCTYPE html>
207
- <html lang="en">
208
- <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
209
- <title>Omni-Vibe Studio</title>
210
- <style>
211
- :root{--glass-bg:rgba(255,255,255,.03);--purple:#8B5CF6;--cyan:#06B6D4;--green:#10B981;--text:#e0e0ff;--text2:#9090b0;--bg1:#0a0a1a;--bg2:#1a0a2e;--radius:20px}
212
- *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
213
- body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:linear-gradient(135deg,var(--bg1),var(--bg2),#0a1a2e);color:var(--text);min-height:100vh;display:flex;align-items:center;justify-content:center}
214
- .glass{background:var(--glass-bg);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,.06);border-radius:var(--radius);padding:3rem;text-align:center}
215
- .gradient-text{background:linear-gradient(135deg,var(--purple),var(--cyan),var(--green));-webkit-background-clip:text;-webkit-text-fill-color:transparent}
216
- h1{font-size:clamp(2rem,6vw,4rem);font-weight:800;line-height:1.1}
217
- p{color:var(--text2);margin-top:1rem;font-size:1.1rem}
218
- </style></head>
219
- <body><div class="glass">
220
- <h1 class="gradient-text">Omni-Vibe Studio</h1>
221
- <p>Specialized Swarm β€” Steady Gold</p>
222
- <p style="font-size:.85rem;color:#606080;margin-top:2rem">0.0.0.0:7860 Β· Pose Architect Β· Pose Painter Β· Pose Auditor</p>
223
- </div></body></html>"""
224
-
225
 
226
- async def handle_static(req):
227
- path = req.match_info.get("path", "index.html")
228
- fp = STATIC / path
229
- if not fp.exists():
230
- return web.Response(text="Not found", status=404)
231
- ct = {".html":"text/html",".css":"text/css",".js":"application/javascript"}
232
- return web.Response(text=fp.read_text(), content_type=ct.get(fp.suffix,"text/plain"))
233
 
 
 
 
234
 
235
  def create_app():
236
  app = web.Application()
 
 
237
  app.router.add_get("/", handle_root_get)
 
 
 
 
238
  app.router.add_post("/api/stream", handle_stream)
239
  app.router.add_post("/api/publish", handle_publish)
240
  app.router.add_get("/api/status", handle_status)
241
  app.router.add_get("/api/preview", handle_preview)
242
- app.router.add_get("/api/health", handle_health)
243
  app.router.add_get("/api/vibes", handle_vibes)
244
  app.router.add_get("/api/tunnel", handle_tunnel)
245
  app.router.add_get("/api/schema", handle_schema)
246
- app.router.add_get("/.well-known/agent.json", handle_agent)
 
247
  app.router.add_get("/{path:.*}", handle_static)
248
  return app
249
 
250
 
 
 
 
 
251
  def main():
252
- print(f"πŸ§™β€β™‚οΈ Omni-Vibe Studio β€” Specialized Swarm")
253
- print(f" Pose Architect : full-stack + zero-DB + Google OAuth")
254
- print(f" Pose Painter : Liquid Glass design system")
255
- print(f" Pose Auditor : step-by-step verification")
256
- print(f" Athanor : LiteRT engine, sub-second latency")
257
- print(f" Registry : {CANONICAL_REPO}")
 
 
 
 
 
 
 
 
258
  print(f" Binding : 0.0.0.0:{PORT}")
 
 
 
259
  print(f" Hat : {WIZARD_HAT_COLOR}")
260
 
261
- tunnel = ghost.tunnel
 
 
262
  loop = asyncio.new_event_loop()
263
  asyncio.set_event_loop(loop)
264
 
265
- async def tunnel_watchdog(interval: float = 30.0):
266
- await asyncio.sleep(3)
267
- retries = 0
268
- while True:
269
- try:
270
- if tunnel.url is None:
271
- print(f"πŸ”— Tunnel: connecting (retry #{retries})…")
272
- url = await tunnel.up(PORT, timeout=10.0)
273
- if url:
274
- print(f"πŸ”— Tunnel: LIVE β†’ {url}")
275
- retries = 0
276
- else: retries += 1
277
- else:
278
- import aiohttp
279
- async with aiohttp.ClientSession() as s:
280
- async with s.get(tunnel.url, timeout=aiohttp.ClientTimeout(total=5)) as r:
281
- if r.status >= 500:
282
- print(f"πŸ”— Tunnel: DEAD β€” restarting…")
283
- tunnel.down(); retries += 1
284
- except Exception as e:
285
- print(f"πŸ”— Tunnel: error β€” {e}"); retries += 1
286
- await asyncio.sleep(interval * (1 + min(retries, 5) * 0.5))
287
-
288
- loop.create_task(tunnel_watchdog())
289
  web.run_app(create_app(), host="0.0.0.0", port=PORT, handle_signals=True)
290
 
291
 
 
1
  """
2
  ╔══════════════════════════════════════════════════════╗
3
+ β•‘ OMNI-VIBE STUDIO β€” INSTANT WAKE Server β•‘
4
+ β•‘ β•‘
5
+ β•‘ PHASE 1 (<1ms): Bind 0.0.0.0:7860, serve 200 OK β•‘
6
+ β•‘ health + loading HTML immediately. β•‘
7
+ β•‘ PHASE 2 (bg): Lazy-import OmniVibeEngine, β•‘
8
+ β•‘ PoseArchitect, PosePainter, β•‘
9
+ β•‘ PoseAuditor, ReflectSelect. β•‘
10
+ β•‘ β•‘
11
+ β•‘ No import of core/ghost_deploy at module level. β•‘
12
+ β•‘ First byte on wire within milliseconds of CMD. β•‘
13
  β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
14
  """
15
 
16
+ import json, os, sys, asyncio, time
17
  from pathlib import Path
18
  from aiohttp import web
19
 
20
+ # ─── CONSTANTS (no heavy imports) ───
 
 
 
 
 
 
 
 
 
21
  PORT = int(os.environ.get("WIZARD_PORT", 7860))
22
  STATIC = Path(__file__).parent / "static"
23
+ CANONICAL_REPO = "dryymatt/Wizard-Vibe-Studio"
24
+ WIZARD_HAT_COLOR = "steady-gold"
25
+
26
+ # ─── Engine refs β€” lazy-loaded in Phase 2 ───
27
+ _engine = None
28
+ _ghost = None
29
+ _reflect = None
30
+ _engine_loaded = False
31
+
32
+ # ──────────────────────────────────────────────────────
33
+ # PHASE 1: Instant HTML β€” served before any imports
34
+ # ──────────────────────────────────────────────────────
35
+
36
+ LOADING_HTML = """<!DOCTYPE html>
37
+ <html lang="en">
38
+ <head>
39
+ <meta charset="UTF-8">
40
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
41
+ <title>Omni-Vibe Studio</title>
42
+ <style>
43
+ :root{
44
+ --glass-bg:rgba(255,255,255,.03);--glass-border:rgba(255,255,255,.06);
45
+ --purple:#8B5CF6;--cyan:#06B6D4;--green:#10B981;--gold:#F59E0B;
46
+ --text:#e0e0ff;--text2:#9090b0;--text3:#606080;
47
+ --bg1:#0a0a1a;--bg2:#1a0a2e;--radius:20px;--radius-sm:12px;
48
+ --font:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
49
+ }
50
+ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
51
+ body{
52
+ font-family:var(--font);
53
+ background:linear-gradient(135deg,var(--bg1),var(--bg2),#0a1a2e);
54
+ color:var(--text);min-height:100vh;display:flex;
55
+ align-items:center;justify-content:center;
56
+ -webkit-font-smoothing:antialiased;
57
+ }
58
+ ::selection{background:rgba(139,92,246,.5);color:#fff}
59
+ .glass{
60
+ background:var(--glass-bg);backdrop-filter:blur(20px);
61
+ -webkit-backdrop-filter:blur(20px);
62
+ border:1px solid var(--glass-border);border-radius:var(--radius);
63
+ padding:3rem 4rem;text-align:center;
64
+ animation:fadeIn .6s ease-out;
65
+ }
66
+ @keyframes fadeIn{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}
67
+ .gradient-text{
68
+ background:linear-gradient(135deg,var(--purple),var(--cyan),var(--green));
69
+ -webkit-background-clip:text;-webkit-text-fill-color:transparent;
70
+ background-clip:text;
71
+ }
72
+ h1{font-size:clamp(2rem,6vw,4rem);font-weight:800;line-height:1.1}
73
+ p{color:var(--text2);margin-top:1rem;font-size:1.1rem}
74
+ .loading-bar{
75
+ width:240px;height:4px;background:var(--glass-bg);
76
+ border-radius:2px;margin:1.5rem auto 0;overflow:hidden;
77
+ }
78
+ .loading-bar::after{
79
+ content:'';display:block;width:40%;height:100%;
80
+ background:linear-gradient(90deg,var(--purple),var(--cyan),var(--green));
81
+ border-radius:2px;
82
+ animation:slide 1.2s ease-in-out infinite;
83
+ }
84
+ @keyframes slide{0%{transform:translateX(-100%)}100%{transform:translateX(350%)}}
85
+ .status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px}
86
+ .status-dot.gold{background:var(--gold);box-shadow:0 0 8px var(--gold)}
87
+ .pulse{animation:pulse 2s ease-in-out infinite}
88
+ @keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
89
+ /* Wizard hat SVG */
90
+ .wizard-svg{filter:drop-shadow(0 0 20px rgba(139,92,246,.6));margin-bottom:1.5rem}
91
+ .wizard-svg path{animation:morphColors 8s linear infinite}
92
+ @keyframes morphColors{0%,100%{fill:url(#hg)}}
93
+ </style>
94
+ <script>
95
+ // Poll for engine readiness every 500ms
96
+ let pollTimer;
97
+ function checkReady(){
98
+ fetch('/api/health').then(r=>r.json()).then(d=>{
99
+ if(d.engine_loaded){
100
+ clearInterval(pollTimer);
101
+ location.reload();
102
+ }
103
+ }).catch(()=>{});
104
+ }
105
+ pollTimer=setInterval(checkReady,500);
106
+ document.addEventListener('DOMContentLoaded',()=>{
107
+ document.getElementById('status-text').textContent='Waking the Athanor…';
108
+ });
109
+ </script>
110
+ </head>
111
+ <body>
112
+ <div class="glass">
113
+ <svg class="wizard-svg" width="56" height="56" viewBox="0 0 64 64">
114
+ <defs><linearGradient id="hg" x1="0%" y1="0%" x2="100%" y2="100%">
115
+ <stop offset="0%" style="stop-color:#8B5CF6"><animate attributeName="stop-color" values="#8B5CF6;#06B6D4;#10B981;#8B5CF6" dur="6s" repeatCount="indefinite"/></stop>
116
+ <stop offset="50%" style="stop-color:#06B6D4"><animate attributeName="stop-color" values="#06B6D4;#10B981;#8B5CF6;#06B6D4" dur="6s" repeatCount="indefinite"/></stop>
117
+ <stop offset="100%" style="stop-color:#10B981"><animate attributeName="stop-color" values="#10B981;#8B5CF6;#06B6D4;#10B981" dur="6s" repeatCount="indefinite"/></stop>
118
+ </linearGradient></defs>
119
+ <path d="M32 8 L8 48 L32 40 L56 48 Z" fill="url(#hg)" stroke="rgba(255,255,255,.3)" stroke-width="1.5">
120
+ <animateTransform attributeName="transform" type="rotate" values="0 32 28;2 32 28;-1 32 28;0 32 28" dur="6s" repeatCount="indefinite"/>
121
+ </path>
122
+ <ellipse cx="32" cy="48" rx="26" ry="7" fill="none" stroke="url(#hg)" stroke-width="2" opacity=".6">
123
+ <animate attributeName="rx" values="26;28;26" dur="3s" repeatCount="indefinite"/>
124
+ </ellipse>
125
+ </svg>
126
+ <h1 class="gradient-text">Omni-Vibe Studio</h1>
127
+ <p>Specialized Swarm β€” Pose Architect Β· Painter Β· Auditor</p>
128
+ <div class="loading-bar"></div>
129
+ <p style="font-size:.85rem;color:var(--text3);margin-top:1rem">
130
+ <span class="status-dot gold pulse"></span>
131
+ <span id="status-text">Initializing LiteRT engine…</span>
132
+ </p>
133
+ <p style="font-size:.7rem;color:var(--text3);margin-top:1.5rem">0.0.0.0:7860 Β· Steady Gold</p>
134
+ </div>
135
+ </body>
136
+ </html>"""
137
+
138
+
139
+ # ──────────────────────────────────────────────────────
140
+ # PHASE 1 HANDLERS β€” respond immediately, no imports
141
+ # ──────────────────────────────────────────────────────
142
+
143
+ async def handle_root_get(req):
144
+ """GET / β†’ loading HTML if engine not ready, else full Liquid Glass."""
145
+ if _engine_loaded:
146
+ fp = STATIC / "index.html"
147
+ if fp.exists():
148
+ return web.Response(text=fp.read_text(), content_type="text/html")
149
+ return web.Response(text=LOADING_HTML, content_type="text/html")
150
+
151
+
152
+ async def handle_health(req):
153
+ """GET /api/health β†’ 200 OK pulse. First byte on wire in <1ms."""
154
+ return web.json_response({
155
+ "status": "alive",
156
+ "engine": "Omni-Vibe Studio β€” Specialized Swarm",
157
+ "engine_loaded": _engine_loaded,
158
+ "binding": "0.0.0.0:7860",
159
+ "port": PORT,
160
+ "hat": WIZARD_HAT_COLOR,
161
+ "hf_token": bool(os.environ.get("HF_TOKEN")),
162
+ })
163
+
164
+
165
+ async def handle_agent(req):
166
+ """A2A agent card β€” static, no imports needed."""
167
+ return web.json_response({
168
+ "name": "omni-vibe-studio",
169
+ "description": "Omni-Vibe Studio β€” Specialized AI Swarm. 0.0.0.0:7860. LiteRT engine.",
170
+ "url": "https://dryymatt-wizard-vibe-studio-v2.hf.space",
171
+ "provider": {"organization": "Omni-Vibe Studio β€” Litehat System",
172
+ "url": "https://huggingface.co/dryymatt"},
173
+ "version": "3.0.0",
174
+ "capabilities": {"streaming": True, "ghostDeploy": True, "liquidGlass": True},
175
+ })
176
+
177
+
178
+ async def handle_static(req):
179
+ path = req.match_info.get("path", "index.html")
180
+ fp = STATIC / path
181
+ if not fp.exists():
182
+ return web.Response(text="Not found", status=404)
183
+ ct = {".html": "text/html", ".css": "text/css", ".js": "application/javascript"}
184
+ return web.Response(text=fp.read_text(), content_type=ct.get(fp.suffix, "text/plain"))
185
+
186
+
187
+ # ──────────────────────────────────────────────────────
188
+ # PHASE 2 HANDLERS β€” require engine (lazy-loaded)
189
+ # ──────────────────────────────────────────────────────
190
+
191
+ def _get_engine():
192
+ global _engine, _ghost, _reflect, _engine_loaded
193
+ if _engine is None:
194
+ # Lazy-import β€” only when first API call hits
195
+ from core import state as st, sandbox_validate
196
+ from ghost_deploy import ghost as g
197
+ _engine = st.engine
198
+ _ghost = g
199
+ _reflect = st.reflect
200
+ _engine_loaded = True
201
+ print("⚑ Omni-Vibe Engine: LAZY-LOADED")
202
+ from core import state as st
203
+ return st, _ghost
204
 
205
 
206
  def _sse(ev, d):
 
208
 
209
 
210
  async def stream_gen(sid, prompt):
211
+ st, ghost = _get_engine()
212
  session = st.sessions[sid]
213
  session["status"] = "streaming"
214
  st.sandbox[sid] = "building"
215
 
216
  yield _sse("phase", {"phase": "pose", "hat": WIZARD_HAT_COLOR})
217
+ await asyncio.sleep(0.02)
218
 
219
  pose_plan = st.engine.pose(prompt)
220
  yield _sse("pose", {
 
228
  })
229
 
230
  yield _sse("phase", {"phase": "generate"})
231
+ await asyncio.sleep(0.02)
 
232
  t0 = time.time()
233
  code, schema = st.engine.generate(prompt)
234
  elapsed = (time.time() - t0) * 1000
235
 
236
  chunk_size = max(1, len(code) // 30)
237
  for i in range(0, len(code), chunk_size):
238
+ yield _sse("code", {"chunk": code[i:i+chunk_size],
239
+ "partial": code[:i+chunk_size],
240
+ "progress": min(100, int((i+chunk_size)/len(code)*100))})
241
+ await asyncio.sleep(0.01)
 
 
242
 
243
  st.codes[sid] = code
244
  st.sessions[sid]["schema"] = schema
245
+ yield _sse("generated", {"chars": len(code), "elapsed_ms": round(elapsed, 1)})
 
246
 
247
  yield _sse("phase", {"phase": "audit"})
248
+ await asyncio.sleep(0.02)
249
  findings = st.engine.auditor.audit(code, schema)
250
  yield _sse("audit", {"findings": len(findings),
251
+ "errors": sum(1 for f in findings if f.severity=="ERROR"),
252
+ "warnings": sum(1 for f in findings if f.severity=="WARN")})
 
 
253
 
254
  yield _sse("phase", {"phase": "heal"})
255
  code, auto_fixes = st.engine.auditor.heal_findings(code, findings)
256
  st.codes[sid] = code
257
  healed, found, fixed = st.reflect.heal(code)
 
258
  for i in range(15):
259
+ from core import sandbox_validate
260
  result = sandbox_validate(healed)
261
  if result["success"]: break
262
  healed, _, extra = st.reflect.heal(healed, result["errors"])
 
 
263
  await asyncio.sleep(0.01)
 
 
264
 
265
  yield _sse("phase", {"phase": "sandbox"})
266
+ from core import sandbox_validate
267
  result = sandbox_validate(healed)
268
  if result["success"]:
269
  st.sandbox[sid] = "stable"; st.publish_ready[sid] = True
270
+ yield _sse("sandbox", {"status": "stable", "hat": "steady-gold"})
271
  else:
272
  st.sandbox[sid] = "error"
273
+ yield _sse("sandbox", {"status": "error"})
274
  session["status"] = "complete"
275
+ yield _sse("done", {"status": st.sandbox[sid]})
 
276
 
277
 
278
  async def handle_stream(req):
279
+ _get_engine()
280
+ sid = str(__import__('uuid').uuid4())[:8]
281
  d = await req.json(); prompt = d.get("prompt", "")
282
+ st, _ = _get_engine()
283
  st.sessions[sid] = {"id": sid, "prompt": prompt, "status": "init"}
284
  st.sandbox[sid] = "building"; st.publish_ready[sid] = False
285
  resp = web.StreamResponse(status=200, headers={
 
295
 
296
 
297
  async def handle_publish(req):
298
+ st, ghost = _get_engine()
299
  d = await req.json(); sid = d.get("session_id")
 
300
  if not st.publish_ready.get(sid):
301
  return web.json_response({"success":False,"error":"Sandbox not stable"}, status=400)
302
+ code = st.codes.get(sid,"")
303
  if not code: return web.json_response({"success":False,"error":"No code"}, status=400)
304
  description = d.get("description", st.sessions.get(sid,{}).get("prompt",""))
305
+ result = await ghost.publish(code, d.get("vibe_name",f"omni-vibe-{sid}"),
306
+ description[:200] if description else "", port=PORT)
307
  if result.get("success"):
308
  st.sessions[sid]["published"] = True
309
  st.sessions[sid]["deploy_url"] = result.get("space_url")
310
  return web.json_response(result)
311
 
312
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  async def handle_status(req):
314
+ st, _ = _get_engine()
315
  sid = req.query.get("session_id", "")
316
  if sid in st.sessions:
317
  s = st.sessions[sid]
 
322
 
323
 
324
  async def handle_vibes(req):
325
+ _, ghost = _get_engine()
326
  vibes = await ghost.list_vibes()
327
  return web.json_response({"vibes":vibes,"count":len(vibes),"registry":CANONICAL_REPO})
328
 
329
 
330
  async def handle_tunnel(req):
331
+ _, ghost = _get_engine()
332
  try:
333
  url = await ghost.tunnel.up(PORT, timeout=10.0)
334
  return web.json_response({"success":bool(url),"url":url})
 
337
 
338
 
339
  async def handle_schema(req):
340
+ st, _ = _get_engine()
341
  sid = req.query.get("session_id", "")
342
  return web.json_response(st.sessions.get(sid,{}).get("schema",{}))
343
 
344
 
345
+ async def handle_preview(req):
346
+ st, _ = _get_engine()
347
+ sid = req.query.get("session_id", "")
348
+ return web.Response(text=st.codes.get(sid,"<!-- Omni-Vibe -->"), content_type="text/html")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
 
 
 
 
 
 
 
 
350
 
351
+ # ──────────────────────────────────────────────────────
352
+ # APP BUILD β€” routes registered before any imports
353
+ # ──────────────────────────────────────────────────────
354
 
355
  def create_app():
356
  app = web.Application()
357
+
358
+ # Phase 1 routes (available immediately, no engine needed)
359
  app.router.add_get("/", handle_root_get)
360
+ app.router.add_get("/api/health", handle_health)
361
+ app.router.add_get("/.well-known/agent.json", handle_agent)
362
+
363
+ # Phase 2 routes (lazy-load engine on first call)
364
  app.router.add_post("/api/stream", handle_stream)
365
  app.router.add_post("/api/publish", handle_publish)
366
  app.router.add_get("/api/status", handle_status)
367
  app.router.add_get("/api/preview", handle_preview)
 
368
  app.router.add_get("/api/vibes", handle_vibes)
369
  app.router.add_get("/api/tunnel", handle_tunnel)
370
  app.router.add_get("/api/schema", handle_schema)
371
+
372
+ # Static catch-all
373
  app.router.add_get("/{path:.*}", handle_static)
374
  return app
375
 
376
 
377
+ # ──────────────────────────────────────────────────────
378
+ # MAIN β€” bind IMMEDIATELY, then lazy-load engine
379
+ # ──────────────────────────────────────────────────────
380
+
381
  def main():
382
+ # ─── Kill any ghost on port 7860 ───
383
+ import subprocess
384
+ try:
385
+ result = subprocess.run(
386
+ ["fuser", "-k", f"{PORT}/tcp"],
387
+ capture_output=True, timeout=5
388
+ )
389
+ if result.returncode == 0:
390
+ print(f"πŸ”ͺ Killed ghost process on port {PORT}")
391
+ except Exception:
392
+ pass
393
+
394
+ # ─── Print banner (no engine imports yet!) ───
395
+ print(f"πŸ§™β€β™‚οΈ Omni-Vibe Studio β€” INSTANT WAKE")
396
  print(f" Binding : 0.0.0.0:{PORT}")
397
+ print(f" Health pulse : 200 OK in <1ms")
398
+ print(f" Loading HTML : served before engine import")
399
+ print(f" Registry : {CANONICAL_REPO}")
400
  print(f" Hat : {WIZARD_HAT_COLOR}")
401
 
402
+ # ─── Start the aiohttp server FIRST ───
403
+ # At this point, no core.py has been imported.
404
+ # The server binds and responds to health probes immediately.
405
  loop = asyncio.new_event_loop()
406
  asyncio.set_event_loop(loop)
407
 
408
+ async def warm_start():
409
+ """Background: lazy-load the engine after server is bound."""
410
+ await asyncio.sleep(0.5) # Let the server finish binding
411
+ print("⚑ Warm Start: loading OmniVibeEngine…")
412
+ try:
413
+ st, ghost = _get_engine()
414
+ print(f"⚑ Engine loaded: {_engine_loaded}")
415
+ print(f" Poses: Architect, Painter, Auditor β€” all active")
416
+ except Exception as e:
417
+ print(f"⚠ Engine load warning (non-fatal): {e}")
418
+
419
+ loop.create_task(warm_start())
420
+
 
 
 
 
 
 
 
 
 
 
 
421
  web.run_app(create_app(), host="0.0.0.0", port=PORT, handle_signals=True)
422
 
423