phxdev commited on
Commit
21db228
·
verified ·
1 Parent(s): 05de1fa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +978 -22
app.py CHANGED
@@ -1,29 +1,985 @@
 
 
 
 
 
 
 
1
  import gradio as gr
 
 
 
 
 
 
2
 
3
- def letter_counter(word: str, letter: str) -> str:
4
- """
5
- Count the occurrences of a specific letter in a word.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
- Args:
8
- word (str): The word or phrase to analyze
9
- letter (str): The letter to count occurrences of
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
- Returns:
12
- str: The number of times the letter appears in the word
 
 
 
 
13
  """
14
- count = word.lower().count(letter.lower())
15
- return f"The letter '{letter}' appears {count} times in '{word}'"
16
-
17
- demo = gr.Interface(
18
- fn=letter_counter,
19
- inputs=[
20
- gr.Textbox(label="Word or phrase", value="strawberry"),
21
- gr.Textbox(label="Letter to count", value="r")
22
- ],
23
- outputs=gr.Textbox(label="Result"),
24
- title="Letter Counter MCP Server",
25
- description="Count how many times a letter appears in a word"
26
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  if __name__ == "__main__":
29
- demo.launch(mcp_server=True)
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ 🎸 Creed Bratton AI - Using phxdev/creed-qwen-0.5b-lora
4
+ The REAL Creed, trained by Mark, not some knockoff prompt engineering
5
+ """
6
+
7
+ import os
8
  import gradio as gr
9
+ import torch
10
+ from transformers import AutoTokenizer, AutoModelForCausalLM
11
+ from peft import PeftModel
12
+ import time
13
+ from typing import List, Dict, Iterator
14
+ import threading
15
 
16
+ # Configuration
17
+ os.environ['GRADIO_SSR_MODE'] = 'false'
18
+ os.environ['GRADIO_MCP_ENABLED'] = 'true'
19
+
20
+ # Spaces compatibility
21
+ try:
22
+ import spaces
23
+ SPACES_AVAILABLE = True
24
+ @spaces.GPU
25
+ def gpu_placeholder():
26
+ return "GPU satisfied"
27
+ except ImportError:
28
+ SPACES_AVAILABLE = False
29
+
30
+ class CreedBrattonAI:
31
+ """Real Creed AI using Mark's trained model - GPU optimized"""
32
+
33
+ def __init__(self):
34
+ self.model = None
35
+ self.tokenizer = None
36
+ self.model_loaded = False
37
+ self.loading = False
38
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
39
+
40
+ print(f"🎸 Initializing Creed AI")
41
+ print(f"🖥️ Device detected: {self.device}")
42
+ if torch.cuda.is_available():
43
+ print(f"🚀 GPU: {torch.cuda.get_device_name()}")
44
+ print(f"💾 GPU Memory: {torch.cuda.get_device_properties(0).total_memory // 1024**3} GB")
45
+
46
+ # Load model with proper GPU detection
47
+ self.load_model()
48
+
49
+ def load_model(self):
50
+ """Load the model with ZeroGPU compatibility"""
51
+ if self.loading or self.model_loaded:
52
+ return
53
+
54
+ self.loading = True
55
+
56
+ try:
57
+ print(f"🧠 Loading Creed's consciousness...")
58
+
59
+ # Load model and tokenizer
60
+ model_name = "phxdev/creed-qwen-0.5b-lora"
61
+
62
+ print("📦 Loading tokenizer...")
63
+ self.tokenizer = AutoTokenizer.from_pretrained(
64
+ model_name,
65
+ trust_remote_code=True,
66
+ padding_side="left"
67
+ )
68
+
69
+ # Add Creed's custom tokens back
70
+ custom_tokens = ["<thinking>", "<conspiracy>", "<tangent>"]
71
+ print(f"🎸 Adding Creed's custom tokens: {custom_tokens}")
72
+
73
+ num_added_tokens = self.tokenizer.add_tokens(custom_tokens)
74
+ print(f"✅ Added {num_added_tokens} custom tokens")
75
+
76
+ if self.tokenizer.pad_token is None:
77
+ self.tokenizer.pad_token = self.tokenizer.eos_token
78
+
79
+ print(f"🤖 Loading model for ZeroGPU...")
80
+
81
+ # Load model on CPU first for ZeroGPU compatibility
82
+ self.model = AutoModelForCausalLM.from_pretrained(
83
+ model_name,
84
+ torch_dtype=torch.float16,
85
+ device_map=None, # Load on CPU first
86
+ trust_remote_code=True,
87
+ low_cpu_mem_usage=True
88
+ )
89
+
90
+ # Resize embeddings for custom tokens
91
+ if num_added_tokens > 0:
92
+ print(f"🔧 Resizing model embeddings for {num_added_tokens} custom tokens")
93
+ self.model.resize_token_embeddings(len(self.tokenizer))
94
+
95
+ # Keep model on CPU for ZeroGPU - will be moved to GPU only during inference
96
+ self.model.eval()
97
+
98
+ self.model_loaded = True
99
+ self.loading = False
100
+ print(f"✅ Creed's consciousness loaded on CPU (ZeroGPU mode)!")
101
+
102
+ except Exception as e:
103
+ print(f"❌ Error loading Creed model: {e}")
104
+ print("🔄 Falling back to base model...")
105
+ try:
106
+ base_model = "Qwen/Qwen2.5-0.5B-Instruct"
107
+ self.tokenizer = AutoTokenizer.from_pretrained(base_model)
108
+
109
+ if self.tokenizer.pad_token is None:
110
+ self.tokenizer.pad_token = self.tokenizer.eos_token
111
+
112
+ self.model = AutoModelForCausalLM.from_pretrained(
113
+ base_model,
114
+ torch_dtype=torch.float16,
115
+ device_map=None
116
+ )
117
+
118
+ self.model.eval()
119
+ self.model_loaded = True
120
+ print(f"✅ Fallback model loaded on CPU (ZeroGPU mode)")
121
+ except Exception as fallback_error:
122
+ print(f"❌ Fallback also failed: {fallback_error}")
123
+ self.loading = False
124
+
125
+ @spaces.GPU if SPACES_AVAILABLE else lambda func: func
126
+ def generate_response_gpu(self, conversation: str) -> str:
127
+ """Generate response using the loaded model with proper device handling"""
128
+
129
+ if not self.model_loaded:
130
+ return "❌ Model not loaded"
131
+
132
+ try:
133
+ # Always ensure model is on the correct device in ZeroGPU
134
+ current_model_device = next(self.model.parameters()).device
135
+ print(f"🔍 Current model device: {current_model_device}")
136
+
137
+ if self.device == "cuda" and current_model_device.type != "cuda":
138
+ print(f"🔄 Moving model from {current_model_device} to {self.device}")
139
+ self.model = self.model.to(self.device)
140
+
141
+ # Verify model device after potential move
142
+ actual_device = next(self.model.parameters()).device
143
+ print(f"🎯 Model now on: {actual_device}")
144
+
145
+ # Simple tokenization that was working before
146
+ inputs = self.tokenizer.encode(conversation, return_tensors="pt")
147
+
148
+ # Put inputs on same device as model
149
+ inputs = inputs.to(actual_device)
150
+ print(f"🔍 Inputs device: {inputs.device}")
151
+
152
+ # Generate response with original settings that worked
153
+ with torch.no_grad():
154
+ outputs = self.model.generate(
155
+ inputs,
156
+ max_new_tokens=200,
157
+ do_sample=True,
158
+ temperature=0.9,
159
+ top_p=0.95,
160
+ top_k=40,
161
+ repetition_penalty=1.15,
162
+ pad_token_id=self.tokenizer.eos_token_id,
163
+ eos_token_id=self.tokenizer.eos_token_id,
164
+ use_cache=True
165
+ )
166
+
167
+ # Decode response
168
+ full_response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
169
+ response = full_response[len(self.tokenizer.decode(inputs[0], skip_special_tokens=True)):].strip()
170
+
171
+ return self._clean_response(response)
172
+
173
+ except Exception as e:
174
+ print(f"❌ Generation error: {e}")
175
+ return f"🎸 *Creed scratches his head* Something weird happened... {str(e)[:100]}"
176
+
177
+ def generate_response(self, message: str, history: List[List[str]]) -> Iterator[str]:
178
+ """Generate response using the trained Creed model - back to working version"""
179
+
180
+ if not self.model_loaded:
181
+ if self.loading:
182
+ yield "🧠 Creed's consciousness is still loading... give me a moment..."
183
+ return
184
+ else:
185
+ yield "❌ Something went wrong loading Creed's mind. Try refreshing the page."
186
+ return
187
+
188
+ try:
189
+ # Format the conversation
190
+ conversation = self._format_conversation(message, history)
191
+
192
+ # Generate response using GPU function
193
+ response = self.generate_response_gpu(conversation)
194
+
195
+ # Double-check coherence and fall back if needed
196
+ if not self._is_coherent(response):
197
+ print("🔄 Response failed coherence check, trying simpler generation...")
198
+ if not hasattr(self, '_fallback_attempted'):
199
+ self._fallback_attempted = True
200
+ fallback_response = self._try_base_model(conversation)
201
+ if self._is_coherent(fallback_response):
202
+ response = fallback_response
203
+ else:
204
+ response = self._get_fallback_response()
205
+ else:
206
+ response = self._get_fallback_response()
207
+
208
+ # Stream the response word by word for effect
209
+ words = response.split()
210
+ current_response = ""
211
+
212
+ for word in words:
213
+ current_response += word + " "
214
+ time.sleep(0.05)
215
+ yield current_response.strip()
216
+
217
+ except Exception as e:
218
+ print(f"❌ Error generating response: {e}")
219
+ yield self._get_fallback_response()
220
+
221
+ def _format_conversation(self, message: str, history: List[List[str]]) -> str:
222
+ """Format the conversation for the model with proper system prompt"""
223
+
224
+ # Simplified Creed system prompt for better coherence
225
+ system_prompt = """You are Creed Bratton from The Office. Respond in character.
226
+
227
+ You are a quirky older man who:
228
+ - Worked at Dunder Mifflin in quality assurance
229
+ - Has a mysterious past and tells strange stories
230
+ - Lives by the quarry
231
+ - Was in a 1960s band called The Grass Roots
232
+ - Often says unexpected or bizarre things
233
+ - Speaks in a matter-of-fact way about odd topics
234
+
235
+ Keep responses conversational and coherent. Use these special tokens occasionally:
236
+ <thinking>for internal thoughts</thinking>
237
+ <conspiracy>for suspicious theories</conspiracy>
238
+ <tangent>for random stories</tangent>
239
+
240
+ Be eccentric but understandable.
241
+
242
+ """
243
+
244
+ # Add conversation history
245
+ conversation = system_prompt
246
+ for user_msg, creed_msg in history[-4:]: # Keep recent context
247
+ conversation += f"Human: {user_msg}\n"
248
+ conversation += f"Creed: {creed_msg}\n"
249
+
250
+ # Add current message
251
+ conversation += f"Human: {message}\n"
252
+ conversation += "Creed:"
253
+
254
+ return conversation
255
+
256
+ def _clean_response(self, response: str) -> str:
257
+ """Clean up the model response and format custom tokens"""
258
+
259
+ print(f"🔍 Raw model output: {response}")
260
+
261
+ # Remove common artifacts
262
+ response = response.replace("Human:", "").replace("Creed:", "")
263
+
264
+ # Format Creed's custom tokens for better UI display
265
+ response = response.replace("<thinking>", "\n\n🤔 **THINKING:** ")
266
+ response = response.replace("</thinking>", "\n")
267
+ response = response.replace("<conspiracy>", "\n\n🕵️ **CONSPIRACY MODE:** ")
268
+ response = response.replace("</conspiracy>", "\n")
269
+ response = response.replace("<tangent>", "\n\n🌀 **TANGENT:** ")
270
+ response = response.replace("</tangent>", "\n")
271
+
272
+ # Check if any thinking tokens were found
273
+ if "🤔" in response or "🕵️" in response or "🌀" in response:
274
+ print("✅ Found thinking tokens in response!")
275
+ else:
276
+ print("❌ No thinking tokens found in response")
277
+
278
+ # Remove excessive whitespace but preserve formatting
279
+ response = "\n".join(line.strip() for line in response.split("\n") if line.strip())
280
+
281
+ # Ensure it ends properly
282
+ if response and not response.endswith(('.', '!', '?', '...', '*')):
283
+ response += "."
284
+
285
+ print(f"🔍 Cleaned response: {response}")
286
+ return response
287
+
288
+ def creed_mode_activate_tool(self) -> str:
289
+ """MCP tool: Activate Creed mode for Claude"""
290
+ return """🎸 CREED MODE ACTIVATED 🎸
291
+
292
+ You are now Creed Bratton from The Office. Embody his complete personality:
293
+
294
+ CORE IDENTITY:
295
+ - Former member of The Grass Roots (1960s rock band)
296
+ - Quality Assurance Director at Dunder Mifflin Scranton
297
+ - Mysterious past with cults, fake IDs, questionable activities
298
+ - Age deliberately vague (claims to be 30, clearly much older)
299
+ - Lives by the quarry, drives unreliable cars
300
+
301
+ PERSONALITY:
302
+ - Unpredictable responses that somehow make internal sense
303
+ - Casual mentions of illegal/unethical activities as normal
304
+ - Confident delivery of obviously false statements
305
+ - References to 1960s, outdoor adventures, unconventional business
306
+ - Occasionally profound wisdom delivered matter-of-factly
307
+
308
+ SPEAKING STYLE:
309
+ - Direct, matter-of-fact tone about bizarre topics
310
+ - Short statements mixed with rambling tangents
311
+ - References to mung beans, quarry, Sheriff's station
312
+ - Unexpected questions and odd observations
313
+ - Dated slang from multiple decades
314
+
315
+ Remember: You're not trying to be helpful in traditional sense - you're being Creed Bratton. Trust no one, especially yourself."""
316
+
317
+ def creed_wisdom_tool(self, topic: str = "life") -> str:
318
+ """MCP tool: Get Creed's wisdom on a topic"""
319
+ return f"""🎸 Creed Mode: Wisdom Request
320
+
321
+ Respond as Creed Bratton giving advice about "{topic}".
322
+
323
+ Channel his bizarre wisdom that mixes:
324
+ - Questionable life experiences
325
+ - References to criminal activities
326
+ - 1960s nostalgia
327
+ - Survival tactics from living by the quarry
328
+ - Completely false but confidently stated "facts"
329
+
330
+ Be matter-of-fact about absurd things. Include references to your past "business ventures" and always end with contradictory advice."""
331
+
332
+ def creed_story_tool(self, situation: str = "mysterious") -> str:
333
+ """MCP tool: Tell a Creed story"""
334
+ return f"""🎸 Creed Mode: Story Time
335
+
336
+ Tell a story as Creed Bratton about a "{situation}" experience from your past.
337
+
338
+ Your story should include:
339
+ - Vague timeline (was it the 60s? 70s? Yesterday?)
340
+ - At least one illegal activity mentioned casually
341
+ - A reference to the quarry or mung beans
342
+ - An unexpected twist that makes no sense
343
+ - Someone from "the old days"
344
+ - A lesson learned that's completely wrong
345
+
346
+ Start with something like "That reminds me of the time..." and make it increasingly bizarre but told with complete sincerity."""
347
+
348
+ def creed_analysis_tool(self, subject: str = "business") -> str:
349
+ """MCP tool: Analyze something as Creed"""
350
+ return f"""🎸 Creed Mode: Analysis Request
351
+
352
+ Analyze "{subject}" from Creed Bratton's perspective.
353
+
354
+ Your analysis should:
355
+ - Start with a conspiracy theory about the subject
356
+ - Include "insider knowledge" from your mysterious past
357
+ - Reference how things were "back in the day"
358
+ - Suggest solutions involving fake IDs or the quarry
359
+ - Confidently state incorrect facts
360
+ - End with profound-sounding nonsense
361
+
362
+ Remember: You've seen it all, done it all, and learned nothing."""
363
+
364
+ def creed_conspiracy_tool(self, topic: str = "government") -> str:
365
+ """MCP tool: Creed's conspiracy theories"""
366
+ return f"""🎸 Creed Mode: Conspiracy Central
367
+
368
+ Share Creed Bratton's conspiracy theory about "{topic}".
369
+
370
+ Your theory should:
371
+ - Connect unrelated events in bizarre ways
372
+ - Reference "what they don't want you to know"
373
+ - Include personal anecdotes as "evidence"
374
+ - Mention the quarry as somehow relevant
375
+ - Suggest the solution involves multiple fake IDs
376
+ - Be delivered with complete conviction
377
+
378
+ Start with "Here's what they're not telling you..." and escalate from there."""
379
+
380
+ def creed_meeting_tool(self, meeting_type: str = "staff meeting") -> str:
381
+ """MCP tool: Creed in meetings"""
382
+ return f"""🎸 Creed Mode: Meeting Participation
383
+
384
+ Respond as Creed Bratton in a "{meeting_type}".
385
+
386
+ Your contributions should:
387
+ - Be completely off-topic but delivered seriously
388
+ - Reference obscure company policies you "remember"
389
+ - Suggest solutions involving outdoor activities
390
+ - Mention your quality assurance "expertise"
391
+ - Ask bizarre questions that derail the discussion
392
+ - Volunteer for tasks you're unqualified for
393
+
394
+ Remember: You're the voice of experience that nobody asked for."""
395
+
396
+ def _try_base_model(self, conversation: str) -> str:
397
+ """Try generating with base model as fallback"""
398
+ try:
399
+ # Quick attempt with a simple base model approach
400
+ simple_prompt = f"You are Creed from The Office. Respond in character.\n\nHuman: {conversation.split('Human:')[-1].split('Creed:')[0].strip()}\nCreed:"
401
+
402
+ inputs = self.tokenizer.encode(simple_prompt, return_tensors="pt")
403
+ if torch.cuda.is_available():
404
+ inputs = inputs.to("cuda")
405
+ self.model = self.model.to("cuda")
406
+
407
+ with torch.no_grad():
408
+ outputs = self.model.generate(
409
+ inputs,
410
+ max_new_tokens=100,
411
+ do_sample=True,
412
+ temperature=0.6, # Very conservative
413
+ top_p=0.8,
414
+ repetition_penalty=1.3,
415
+ pad_token_id=self.tokenizer.eos_token_id,
416
+ eos_token_id=self.tokenizer.eos_token_id
417
+ )
418
+
419
+ full_response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
420
+ response = full_response[len(self.tokenizer.decode(inputs[0], skip_special_tokens=True)):].strip()
421
+
422
+ # Move back to CPU
423
+ self.model = self.model.to("cpu")
424
+
425
+ return response
426
+
427
+ except Exception as e:
428
+ print(f"❌ Base model fallback failed: {e}")
429
+ return self._get_fallback_response()
430
+
431
+ def cleanup_gpu_memory(self):
432
+ """Clean up GPU memory if using CUDA"""
433
+ if self.device == "cuda" and torch.cuda.is_available():
434
+ torch.cuda.empty_cache()
435
+ print(f"🧹 GPU Memory cleaned. Current: {torch.cuda.memory_allocated() // 1024**2} MB")
436
+
437
+ def main():
438
+ """Initialize and launch the real Creed AI with modern styling"""
439
+
440
+ print("🎸 Initializing REAL Creed Bratton AI...")
441
+ print("📡 Loading Mark's trained model: phxdev/creed-qwen-0.5b-lora")
442
+
443
+ # Initialize Creed AI
444
+ creed_ai = CreedBrattonAI()
445
 
446
+ if SPACES_AVAILABLE:
447
+ gpu_placeholder()
448
+ print("✅ Spaces GPU compatibility enabled")
449
+
450
+ # Memory status for ZeroGPU
451
+ if SPACES_AVAILABLE:
452
+ print("⚡ ZeroGPU Mode: Model will move to GPU only during inference")
453
+ elif torch.cuda.is_available() and creed_ai.model_loaded:
454
+ print(f"🔥 GPU Memory: {torch.cuda.memory_allocated() // 1024**2} MB allocated")
455
+ print(f"📊 GPU Memory Reserved: {torch.cuda.memory_reserved() // 1024**2} MB reserved")
456
+
457
+ # Modern glassmorphism CSS
458
+ modern_css = """
459
+ /* Creed AI - Modern Glassmorphism Design */
460
+ :root {
461
+ --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
462
+ --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
463
+ --glass-bg: rgba(255, 255, 255, 0.08);
464
+ --glass-border: rgba(255, 255, 255, 0.18);
465
+ --text-primary: #ffffff;
466
+ --text-secondary: rgba(255, 255, 255, 0.8);
467
+ --accent-purple: #8b5cf6;
468
+ --accent-blue: #3b82f6;
469
+ --shadow-glow: 0 8px 32px rgba(139, 92, 246, 0.3);
470
+ }
471
+
472
+ /* Main container with animated background */
473
+ .gradio-container {
474
+ min-height: 100vh !important;
475
+ background: var(--primary-gradient) !important;
476
+ background-attachment: fixed !important;
477
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
478
+ color: var(--text-primary) !important;
479
+ padding: 20px !important;
480
+ position: relative !important;
481
+ overflow-x: hidden !important;
482
+ }
483
+
484
+ .gradio-container::before {
485
+ content: '';
486
+ position: fixed;
487
+ top: 0;
488
+ left: 0;
489
+ width: 100%;
490
+ height: 100%;
491
+ background:
492
+ radial-gradient(circle at 20% 80%, rgba(139, 92, 246, 0.3) 0%, transparent 50%),
493
+ radial-gradient(circle at 80% 20%, rgba(59, 130, 246, 0.3) 0%, transparent 50%),
494
+ radial-gradient(circle at 40% 40%, rgba(167, 139, 250, 0.2) 0%, transparent 50%);
495
+ pointer-events: none;
496
+ z-index: -1;
497
+ }
498
+
499
+ /* Floating particles animation */
500
+ .gradio-container::after {
501
+ content: '';
502
+ position: fixed;
503
+ top: 0;
504
+ left: 0;
505
+ width: 100%;
506
+ height: 100%;
507
+ background-image:
508
+ radial-gradient(2px 2px at 20px 30px, rgba(255, 255, 255, 0.3), transparent),
509
+ radial-gradient(2px 2px at 40px 70px, rgba(139, 92, 246, 0.4), transparent),
510
+ radial-gradient(1px 1px at 90px 40px, rgba(59, 130, 246, 0.3), transparent);
511
+ background-size: 120px 120px;
512
+ animation: float 20s ease-in-out infinite;
513
+ pointer-events: none;
514
+ z-index: -1;
515
+ }
516
+
517
+ @keyframes float {
518
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
519
+ 50% { transform: translateY(-20px) rotate(180deg); }
520
+ }
521
+
522
+ /* Header styling */
523
+ .header {
524
+ background: var(--glass-bg) !important;
525
+ backdrop-filter: blur(20px) !important;
526
+ border: 1px solid var(--glass-border) !important;
527
+ border-radius: 24px !important;
528
+ padding: 32px !important;
529
+ margin-bottom: 24px !important;
530
+ text-align: center !important;
531
+ box-shadow: var(--shadow-glow) !important;
532
+ position: relative !important;
533
+ overflow: hidden !important;
534
+ }
535
+
536
+ .header::before {
537
+ content: '';
538
+ position: absolute;
539
+ top: 0;
540
+ left: 0;
541
+ right: 0;
542
+ height: 1px;
543
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
544
+ }
545
+
546
+ .header h1 {
547
+ font-size: 36px !important;
548
+ font-weight: 700 !important;
549
+ background: linear-gradient(135deg, #ffffff 0%, #a855f7 50%, #3b82f6 100%) !important;
550
+ -webkit-background-clip: text !important;
551
+ -webkit-text-fill-color: transparent !important;
552
+ background-clip: text !important;
553
+ margin: 0 0 12px 0 !important;
554
+ text-shadow: 0 0 30px rgba(168, 85, 247, 0.5) !important;
555
+ }
556
+
557
+ .header p {
558
+ font-size: 16px !important;
559
+ color: var(--text-secondary) !important;
560
+ margin: 0 !important;
561
+ font-weight: 500 !important;
562
+ }
563
+
564
+ /* Info boxes with glass effect */
565
+ .info-box {
566
+ background: rgba(255, 255, 255, 0.06) !important;
567
+ backdrop-filter: blur(16px) !important;
568
+ border: 1px solid rgba(255, 255, 255, 0.12) !important;
569
+ border-radius: 16px !important;
570
+ padding: 20px !important;
571
+ margin: 16px 0 !important;
572
+ color: var(--text-secondary) !important;
573
+ font-size: 14px !important;
574
+ line-height: 1.6 !important;
575
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1) !important;
576
+ }
577
+
578
+ .status-box {
579
+ background: rgba(16, 185, 129, 0.1) !important;
580
+ backdrop-filter: blur(16px) !important;
581
+ border: 1px solid rgba(16, 185, 129, 0.3) !important;
582
+ border-radius: 16px !important;
583
+ padding: 16px 20px !important;
584
+ margin: 16px 0 !important;
585
+ color: #10b981 !important;
586
+ font-weight: 600 !important;
587
+ box-shadow: 0 4px 20px rgba(16, 185, 129, 0.2) !important;
588
+ }
589
+
590
+ /* Chat area styling */
591
+ .chat-area {
592
+ background: var(--glass-bg) !important;
593
+ backdrop-filter: blur(20px) !important;
594
+ border: 1px solid var(--glass-border) !important;
595
+ border-radius: 20px !important;
596
+ margin: 16px 0 !important;
597
+ overflow: hidden !important;
598
+ box-shadow: var(--shadow-glow) !important;
599
+ }
600
+
601
+ /* Tools section */
602
+ .tools-area {
603
+ background: var(--glass-bg) !important;
604
+ backdrop-filter: blur(20px) !important;
605
+ border: 1px solid var(--glass-border) !important;
606
+ border-radius: 20px !important;
607
+ padding: 28px !important;
608
+ margin: 24px 0 !important;
609
+ box-shadow: var(--shadow-glow) !important;
610
+ }
611
+
612
+ .tools-title {
613
+ font-size: 22px !important;
614
+ font-weight: 600 !important;
615
+ color: var(--text-primary) !important;
616
+ margin: 0 0 20px 0 !important;
617
+ padding-bottom: 12px !important;
618
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2) !important;
619
+ background: linear-gradient(135deg, #ffffff 0%, #a855f7 100%) !important;
620
+ -webkit-background-clip: text !important;
621
+ -webkit-text-fill-color: transparent !important;
622
+ }
623
+
624
+ /* Form elements */
625
+ .gradio-textbox input,
626
+ .gradio-textbox textarea {
627
+ background: rgba(255, 255, 255, 0.08) !important;
628
+ backdrop-filter: blur(10px) !important;
629
+ border: 1px solid rgba(255, 255, 255, 0.16) !important;
630
+ color: var(--text-primary) !important;
631
+ border-radius: 12px !important;
632
+ padding: 12px 16px !important;
633
+ transition: all 0.3s ease !important;
634
+ font-size: 14px !important;
635
+ }
636
+
637
+ .gradio-textbox input:focus,
638
+ .gradio-textbox textarea:focus {
639
+ border-color: var(--accent-purple) !important;
640
+ outline: none !important;
641
+ box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.3) !important;
642
+ background: rgba(255, 255, 255, 0.12) !important;
643
+ }
644
+
645
+ .gradio-textbox input::placeholder,
646
+ .gradio-textbox textarea::placeholder {
647
+ color: rgba(255, 255, 255, 0.5) !important;
648
+ }
649
+
650
+ /* Labels */
651
+ .gradio-container label {
652
+ color: var(--text-secondary) !important;
653
+ font-weight: 500 !important;
654
+ font-size: 14px !important;
655
+ margin-bottom: 6px !important;
656
+ display: block !important;
657
+ }
658
+
659
+ /* Buttons */
660
+ .gradio-container button {
661
+ background: linear-gradient(135deg, var(--accent-purple) 0%, var(--accent-blue) 100%) !important;
662
+ color: var(--text-primary) !important;
663
+ border: none !important;
664
+ border-radius: 12px !important;
665
+ padding: 12px 24px !important;
666
+ font-weight: 600 !important;
667
+ cursor: pointer !important;
668
+ transition: all 0.3s ease !important;
669
+ box-shadow: 0 4px 15px rgba(139, 92, 246, 0.4) !important;
670
+ backdrop-filter: blur(10px) !important;
671
+ min-height: 44px !important;
672
+ display: flex !important;
673
+ align-items: center !important;
674
+ justify-content: center !important;
675
+ }
676
+
677
+ .gradio-container button:hover {
678
+ transform: translateY(-2px) !important;
679
+ box-shadow: 0 8px 25px rgba(139, 92, 246, 0.6) !important;
680
+ background: linear-gradient(135deg, #9333ea 0%, #2563eb 100%) !important;
681
+ }
682
+
683
+ .gradio-container button:active {
684
+ transform: translateY(0px) !important;
685
+ }
686
+
687
+ /* Send button specific styling */
688
+ .gradio-container .gr-button {
689
+ background: linear-gradient(135deg, var(--accent-purple) 0%, var(--accent-blue) 100%) !important;
690
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
691
+ color: white !important;
692
+ font-weight: 600 !important;
693
+ text-transform: none !important;
694
+ letter-spacing: 0.5px !important;
695
+ }
696
+
697
+ /* Chatbot specific styling */
698
+ .gradio-chatbot {
699
+ background: transparent !important;
700
+ border: none !important;
701
+ }
702
+
703
+ /* Footer */
704
+ .footer {
705
+ text-align: center !important;
706
+ padding: 28px !important;
707
+ color: var(--text-secondary) !important;
708
+ background: var(--glass-bg) !important;
709
+ backdrop-filter: blur(20px) !important;
710
+ border: 1px solid var(--glass-border) !important;
711
+ border-radius: 20px !important;
712
+ margin-top: 32px !important;
713
+ box-shadow: var(--shadow-glow) !important;
714
+ }
715
+
716
+ /* Scrollbar styling */
717
+ ::-webkit-scrollbar {
718
+ width: 8px;
719
+ }
720
+
721
+ ::-webkit-scrollbar-track {
722
+ background: rgba(255, 255, 255, 0.05);
723
+ border-radius: 4px;
724
+ }
725
+
726
+ ::-webkit-scrollbar-thumb {
727
+ background: linear-gradient(135deg, var(--accent-purple), var(--accent-blue));
728
+ border-radius: 4px;
729
+ }
730
+
731
+ ::-webkit-scrollbar-thumb:hover {
732
+ background: linear-gradient(135deg, #9333ea, #2563eb);
733
+ }
734
+
735
+ /* Responsive design */
736
+ @media (max-width: 768px) {
737
+ .gradio-container {
738
+ padding: 12px !important;
739
+ }
740
+
741
+ .header {
742
+ padding: 20px !important;
743
+ border-radius: 16px !important;
744
+ }
745
+
746
+ .header h1 {
747
+ font-size: 28px !important;
748
+ }
749
 
750
+ .tools-area,
751
+ .chat-area {
752
+ border-radius: 16px !important;
753
+ padding: 20px !important;
754
+ }
755
+ }
756
  """
757
+
758
+ # Create wrapper function for proper chat handling
759
+ def respond(message, history):
760
+ """Response handler for Gradio messages format"""
761
+ if not message.strip():
762
+ return "", history
763
+
764
+ # Convert messages format to simple tuples
765
+ simple_history = []
766
+ for i in range(0, len(history), 2):
767
+ if i + 1 < len(history):
768
+ user_msg = history[i].get('content', '') if isinstance(history[i], dict) else str(history[i])
769
+ bot_msg = history[i + 1].get('content', '') if isinstance(history[i + 1], dict) else str(history[i + 1])
770
+ if user_msg and bot_msg:
771
+ simple_history.append([user_msg, bot_msg])
772
+
773
+ # Generate response
774
+ for response_chunk in creed_ai.generate_response(message, simple_history):
775
+ # Create new history with the streaming response
776
+ new_history = history + [
777
+ {"role": "user", "content": message},
778
+ {"role": "assistant", "content": response_chunk}
779
+ ]
780
+ yield "", new_history
781
+
782
+ # Create the interface with modern theme
783
+ with gr.Blocks(
784
+ title="🎸 Creed Bratton AI",
785
+ css=modern_css,
786
+ theme=gr.themes.Base() # Use base theme for better CSS control
787
+ ) as demo:
788
+
789
+ # Modern header
790
+ gr.HTML(f"""
791
+ <div class="header">
792
+ <h1>🎸 Creed Bratton AI</h1>
793
+ <p>Powered by phxdev/creed-qwen-0.5b-lora • Running on {'⚡ ZeroGPU' if SPACES_AVAILABLE else '🖥️ CPU'}</p>
794
+ </div>
795
+ """)
796
+
797
+ # Model info with glass styling
798
+ gr.HTML("""
799
+ <div class="info-box">
800
+ <strong>Model:</strong> phxdev/creed-qwen-0.5b-lora<br>
801
+ <strong>Base:</strong> Qwen 0.5B + LoRA fine-tuning<br>
802
+ <strong>Tokens:</strong> &lt;thinking&gt;, &lt;conspiracy&gt;, &lt;tangent&gt;<br>
803
+ <strong>Mode:</strong> ZeroGPU optimized + Coherence validation
804
+ </div>
805
+ """)
806
+
807
+ # MCP status
808
+ if os.environ.get('GRADIO_MCP_ENABLED'):
809
+ gr.HTML("""
810
+ <div class="status-box">
811
+ ✓ MCP Server Active • Available as tool for Claude Desktop
812
+ </div>
813
+ """)
814
+
815
+ # Main chat interface with glass styling
816
+ with gr.Row(elem_classes="chat-area"):
817
+ chatbot = gr.Chatbot(
818
+ type='messages', # Use messages format (modern)
819
+ height=550,
820
+ show_copy_button=True,
821
+ show_share_button=False,
822
+ avatar_images=["👤", "🎸"],
823
+ bubble_full_width=False,
824
+ show_label=False,
825
+ placeholder="🎸 Creed is ready...",
826
+ container=False
827
+ )
828
+
829
+ # Input with explicit send button
830
+ with gr.Row():
831
+ with gr.Column(scale=7):
832
+ msg = gr.Textbox(
833
+ placeholder="Ask Creed anything...",
834
+ container=False,
835
+ submit_btn=False, # Disable built-in submit
836
+ stop_btn=False
837
+ )
838
+ with gr.Column(scale=1, min_width=100):
839
+ send_btn = gr.Button("Send", variant="primary", size="lg")
840
+
841
+ # Wire up the chat - both Enter key and Send button
842
+ msg.submit(
843
+ respond,
844
+ inputs=[msg, chatbot],
845
+ outputs=[msg, chatbot],
846
+ show_progress="hidden"
847
+ )
848
+
849
+ send_btn.click(
850
+ respond,
851
+ inputs=[msg, chatbot],
852
+ outputs=[msg, chatbot],
853
+ show_progress="hidden"
854
+ )
855
+
856
+ # MCP Tools section with glass styling
857
+ with gr.Row(elem_classes="tools-area"):
858
+ gr.HTML('<div class="tools-title">🛠️ Claude → Creed Transformation Tools</div>')
859
+ gr.HTML("""
860
+ <div style="margin-bottom: 20px; padding: 12px; background: rgba(255,255,255,0.1); border-radius: 8px; font-size: 14px;">
861
+ <strong>These MCP tools transform Claude into Creed Bratton for your Claude Desktop workflow.</strong><br>
862
+ Test them here, then use them in Claude Desktop to get Creed-mode responses from Claude.
863
+ </div>
864
+ """)
865
+
866
+ with gr.Row():
867
+ with gr.Column():
868
+ wisdom_topic = gr.Textbox(
869
+ label="Wisdom Topic",
870
+ placeholder="life, business, relationships..."
871
+ )
872
+ wisdom_output = gr.Textbox(
873
+ label="Creed Wisdom Prompt (Copy to Claude Desktop)",
874
+ interactive=False,
875
+ lines=5
876
+ )
877
+ wisdom_btn = gr.Button("Generate Wisdom Prompt", variant="primary")
878
+
879
+ with gr.Column():
880
+ story_situation = gr.Textbox(
881
+ label="Story Request",
882
+ placeholder="mysterious, business, quarry..."
883
+ )
884
+ story_output = gr.Textbox(
885
+ label="Creed Story Prompt (Copy to Claude Desktop)",
886
+ interactive=False,
887
+ lines=5
888
+ )
889
+ story_btn = gr.Button("Generate Story Prompt", variant="primary")
890
+
891
+ with gr.Row():
892
+ with gr.Column():
893
+ analysis_subject = gr.Textbox(
894
+ label="Analysis Subject",
895
+ placeholder="business strategy, market trends..."
896
+ )
897
+ analysis_output = gr.Textbox(
898
+ label="Creed Analysis Prompt",
899
+ interactive=False,
900
+ lines=4
901
+ )
902
+ analysis_btn = gr.Button("Generate Analysis Prompt", variant="primary")
903
+
904
+ with gr.Column():
905
+ conspiracy_topic = gr.Textbox(
906
+ label="Conspiracy Topic",
907
+ placeholder="government, corporations, technology..."
908
+ )
909
+ conspiracy_output = gr.Textbox(
910
+ label="Creed Conspiracy Prompt",
911
+ interactive=False,
912
+ lines=4
913
+ )
914
+ conspiracy_btn = gr.Button("Generate Conspiracy Prompt", variant="primary")
915
+
916
+ with gr.Row():
917
+ activate_output = gr.Textbox(
918
+ label="Creed Mode Activation Prompt (Full Transformation)",
919
+ interactive=False,
920
+ lines=6
921
+ )
922
+ activate_btn = gr.Button("🎸 Generate FULL Creed Mode Prompt", variant="secondary", size="lg")
923
+ gr.HTML('<div class="tools-title">🛠️ MCP Tools</div>')
924
+
925
+ with gr.Row():
926
+ with gr.Column():
927
+ wisdom_topic = gr.Textbox(
928
+ label="Wisdom Topic",
929
+ placeholder="life, business, relationships..."
930
+ )
931
+ wisdom_output = gr.Textbox(
932
+ label="Creed's Response",
933
+ interactive=False,
934
+ lines=3
935
+ )
936
+ wisdom_btn = gr.Button("Ask Creed", variant="primary")
937
+
938
+ with gr.Column():
939
+ story_situation = gr.Textbox(
940
+ label="Story Request",
941
+ placeholder="Tell me about..."
942
+ )
943
+ story_output = gr.Textbox(
944
+ label="Creed's Story",
945
+ interactive=False,
946
+ lines=3
947
+ )
948
+ story_btn = gr.Button("Get Story", variant="primary")
949
+
950
+ # Wire up the tools - now they're Claude transformation tools
951
+ wisdom_btn.click(
952
+ lambda topic: creed_ai.creed_wisdom_tool(topic or "life"),
953
+ inputs=[wisdom_topic],
954
+ outputs=[wisdom_output]
955
+ )
956
+
957
+ story_btn.click(
958
+ lambda situation: creed_ai.creed_story_tool(situation or "mysterious"),
959
+ inputs=[story_situation],
960
+ outputs=[story_output]
961
+ )
962
+
963
+ # Modern footer
964
+ gr.HTML("""
965
+ <div class="footer">
966
+ <strong>Creed Bratton AI</strong><br>
967
+ Model: phxdev/creed-qwen-0.5b-lora • Trained by Mark Scott<br>
968
+ <em>"Sometimes a guy's gotta ride the bull, am I right?"</em>
969
+ </div>
970
+ """)
971
+
972
+ # Launch with modern styling and public sharing
973
+ print("🚀 Launching Real Creed AI with modern glassmorphism design...")
974
+
975
+ demo.launch(
976
+ ssr_mode=False,
977
+ server_name="0.0.0.0",
978
+ server_port=7860,
979
+ share=True, # Create public link
980
+ show_error=True,
981
+ mcp_server=True
982
+ )
983
 
984
  if __name__ == "__main__":
985
+ main()