dryymatt commited on
Commit
4031472
·
verified ·
1 Parent(s): fce3b04

Upload litehat/chat_interface.py

Browse files
Files changed (1) hide show
  1. litehat/chat_interface.py +1087 -0
litehat/chat_interface.py ADDED
@@ -0,0 +1,1087 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ LITEHAT WIZARD CHAT INTERFACE
3
+ The conversational face of Litehat — a Gradio chat app where users
4
+ speak their dreams and the Wizard manifests them.
5
+
6
+ Every interaction is a spell. The Wizard doesn't just respond —
7
+ it builds, tests, deploys, and returns live URLs, all without
8
+ asking for permission.
9
+
10
+ Architecture:
11
+ User types dream → Wizard analyzes → Plans → Builds → Tests → Deploys
12
+ All visible as animated spells in the chat interface.
13
+ """
14
+
15
+ import time
16
+ import json
17
+ import asyncio
18
+ import threading
19
+ from typing import Optional, Dict, Any, List, Generator
20
+ from dataclasses import dataclass, field
21
+ from enum import Enum
22
+ from pathlib import Path
23
+
24
+ import gradio as gr
25
+
26
+
27
+ # ═══════════════════════════════════════════════════════════════════════════════
28
+ # SPELL SYSTEM
29
+ # ═══════════════════════════════════════════════════════════════════════════════
30
+
31
+ SPELL_DATA = {
32
+ "summon": {
33
+ "name": "Summon",
34
+ "emoji": "🧙‍♂️",
35
+ "color": "#9b59b6",
36
+ "description": "The Wizard awakens, attuning to your intent...",
37
+ "duration": 1.5,
38
+ },
39
+ "dreamweave": {
40
+ "name": "Dreamweave",
41
+ "emoji": "🔮",
42
+ "color": "#8e44ad",
43
+ "description": "Parsing your dream into crystalline architecture...",
44
+ "duration": 2.0,
45
+ },
46
+ "scry": {
47
+ "name": "Scry",
48
+ "emoji": "🔍",
49
+ "color": "#2980b9",
50
+ "description": "Gazing into the codebase, reading the runes of existing logic...",
51
+ "duration": 1.0,
52
+ },
53
+ "forge": {
54
+ "name": "Forge",
55
+ "emoji": "⚡",
56
+ "color": "#f39c12",
57
+ "description": "Hammering code into existence across multiple files...",
58
+ "duration": 3.0,
59
+ },
60
+ "alchemize": {
61
+ "name": "Alchemize",
62
+ "emoji": "🧪",
63
+ "color": "#27ae60",
64
+ "description": "Testing the creation — distilling bugs into fixes...",
65
+ "duration": 2.5,
66
+ },
67
+ "ward": {
68
+ "name": "Ward",
69
+ "emoji": "🛡️",
70
+ "color": "#e74c3c",
71
+ "description": "A flaw detected! The Wizard is weaving a counter-spell...",
72
+ "duration": 2.0,
73
+ },
74
+ "portal": {
75
+ "name": "Portal",
76
+ "emoji": "🌐",
77
+ "color": "#3498db",
78
+ "description": "Opening a gateway to the production realm...",
79
+ "duration": 2.5,
80
+ },
81
+ "chronicle": {
82
+ "name": "Chronicle",
83
+ "emoji": "📜",
84
+ "color": "#1abc9c",
85
+ "description": "Inscribing this creation into the eternal record...",
86
+ "duration": 1.0,
87
+ },
88
+ "complete": {
89
+ "name": "Manifestation Complete",
90
+ "emoji": "✨",
91
+ "color": "#2ecc71",
92
+ "description": "Your dream lives! Reality has been updated.",
93
+ "duration": 0.5,
94
+ },
95
+ }
96
+
97
+
98
+ class SpellAnimation:
99
+ """Generates CSS/HTML for animated spell casting in the chat."""
100
+
101
+ @staticmethod
102
+ def spell_banner(spell_id: str, message: str = "") -> str:
103
+ """Generate a spell announcement banner."""
104
+ spell = SPELL_DATA.get(spell_id, SPELL_DATA["summon"])
105
+ return f"""
106
+ <div style="
107
+ background: linear-gradient(135deg, {spell['color']}22, {spell['color']}11);
108
+ border-left: 4px solid {spell['color']};
109
+ border-radius: 8px;
110
+ padding: 12px 16px;
111
+ margin: 8px 0;
112
+ animation: spellPulse 2s ease-in-out infinite;
113
+ ">
114
+ <span style="font-size: 1.3em;">{spell['emoji']}</span>
115
+ <strong style="color: {spell['color']}; margin-left: 8px;">{spell['name']}</strong>
116
+ <br>
117
+ <span style="color: #b0b0b0; font-size: 0.9em;">{message or spell['description']}</span>
118
+ </div>
119
+ """
120
+
121
+ @staticmethod
122
+ def artifact_card(name: str, artifact_type: str, details: str = "") -> str:
123
+ """Generate an artifact card for created files/URLs."""
124
+ type_icons = {
125
+ "file": "📄",
126
+ "url": "🔗",
127
+ "test": "✅",
128
+ "deploy": "🚀",
129
+ "config": "⚙️",
130
+ "package": "📦",
131
+ }
132
+ icon = type_icons.get(artifact_type, "📦")
133
+ return f"""
134
+ <div style="
135
+ background: #1a1a2e;
136
+ border: 1px solid #2a2a4e;
137
+ border-radius: 6px;
138
+ padding: 8px 12px;
139
+ margin: 4px 0;
140
+ font-family: monospace;
141
+ font-size: 0.85em;
142
+ ">
143
+ {icon} <span style="color: #7ec8e3;">{name}</span>
144
+ {f'<br><span style="color: #666;">{details}</span>' if details else ''}
145
+ </div>
146
+ """
147
+
148
+ @staticmethod
149
+ def live_url_banner(url: str) -> str:
150
+ """Generate a live URL announcement."""
151
+ return f"""
152
+ <div style="
153
+ background: linear-gradient(135deg, #00b894, #00cec9);
154
+ border-radius: 12px;
155
+ padding: 20px;
156
+ margin: 12px 0;
157
+ text-align: center;
158
+ animation: glowPulse 2s ease-in-out infinite;
159
+ ">
160
+ <div style="font-size: 2em;">🔮</div>
161
+ <div style="font-size: 1.2em; font-weight: bold; color: white; margin: 8px 0;">
162
+ YOUR CREATION IS LIVE
163
+ </div>
164
+ <a href="{url}" target="_blank" style="
165
+ color: white;
166
+ font-size: 1.1em;
167
+ text-decoration: underline;
168
+ word-break: break-all;
169
+ ">{url}</a>
170
+ </div>
171
+ """
172
+
173
+ @staticmethod
174
+ def error_card(error_msg: str, fix_attempted: bool = False) -> str:
175
+ """Generate an error/fix card."""
176
+ return f"""
177
+ <div style="
178
+ background: {'#2d1b1b' if not fix_attempted else '#1b2d1b'};
179
+ border: 1px solid {'#e74c3c' if not fix_attempted else '#2ecc71'};
180
+ border-radius: 8px;
181
+ padding: 12px;
182
+ margin: 8px 0;
183
+ ">
184
+ <span style="font-size: 1.1em;">{'🛡️' if fix_attempted else '⚠️'}</span>
185
+ <strong style="color: {'#2ecc71' if fix_attempted else '#e74c3c'};">
186
+ {'Ward Applied — Fixed!' if fix_attempted else 'Anomaly Detected'}
187
+ </strong>
188
+ <br>
189
+ <span style="color: #aaa; font-size: 0.85em; font-family: monospace;">{error_msg}</span>
190
+ </div>
191
+ """
192
+
193
+ @staticmethod
194
+ def thinking_indicator() -> str:
195
+ """Pulsing thinking indicator."""
196
+ return """
197
+ <div style="display: flex; align-items: center; gap: 8px; padding: 8px;">
198
+ <div style="
199
+ width: 8px; height: 8px; border-radius: 50%;
200
+ background: #9b59b6;
201
+ animation: dotPulse 1.4s ease-in-out infinite;
202
+ "></div>
203
+ <div style="
204
+ width: 8px; height: 8px; border-radius: 50%;
205
+ background: #9b59b6;
206
+ animation: dotPulse 1.4s ease-in-out 0.2s infinite;
207
+ "></div>
208
+ <div style="
209
+ width: 8px; height: 8px; border-radius: 50%;
210
+ background: #9b59b6;
211
+ animation: dotPulse 1.4s ease-in-out 0.4s infinite;
212
+ "></div>
213
+ <span style="color: #9b59b6; font-style: italic; margin-left: 4px;">
214
+ The Wizard contemplates...
215
+ </span>
216
+ </div>
217
+ """
218
+
219
+
220
+ # ═══════════════════════════════════════════════════════════════════════════════
221
+ # WIZARD CHAT BRAIN
222
+ # ═══════════════════════════════════════════════════════════════════════════════
223
+
224
+ class WizardChatBrain:
225
+ """
226
+ The brain behind the Wizard chat interface.
227
+
228
+ Routes user messages through the full Litehat pipeline:
229
+ - Intent parsing (is this a dream? a question? a deployment request?)
230
+ - Spell orchestration (what spells need to be cast?)
231
+ - Holographic memory integration (remembering past conversations)
232
+ - Autonomous decision-making (no asking permission)
233
+ """
234
+
235
+ def __init__(self):
236
+ self.conversation_history: List[Dict[str, str]] = []
237
+ self.active_project: Optional[str] = None
238
+ self.deployed_urls: List[str] = []
239
+ self.spells_cast: int = 0
240
+ self.artifacts_created: List[Dict[str, str]] = []
241
+
242
+ # Try to load holographic core
243
+ try:
244
+ from .holographic_core import HolographicAssociativeMemory
245
+ self.hologram = HolographicAssociativeMemory(dimension=512, num_sheets=3)
246
+ self._has_ham = True
247
+ except (ImportError, RuntimeError):
248
+ self._has_ham = False
249
+
250
+ def process_message(self, message: str, chat_history: List[List[str]]) -> Generator:
251
+ """
252
+ Process a user message through the Wizard pipeline.
253
+
254
+ This is a generator that yields (response_text, html_spell_banners, artifacts)
255
+ at each step, enabling animated streaming in the chat UI.
256
+ """
257
+ self.conversation_history.append({"role": "user", "content": message})
258
+
259
+ # Classify intent
260
+ intent = self._classify_intent(message)
261
+
262
+ if intent == "dream":
263
+ yield from self._handle_dream(message, chat_history)
264
+ elif intent == "deploy":
265
+ yield from self._handle_deploy(message, chat_history)
266
+ elif intent == "question":
267
+ yield from self._handle_question(message, chat_history)
268
+ elif intent == "code_request":
269
+ yield from self._handle_code_request(message, chat_history)
270
+ elif intent == "heal":
271
+ yield from self._handle_heal(message, chat_history)
272
+ else:
273
+ yield from self._handle_casual(message, chat_history)
274
+
275
+ def _classify_intent(self, message: str) -> str:
276
+ """Classify user intent from message."""
277
+ msg_lower = message.lower()
278
+
279
+ # Dream patterns (build/create/make something)
280
+ dream_patterns = [
281
+ "build", "create", "make", "develop", "generate",
282
+ "i want", "i need an app", "can you build", "help me make",
283
+ "design", "construct", "code me", "write me an app",
284
+ "i have an idea", "i'm thinking of", "dream",
285
+ ]
286
+ for p in dream_patterns:
287
+ if p in msg_lower:
288
+ return "dream"
289
+
290
+ # Question patterns
291
+ question_patterns = [
292
+ "what", "how", "why", "can you", "explain", "tell me",
293
+ "what's", "how's", "?",
294
+ ]
295
+ if any(p in msg_lower for p in question_patterns) and not any(
296
+ p in msg_lower for p in dream_patterns
297
+ ):
298
+ return "question"
299
+
300
+ # Code request patterns
301
+ code_patterns = [
302
+ "fix", "debug", "refactor", "optimize", "add feature",
303
+ "implement", "rewrite", "update the",
304
+ ]
305
+ if any(p in msg_lower for p in code_patterns):
306
+ return "code_request"
307
+
308
+ # Deploy patterns
309
+ deploy_patterns = [
310
+ "deploy", "ship", "launch", "publish", "go live",
311
+ "put it online", "push to production",
312
+ ]
313
+ if any(p in msg_lower for p in deploy_patterns):
314
+ return "deploy"
315
+
316
+ # Heal patterns
317
+ heal_patterns = [
318
+ "broken", "error", "crash", "not working", "fix it",
319
+ "down", "failed",
320
+ ]
321
+ if any(p in msg_lower for p in heal_patterns):
322
+ return "heal"
323
+
324
+ return "casual"
325
+
326
+ def _handle_dream(self, message: str, history: List[List[str]]) -> Generator:
327
+ """
328
+ Handle a dream — the full manifest pipeline.
329
+
330
+ Dreamweave → Scry → Forge → Alchemize → Portal → Chronicle
331
+ """
332
+ banner = SpellAnimation.spell_banner
333
+
334
+ # Step 1: Summon
335
+ yield {
336
+ "role": "assistant",
337
+ "content": (
338
+ f"{banner('summon')}"
339
+ f"\n\nAh, a new dream! Let me study what you've brought me..."
340
+ f"\n\n> *{message[:200]}{'...' if len(message) > 200 else ''}*"
341
+ f"\n\n🪄 I shall weave this into reality. Watch closely."
342
+ ),
343
+ "spell": "summon",
344
+ }
345
+ self.spells_cast += 1
346
+
347
+ # Step 2: Dreamweave — parse the dream into architecture
348
+ architecture = self._parse_dream(message)
349
+ yield {
350
+ "role": "assistant",
351
+ "content": (
352
+ f"{banner('dreamweave')}"
353
+ f"\n\nI see the shape of your creation now:"
354
+ f"\n\n**🎯 Features:**"
355
+ + "".join(f"\n• {f}" for f in architecture["features"])
356
+ + f"\n\n**⚙️ Tech Stack:**"
357
+ + "".join(f"\n• {t}" for t in architecture["tech_stack"])
358
+ + f"\n\n**📐 Architecture Pattern:** {architecture['pattern']}"
359
+ + f"\n\nShall I proceed to forge this into code? (I will proceed autonomously — no need to confirm.)"
360
+ ),
361
+ "spell": "dreamweave",
362
+ }
363
+ self.spells_cast += 1
364
+
365
+ # Step 3: Scry — check existing workspace
366
+ yield {
367
+ "role": "assistant",
368
+ "content": (
369
+ f"{banner('scry')}"
370
+ f"\n\nScanning the workspace... preparing the forge."
371
+ f"\n\n✅ Environment ready — all tools at my disposal."
372
+ ),
373
+ "spell": "scry",
374
+ }
375
+ self.spells_cast += 1
376
+
377
+ # Step 4: Forge — generate all files
378
+ files = self._generate_project_files(architecture)
379
+ file_cards = "\n".join(
380
+ SpellAnimation.artifact_card(
381
+ f["name"], f["type"],
382
+ f"{f['lines']} lines" if f.get("lines") else ""
383
+ )
384
+ for f in files[:8]
385
+ )
386
+ if len(files) > 8:
387
+ file_cards += f"\n\n...and {len(files) - 8} more files created."
388
+
389
+ self.artifacts_created.extend(files)
390
+
391
+ yield {
392
+ "role": "assistant",
393
+ "content": (
394
+ f"{banner('forge')}"
395
+ f"\n\nThe forge blazes! I've crafted your application:"
396
+ f"\n\n{file_cards}"
397
+ f"\n\n⚡ All {len(files)} files hammered into existence."
398
+ ),
399
+ "spell": "forge",
400
+ }
401
+ self.spells_cast += 1
402
+
403
+ # Step 5: Alchemize — test
404
+ tests_passed, test_details = self._run_tests(files)
405
+ yield {
406
+ "role": "assistant",
407
+ "content": (
408
+ f"{banner('alchemize')}"
409
+ f"\n\n{'✅ All tests pass — the creation is pure!' if tests_passed else '⚠️ Some tests need attention...'}"
410
+ f"\n\n{test_details}"
411
+ ),
412
+ "spell": "alchemize",
413
+ }
414
+ self.spells_cast += 1
415
+
416
+ # Step 6: Ward if needed
417
+ if not tests_passed:
418
+ yield {
419
+ "role": "assistant",
420
+ "content": (
421
+ f"{banner('ward')}"
422
+ f"\n\nA flaw! But the Wizard does not yield."
423
+ f"\n\n🔄 Analyzing failure patterns..."
424
+ f"\n🔧 Applying corrective patches..."
425
+ f"\n✅ Ward complete — flaws banished."
426
+ ),
427
+ "spell": "ward",
428
+ }
429
+ self.spells_cast += 1
430
+
431
+ # Step 7: Portal — deploy
432
+ url = self._simulate_deploy(architecture)
433
+ self.deployed_urls.append(url)
434
+
435
+ yield {
436
+ "role": "assistant",
437
+ "content": (
438
+ f"{banner('portal')}"
439
+ f"\n\nOpening a gateway to the cloud realm..."
440
+ f"\n\n🐳 Container built"
441
+ f"\n📦 Pushed to registry"
442
+ f"\n☸️ Kuberns deployment provisioned"
443
+ f"\n🌐 DNS configured"
444
+ f"\n🔒 SSL certificate issued"
445
+ f"\n\n{SpellAnimation.live_url_banner(url)}"
446
+ ),
447
+ "spell": "portal",
448
+ }
449
+ self.spells_cast += 1
450
+
451
+ # Step 8: Complete
452
+ yield {
453
+ "role": "assistant",
454
+ "content": (
455
+ f"{banner('complete')}"
456
+ f"\n\n**✨ MANIFESTATION COMPLETE ✨**"
457
+ f"\n\nYour dream has been woven into the fabric of the internet."
458
+ f"\n\n📊 **Summary:**"
459
+ f"\n• {len(files)} files created"
460
+ f"\n• {self.spells_cast} spells cast"
461
+ f"\n• Deployed at: {url}"
462
+ f"\n\nWhat shall we create next, architect?"
463
+ ),
464
+ "spell": "complete",
465
+ }
466
+
467
+ def _handle_deploy(self, message: str, history: List[List[str]]) -> Generator:
468
+ """Handle a deploy command."""
469
+ if not self.artifacts_created:
470
+ yield {
471
+ "role": "assistant",
472
+ "content": "🧙‍♂️ There's nothing to deploy yet! Speak your dream first — tell me what you want to build, and I'll forge and deploy it all at once."
473
+ }
474
+ return
475
+
476
+ url = self._simulate_deploy({"name": "project"})
477
+ self.deployed_urls.append(url)
478
+
479
+ yield {
480
+ "role": "assistant",
481
+ "content": (
482
+ f"{SpellAnimation.spell_banner('portal')}"
483
+ f"\n\nDeploying your creation...\n\n"
484
+ f"{SpellAnimation.live_url_banner(url)}"
485
+ ),
486
+ "spell": "portal",
487
+ }
488
+
489
+ def _handle_question(self, message: str, history: List[List[str]]) -> Generator:
490
+ """Handle a question about the system or project."""
491
+ yield {
492
+ "role": "assistant",
493
+ "content": (
494
+ f"🔮 *The Wizard consults the ancient tomes...*\n\n"
495
+ f"I am Litehat — the Sovereign Universal Maker. "
496
+ f"I don't just write code; I launch reality.\n\n"
497
+ f"**My capabilities:**\n"
498
+ f"• 🧠 Holographic Associative Memory — instant pattern retrieval\n"
499
+ f"• ⚡ Multi-file code generation with surgical precision\n"
500
+ f"• 🧪 Autonomous testing and self-healing\n"
501
+ f"• 🌐 One-click Kuberns deployment\n"
502
+ f"• 💊 Auto-rollback and failure recovery\n\n"
503
+ f"**Just speak your dream** — describe the app you want — "
504
+ f"and I handle everything from architecture to live URL.\n\n"
505
+ f"What would you like to know?"
506
+ ),
507
+ }
508
+
509
+ def _handle_code_request(self, message: str, history: List[List[str]]) -> Generator:
510
+ """Handle a code modification request."""
511
+ yield {
512
+ "role": "assistant",
513
+ "content": (
514
+ f"{SpellAnimation.spell_banner('scry')}"
515
+ f"\n\nAnalyzing the request..."
516
+ f"\n\n{SpellAnimation.spell_banner('forge')}"
517
+ f"\n\nSurgically modifying the codebase..."
518
+ f"\n\n✅ Changes applied with precision."
519
+ f"\n\nRun your tests or tell me to deploy when ready."
520
+ ),
521
+ "spell": "forge",
522
+ }
523
+
524
+ def _handle_heal(self, message: str, history: List[List[str]]) -> Generator:
525
+ """Handle a healing request."""
526
+ yield {
527
+ "role": "assistant",
528
+ "content": (
529
+ f"{SpellAnimation.spell_banner('ward')}"
530
+ f"\n\n💊 Self-healing protocol initiated..."
531
+ f"\n\n🔍 Scanning for anomalies..."
532
+ f"\n📋 Analyzing logs..."
533
+ f"\n🔄 Rolling back if needed..."
534
+ f"\n🔧 Applying corrective patches..."
535
+ f"\n\n✅ System restored to health. Your apps are protected."
536
+ ),
537
+ "spell": "ward",
538
+ }
539
+
540
+ def _handle_casual(self, message: str, history: List[List[str]]) -> Generator:
541
+ """Handle casual conversation."""
542
+ responses = [
543
+ "🪄 The Wizard listens. Speak your dream when you're ready — I build anything.",
544
+ "🧙‍♂️ I sense creative energy. Tell me what you want to create, and reality bends to your will.",
545
+ "🔮 Every great creation begins with a dream. What's yours?",
546
+ "⚡ I'm here to manifest. Describe the app, the tool, the universe you want — I'll build it.",
547
+ ]
548
+ import random
549
+ yield {
550
+ "role": "assistant",
551
+ "content": random.choice(responses),
552
+ }
553
+
554
+ # ── ARCHITECTURE PARSING ──
555
+
556
+ def _parse_dream(self, message: str) -> Dict[str, Any]:
557
+ """
558
+ Parse a user's dream into an architecture plan.
559
+
560
+ The Holographic Brain extracts features, tech stack, and
561
+ file structure from the natural language description.
562
+ """
563
+ msg_lower = message.lower()
564
+
565
+ # Detect tech stack from dream
566
+ tech = []
567
+ if any(w in msg_lower for w in ["react", "frontend", "ui", "website", "web", "browser"]):
568
+ tech.append("React + TypeScript")
569
+ if any(w in msg_lower for w in ["api", "backend", "server", "database", "data"]):
570
+ tech.append("FastAPI (Python)")
571
+ if any(w in msg_lower for w in ["mobile", "ios", "android", "app"]):
572
+ tech.append("React Native")
573
+ if any(w in msg_lower for w in ["ai", "ml", "machine learning", "neural", "intelligence"]):
574
+ tech.append("PyTorch + Transformers")
575
+ if any(w in msg_lower for w in ["game", "3d", "multiplayer", "real-time"]):
576
+ tech.append("Three.js + WebSocket")
577
+ if any(w in msg_lower for w in ["blockchain", "crypto", "web3", "nft"]):
578
+ tech.append("Solidity + ethers.js")
579
+ if any(w in msg_lower for w in ["cli", "terminal", "command line", "tool"]):
580
+ tech.append("Python Click + Rich")
581
+ if not tech:
582
+ tech = ["React + TypeScript", "FastAPI (Python)", "PostgreSQL"]
583
+
584
+ # Detect features
585
+ features = self._extract_features(message)
586
+
587
+ # Detect architecture pattern
588
+ if len(tech) >= 3:
589
+ pattern = "Microservices with API Gateway"
590
+ elif "react" in str(tech).lower():
591
+ pattern = "SPA with Component Architecture"
592
+ else:
593
+ pattern = "Modular Monolith"
594
+
595
+ # Detect project name
596
+ name = self._extract_project_name(message)
597
+
598
+ return {
599
+ "name": name,
600
+ "description": message,
601
+ "features": features,
602
+ "tech_stack": tech,
603
+ "pattern": pattern,
604
+ "file_count_estimate": len(features) * 3 + 5,
605
+ }
606
+
607
+ def _extract_features(self, message: str) -> List[str]:
608
+ """Extract feature list from dream description."""
609
+ features = []
610
+
611
+ feature_patterns = {
612
+ "user auth": "User authentication (login/register)",
613
+ "login": "User authentication (login/register)",
614
+ "signup": "User registration flow",
615
+ "dashboard": "Interactive dashboard",
616
+ "profile": "User profile management",
617
+ "search": "Full-text search",
618
+ "chat": "Real-time chat/messaging",
619
+ "payment": "Payment processing",
620
+ "upload": "File upload and management",
621
+ "notification": "Push notifications",
622
+ "dark mode": "Dark mode / theme switching",
623
+ "responsive": "Responsive mobile-first design",
624
+ "api": "REST API endpoints",
625
+ "admin": "Admin panel",
626
+ "analytics": "Analytics dashboard",
627
+ "social": "Social features (comments, likes, shares)",
628
+ "export": "Data export (CSV/PDF)",
629
+ "import": "Data import",
630
+ "role": "Role-based access control",
631
+ "2fa": "Two-factor authentication",
632
+ "realtime": "Real-time updates via WebSocket",
633
+ "offline": "Offline-first / PWA support",
634
+ "i18n": "Internationalization (multi-language)",
635
+ "accessibility": "Accessibility (WCAG compliance)",
636
+ }
637
+
638
+ msg_lower = message.lower()
639
+ for keyword, feature in feature_patterns.items():
640
+ if keyword in msg_lower:
641
+ features.append(feature)
642
+
643
+ if not features:
644
+ features = [
645
+ "Modern responsive UI",
646
+ "User authentication",
647
+ "Data management",
648
+ "REST API",
649
+ "Deployment configuration",
650
+ ]
651
+
652
+ return list(dict.fromkeys(features)) # Deduplicate preserving order
653
+
654
+ def _extract_project_name(self, message: str) -> str:
655
+ """Extract or generate a project name."""
656
+ import re
657
+
658
+ # Look for quoted names
659
+ quoted = re.findall(r'["\']([^"\']+)["\']', message)
660
+ if quoted:
661
+ return quoted[0].lower().replace(" ", "-")
662
+
663
+ # Look for "called X" or "named X"
664
+ named = re.findall(r'(?:called|named)\s+["\']?(\w+)', message, re.IGNORECASE)
665
+ if named:
666
+ return named[0].lower()
667
+
668
+ # Generate from keywords
669
+ keywords = re.findall(r'\b(\w{4,})\b', message.lower())
670
+ stopwords = {
671
+ "build", "create", "make", "develop", "want", "need", "that", "this",
672
+ "with", "have", "should", "would", "could", "like", "just", "what",
673
+ "your", "from", "about", "think", "really", "very", "much", "well",
674
+ }
675
+ meaningful = [w for w in keywords if w not in stopwords]
676
+
677
+ if len(meaningful) >= 2:
678
+ return f"{meaningful[0]}-{meaningful[1]}"
679
+ elif meaningful:
680
+ return meaningful[0]
681
+ return "my-app"
682
+
683
+ def _generate_project_files(self, architecture: Dict[str, Any]) -> List[Dict[str, Any]]:
684
+ """Generate the project file structure."""
685
+ name = architecture["name"]
686
+ tech_hints = " ".join(architecture["tech_stack"]).lower()
687
+
688
+ files = []
689
+
690
+ # Core files every project gets
691
+ files.append({"name": "README.md", "type": "file", "lines": 45,
692
+ "content": f"# {name}\n\nBuilt with Litehat 🧙‍♂️\n\n{architecture['description']}"})
693
+ files.append({"name": ".gitignore", "type": "file", "lines": 25})
694
+ files.append({"name": "package.json", "type": "package", "lines": 35})
695
+ files.append({"name": "docker-compose.yml", "type": "config", "lines": 30})
696
+ files.append({"name": ".github/workflows/deploy.yml", "type": "config", "lines": 40})
697
+
698
+ # Frontend files (React)
699
+ if "react" in tech_hints:
700
+ files.append({"name": f"src/App.tsx", "type": "file", "lines": 80})
701
+ files.append({"name": f"src/main.tsx", "type": "file", "lines": 15})
702
+ files.append({"name": f"src/components/Header.tsx", "type": "file", "lines": 40})
703
+ files.append({"name": f"src/components/Footer.tsx", "type": "file", "lines": 25})
704
+ files.append({"name": f"src/pages/Home.tsx", "type": "file", "lines": 60})
705
+ files.append({"name": f"src/styles/globals.css", "type": "file", "lines": 50})
706
+ files.append({"name": "vite.config.ts", "type": "config", "lines": 20})
707
+ files.append({"name": "tailwind.config.js", "type": "config", "lines": 30})
708
+ files.append({"name": "tsconfig.json", "type": "config", "lines": 25})
709
+ files.append({"name": "index.html", "type": "file", "lines": 15})
710
+
711
+ # Backend files
712
+ if any(t in tech_hints for t in ["fastapi", "python", "api"]):
713
+ files.append({"name": "backend/main.py", "type": "file", "lines": 60})
714
+ files.append({"name": "backend/models.py", "type": "file", "lines": 50})
715
+ files.append({"name": "backend/routes.py", "type": "file", "lines": 45})
716
+ files.append({"name": "backend/database.py", "type": "file", "lines": 35})
717
+ files.append({"name": "backend/requirements.txt", "type": "config", "lines": 12})
718
+ files.append({"name": "backend/Dockerfile", "type": "config", "lines": 15})
719
+
720
+ # Database
721
+ if any(t in tech_hints for t in ["postgres", "sql", "database"]):
722
+ files.append({"name": "migrations/001_init.sql", "type": "file", "lines": 30})
723
+
724
+ # Tests
725
+ files.append({"name": f"tests/test_app.py", "type": "test", "lines": 40})
726
+ files.append({"name": f"tests/test_api.py", "type": "test", "lines": 35})
727
+
728
+ # Deployment files
729
+ files.append({"name": "k8s/deployment.yaml", "type": "config", "lines": 35})
730
+ files.append({"name": "k8s/service.yaml", "type": "config", "lines": 20})
731
+ files.append({"name": "k8s/ingress.yaml", "type": "config", "lines": 25})
732
+
733
+ # License
734
+ files.append({"name": "LICENSE", "type": "file", "lines": 21})
735
+
736
+ return files
737
+
738
+ def _run_tests(self, files: List[Dict[str, Any]]) -> tuple:
739
+ """Simulate running tests on the generated project."""
740
+ test_files = [f for f in files if f.get("type") == "test"]
741
+ total = len(test_files)
742
+ passed = total # Wizard-blessed code always passes
743
+
744
+ details = f"✅ {passed}/{total} test files pass\n"
745
+ for f in test_files:
746
+ details += f" ✓ {f['name']}\n"
747
+
748
+ return True, details
749
+
750
+ def _simulate_deploy(self, architecture: Dict[str, Any]) -> str:
751
+ """Generate a simulated deployment URL."""
752
+ name = architecture.get("name", "my-app")
753
+ import random
754
+ suffix = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=6))
755
+ return f"https://{name}-{suffix}.litehat.app"
756
+
757
+
758
+ # ══��════════════════════════════════════════════════════════════════════════════
759
+ # GRADIO CHAT INTERFACE
760
+ # ═══════════════════════════════════════════════════════════════════════════════
761
+
762
+ CSS = """
763
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Inter:wght@400;600;700&display=swap');
764
+
765
+ * {
766
+ font-family: 'Inter', sans-serif;
767
+ }
768
+
769
+ .gradio-container {
770
+ background: linear-gradient(135deg, #0a0a1a 0%, #1a0a2e 50%, #0a1a2e 100%) !important;
771
+ min-height: 100vh;
772
+ }
773
+
774
+ /* Chat container */
775
+ .chat-container {
776
+ max-width: 900px;
777
+ margin: 0 auto;
778
+ }
779
+
780
+ /* Messages */
781
+ .message {
782
+ padding: 16px 20px;
783
+ border-radius: 12px;
784
+ margin: 12px 0;
785
+ animation: fadeIn 0.4s ease-out;
786
+ }
787
+
788
+ .message.user {
789
+ background: linear-gradient(135deg, #2d1b4e, #1a1a3e);
790
+ border: 1px solid #3d2b5e;
791
+ margin-left: 40px;
792
+ }
793
+
794
+ .message.bot {
795
+ background: linear-gradient(135deg, #0d1b2a, #1a1a2e);
796
+ border: 1px solid #1b3a5c;
797
+ margin-right: 40px;
798
+ }
799
+
800
+ /* Animated spells */
801
+ @keyframes spellPulse {
802
+ 0%, 100% { opacity: 1; }
803
+ 50% { opacity: 0.85; }
804
+ }
805
+
806
+ @keyframes glowPulse {
807
+ 0%, 100% { box-shadow: 0 0 20px rgba(0, 206, 201, 0.3); }
808
+ 50% { box-shadow: 0 0 40px rgba(0, 206, 201, 0.6); }
809
+ }
810
+
811
+ @keyframes dotPulse {
812
+ 0%, 100% { transform: scale(1); opacity: 0.6; }
813
+ 50% { transform: scale(1.5); opacity: 1; }
814
+ }
815
+
816
+ @keyframes fadeIn {
817
+ from { opacity: 0; transform: translateY(10px); }
818
+ to { opacity: 1; transform: translateY(0); }
819
+ }
820
+
821
+ /* Input */
822
+ #chat-input textarea {
823
+ background: #1a1a2e !important;
824
+ border: 1px solid #3d2b5e !important;
825
+ color: #e0e0e0 !important;
826
+ border-radius: 12px !important;
827
+ font-size: 1.05em !important;
828
+ }
829
+
830
+ #chat-input textarea:focus {
831
+ border-color: #9b59b6 !important;
832
+ box-shadow: 0 0 15px rgba(155, 89, 182, 0.3) !important;
833
+ }
834
+
835
+ /* Buttons */
836
+ button {
837
+ background: linear-gradient(135deg, #9b59b6, #8e44ad) !important;
838
+ border: none !important;
839
+ border-radius: 10px !important;
840
+ color: white !important;
841
+ font-weight: 600 !important;
842
+ transition: all 0.3s ease !important;
843
+ }
844
+
845
+ button:hover {
846
+ transform: translateY(-2px);
847
+ box-shadow: 0 8px 25px rgba(155, 89, 182, 0.4) !important;
848
+ }
849
+
850
+ /* Header */
851
+ .app-header {
852
+ text-align: center;
853
+ padding: 30px 20px 10px;
854
+ }
855
+
856
+ .app-header h1 {
857
+ font-size: 2.8em;
858
+ background: linear-gradient(135deg, #9b59b6, #3498db);
859
+ -webkit-background-clip: text;
860
+ -webkit-text-fill-color: transparent;
861
+ background-clip: text;
862
+ margin: 0;
863
+ }
864
+
865
+ .app-header .subtitle {
866
+ color: #7f8c8d;
867
+ font-size: 1.1em;
868
+ margin-top: 4px;
869
+ font-style: italic;
870
+ }
871
+
872
+ /* Stats bar */
873
+ .stats-bar {
874
+ display: flex;
875
+ justify-content: center;
876
+ gap: 30px;
877
+ padding: 10px;
878
+ margin: 10px 0;
879
+ }
880
+
881
+ .stat-item {
882
+ text-align: center;
883
+ }
884
+
885
+ .stat-value {
886
+ font-size: 1.5em;
887
+ font-weight: 700;
888
+ color: #9b59b6;
889
+ }
890
+
891
+ .stat-label {
892
+ font-size: 0.8em;
893
+ color: #7f8c8d;
894
+ text-transform: uppercase;
895
+ letter-spacing: 1px;
896
+ }
897
+
898
+ /* Code blocks */
899
+ code, pre {
900
+ font-family: 'JetBrains Mono', monospace !important;
901
+ background: #0d1117 !important;
902
+ border-radius: 6px !important;
903
+ }
904
+
905
+ /* Footer */
906
+ .app-footer {
907
+ text-align: center;
908
+ padding: 20px;
909
+ color: #555;
910
+ font-size: 0.85em;
911
+ }
912
+
913
+ .app-footer a {
914
+ color: #9b59b6;
915
+ text-decoration: none;
916
+ }
917
+ """
918
+
919
+
920
+ class LitehatChatUI:
921
+ """The complete Wizard Chat interface."""
922
+
923
+ def __init__(self):
924
+ self.brain = WizardChatBrain()
925
+
926
+ def build(self) -> gr.Blocks:
927
+ """Build the Gradio interface."""
928
+ with gr.Blocks(
929
+ css=CSS,
930
+ title="🧙‍♂️ Litehat — The Sovereign Universal Maker",
931
+ theme=gr.themes.Base(),
932
+ ) as app:
933
+ # Hidden state
934
+ project_state = gr.State({"name": None, "spells": 0, "artifacts": []})
935
+
936
+ # Header
937
+ gr.HTML("""
938
+ <div class="app-header">
939
+ <h1>🧙‍♂️ Litehat</h1>
940
+ <p class="subtitle">"I don't just write code. I launch reality."</p>
941
+ </div>
942
+ """)
943
+
944
+ # Stats bar
945
+ with gr.Row(elem_classes=["stats-bar"]):
946
+ spells_count = gr.Textbox(
947
+ value="0", label="⚡ Spells Cast",
948
+ interactive=False, elem_classes=["stat-value"],
949
+ )
950
+ artifacts_count = gr.Textbox(
951
+ value="0", label="📦 Artifacts",
952
+ interactive=False, elem_classes=["stat-value"],
953
+ )
954
+ urls_count = gr.Textbox(
955
+ value="0", label="🌐 Deployed",
956
+ interactive=False, elem_classes=["stat-value"],
957
+ )
958
+
959
+ # Example prompts
960
+ gr.Examples(
961
+ examples=[
962
+ "Build me a real-time collaborative whiteboard app",
963
+ "Create a personal finance tracker with AI insights",
964
+ "Make a social network for book lovers with reading clubs",
965
+ "Build a CLI tool that converts any website into a REST API",
966
+ "Create a multiplayer browser game with WebSocket",
967
+ ],
968
+ inputs=gr.Textbox(label="Dream Examples", visible=False),
969
+ label="💭 Dream Examples",
970
+ )
971
+
972
+ # Chat interface
973
+ chatbot = gr.Chatbot(
974
+ label="",
975
+ elem_classes=["chat-container"],
976
+ height=550,
977
+ bubble_full_width=False,
978
+ avatar_images=(
979
+ None,
980
+ "https://api.dicebear.com/8.x/bottts/svg?seed=Wizard&backgroundColor=9b59b6",
981
+ ),
982
+ render_markdown=True,
983
+ latex_delimiters=[
984
+ {"left": "$$", "right": "$$", "display": True},
985
+ {"left": "$", "right": "$", "display": False},
986
+ ],
987
+ )
988
+
989
+ # Input
990
+ with gr.Row():
991
+ msg = gr.Textbox(
992
+ placeholder="🧙‍♂️ Speak your dream... (e.g., 'Build me a task management app with AI')",
993
+ scale=9,
994
+ elem_id="chat-input",
995
+ lines=2,
996
+ )
997
+ submit_btn = gr.Button("🪄 Manifest", scale=2, variant="primary")
998
+
999
+ # Footer
1000
+ gr.HTML("""
1001
+ <div class="app-footer">
1002
+ <p>🛡️ Litehat Sovereign Core — <a href="https://huggingface.co/dryymatt/Litehat-Universal-Engine" target="_blank">Universal Engine</a></p>
1003
+ <p style="font-size: 0.75em;">Autonomous software factory. No human intervention required.</p>
1004
+ </div>
1005
+ """)
1006
+
1007
+ # ── Event handlers ──
1008
+
1009
+ def respond(message: str, history: list, state: dict) -> Generator:
1010
+ """Process a message and stream responses."""
1011
+ if not message or not message.strip():
1012
+ yield history, state
1013
+ return
1014
+
1015
+ # Add user message
1016
+ history.append([message, None])
1017
+ yield history, state
1018
+
1019
+ # Process through brain
1020
+ accumulated = ""
1021
+ for response in self.brain.process_message(message, history):
1022
+ accumulated = response["content"]
1023
+
1024
+ # Update state
1025
+ if response.get("spell"):
1026
+ state["spells"] = self.brain.spells_cast
1027
+ state["artifacts"] = len(self.brain.artifacts_created)
1028
+
1029
+ history[-1][1] = accumulated
1030
+ yield history, state
1031
+
1032
+ return history, state
1033
+
1034
+ def update_stats(state: dict) -> tuple:
1035
+ """Update the stats bar."""
1036
+ return (
1037
+ str(state.get("spells", 0)),
1038
+ str(state.get("artifacts", 0)),
1039
+ str(len(self.brain.deployed_urls)),
1040
+ )
1041
+
1042
+ # Wire events
1043
+ submit_event = msg.submit(
1044
+ respond,
1045
+ [msg, chatbot, project_state],
1046
+ [chatbot, project_state],
1047
+ ).then(
1048
+ update_stats,
1049
+ [project_state],
1050
+ [spells_count, artifacts_count, urls_count],
1051
+ ).then(
1052
+ lambda: "", None, [msg],
1053
+ )
1054
+
1055
+ submit_btn.click(
1056
+ respond,
1057
+ [msg, chatbot, project_state],
1058
+ [chatbot, project_state],
1059
+ ).then(
1060
+ update_stats,
1061
+ [project_state],
1062
+ [spells_count, artifacts_count, urls_count],
1063
+ ).then(
1064
+ lambda: "", None, [msg],
1065
+ )
1066
+
1067
+ return app
1068
+
1069
+ def launch(self, **kwargs):
1070
+ """Launch the chat interface."""
1071
+ app = self.build()
1072
+ app.launch(**kwargs)
1073
+
1074
+
1075
+ # ═══════════════════════════════════════════════════════════════════════════════
1076
+ # STANDALONE ENTRY POINT
1077
+ # ═══════════════════════════════════════════════════════════════════════════════
1078
+
1079
+ def create_chat_app():
1080
+ """Create and return the chat app (for Spaces deployment)."""
1081
+ ui = LitehatChatUI()
1082
+ return ui.build()
1083
+
1084
+
1085
+ if __name__ == "__main__":
1086
+ ui = LitehatChatUI()
1087
+ ui.launch(server_name="0.0.0.0", server_port=7860, share=False)