phxdev commited on
Commit
85f63f5
Β·
verified Β·
1 Parent(s): 4c3a213

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +704 -785
app.py CHANGED
@@ -1,44 +1,26 @@
1
  # Create wrapper function for proper chat handling
2
- def respond(message, history):
3
- """Response handler for Gradio messages format"""
4
- if not message.strip():
5
- return "", history
6
-
7
- print(f"πŸ” Input message: {message}")
8
- print(f"πŸ” History length: {len(history)}")
9
-
10
- # Convert messages format to simple tuples for model processing
11
- simple_history = []
12
- for i in range(0, len(history) - 1, 2):
13
- if i + 1 < len(history):
14
- user_msg = history[i].get('content', '') if isinstance(history[i], dict) else str(history[i])
15
- bot_msg = history[i + 1].get('content', '') if isinstance(history[i + 1], dict) else str(history[i + 1])
16
- if user_msg and bot_msg:
17
- simple_history.append([user_msg, bot_msg])
18
-
19
- print(f"πŸ” Simple history: {simple_history}")
20
-
21
- # Generate response with debugging
22
- try:
23
- response_generator = creed_ai.generate_response(message, simple_history)
24
- final_response = ""
25
-
26
- for response_chunk in response_generator:
27
- final_response = response_chunk
28
  # Create new history with the streaming response
29
  new_history = history + [
30
  {"role": "user", "content": message},
31
  {"role": "assistant", "content": response_chunk}
32
  ]
33
- yield "", new_history
34
-
35
- except Exception as e:
36
- print(f"❌ Error in respond: {e}")
37
- error_history = history + [
38
- {"role": "user", "content": message},
39
- {"role": "assistant", "content": f"🎸 *Creed's brain malfunctioned* Error: {str(e)[:100]}"}
40
- ]
41
- yield "", error_history#!/usr/bin/env python3
42
  """
43
  🎸 Creed Bratton AI - Using phxdev/creed-qwen-0.5b-lora
44
  The REAL Creed, trained by Mark, not some knockoff prompt engineering
@@ -59,267 +41,216 @@ os.environ['GRADIO_MCP_ENABLED'] = 'true'
59
 
60
  # Spaces compatibility
61
  try:
62
- import spaces
63
- SPACES_AVAILABLE = True
64
- @spaces.GPU
65
- def gpu_placeholder():
66
- return "GPU satisfied"
67
  except ImportError:
68
- SPACES_AVAILABLE = False
69
 
70
  class CreedBrattonAI:
71
- """Real Creed AI using Mark's trained model - GPU optimized"""
72
-
73
- def __init__(self):
74
- self.model = None
75
- self.tokenizer = None
76
- self.model_loaded = False
77
- self.loading = False
78
- self.device = "cuda" if torch.cuda.is_available() else "cpu"
79
 
80
- print(f"🎸 Initializing Creed AI")
81
- print(f"πŸ–₯️ Device detected: {self.device}")
82
- if torch.cuda.is_available():
83
- print(f"πŸš€ GPU: {torch.cuda.get_device_name()}")
84
- print(f"πŸ’Ύ GPU Memory: {torch.cuda.get_device_properties(0).total_memory // 1024**3} GB")
85
-
86
- # Load model with proper GPU detection
87
- self.load_model()
88
-
89
- def load_model(self):
90
- """Load the model with GPU optimization when available"""
91
- if self.loading or self.model_loaded:
92
- return
93
-
94
- self.loading = True
95
-
96
- try:
97
- print(f"🧠 Loading Creed's consciousness on {self.device}...")
98
-
99
- # Load model and tokenizer
100
- model_name = "phxdev/creed-qwen-0.5b-lora"
101
-
102
- print("πŸ“¦ Loading tokenizer...")
103
- self.tokenizer = AutoTokenizer.from_pretrained(
104
- model_name,
105
- trust_remote_code=True,
106
- padding_side="left"
107
- )
108
-
109
- # Fix pad token issue
110
- if self.tokenizer.pad_token is None:
111
- self.tokenizer.pad_token = self.tokenizer.unk_token or "[PAD]"
112
- print(f"πŸ”§ Set pad_token to: {self.tokenizer.pad_token}")
113
-
114
- # Add Creed's custom tokens
115
- custom_tokens = ["<thinking>", "<conspiracy>", "<tangent>"]
116
- print(f"🎸 Adding Creed's custom tokens: {custom_tokens}")
117
 
118
- num_added_tokens = self.tokenizer.add_tokens(custom_tokens)
119
- print(f"βœ… Added {num_added_tokens} custom tokens")
 
 
 
120
 
121
- print(f"πŸ€– Loading model on {self.device}...")
 
 
 
 
 
 
 
 
122
 
123
- # Load model with proper device handling
124
- if self.device == "cuda":
125
- self.model = AutoModelForCausalLM.from_pretrained(
126
- model_name,
127
- torch_dtype=torch.float16, # Use float16 for GPU efficiency
128
- device_map="auto", # Auto device mapping for GPU
129
- trust_remote_code=True,
130
- low_cpu_mem_usage=True
131
- )
132
- # Explicitly ensure model is on CUDA
133
- if self.model.device.type != "cuda":
134
- print("πŸ”§ Explicitly moving model to CUDA...")
135
- self.model = self.model.to(self.device)
136
- else:
137
- self.model = AutoModelForCausalLM.from_pretrained(
138
  model_name,
139
- torch_dtype=torch.float32, # Use float32 for CPU
140
- device_map=None,
141
  trust_remote_code=True,
142
- low_cpu_mem_usage=True
143
  )
144
- self.model = self.model.to("cpu")
145
-
146
- # Resize embeddings for custom tokens
147
- if num_added_tokens > 0:
148
- print(f"πŸ”§ Resizing model embeddings for {num_added_tokens} custom tokens")
149
- self.model.resize_token_embeddings(len(self.tokenizer))
150
-
151
- self.model.eval()
152
-
153
- # Verify device placement
154
- model_device = next(self.model.parameters()).device
155
- print(f"🎯 Model is actually on: {model_device}")
156
-
157
- self.model_loaded = True
158
- self.loading = False
159
- print(f"βœ… Creed's consciousness loaded on {model_device}!")
160
-
161
- # GPU memory info
162
- if self.device == "cuda" and torch.cuda.is_available():
163
- print(f"πŸ”₯ GPU Memory Used: {torch.cuda.memory_allocated() // 1024**2} MB")
164
- print(f"πŸ“Š GPU Memory Cached: {torch.cuda.memory_reserved() // 1024**2} MB")
165
-
166
- except Exception as e:
167
- print(f"❌ Error loading Creed model: {e}")
168
- print("πŸ”„ Falling back to base model...")
169
- try:
170
- base_model = "Qwen/Qwen2.5-0.5B-Instruct"
171
- self.tokenizer = AutoTokenizer.from_pretrained(base_model)
172
 
173
- # Fix pad token for fallback too
 
 
 
 
 
 
174
  if self.tokenizer.pad_token is None:
175
- self.tokenizer.pad_token = self.tokenizer.unk_token or "[PAD]"
 
 
176
 
 
177
  if self.device == "cuda":
178
  self.model = AutoModelForCausalLM.from_pretrained(
179
- base_model,
180
- torch_dtype=torch.float16,
181
- device_map="auto"
 
 
182
  )
 
183
  if self.model.device.type != "cuda":
 
184
  self.model = self.model.to(self.device)
185
  else:
186
  self.model = AutoModelForCausalLM.from_pretrained(
187
- base_model,
188
- torch_dtype=torch.float32,
189
- device_map=None
 
 
190
  )
191
  self.model = self.model.to("cpu")
192
 
 
 
 
 
 
193
  self.model.eval()
194
- self.model_loaded = True
 
195
  model_device = next(self.model.parameters()).device
196
- print(f"βœ… Fallback model loaded on {model_device}")
197
- except Exception as fallback_error:
198
- print(f"❌ Fallback also failed: {fallback_error}")
199
- self.loading = False
200
-
201
- @spaces.GPU if SPACES_AVAILABLE else lambda func: func
202
- def generate_response_gpu(self, conversation: str) -> str:
203
- """Generate response using the loaded model with proper device handling"""
204
-
205
- if not self.model_loaded:
206
- return "❌ Model not loaded"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
- try:
209
- print(f"πŸ” Input conversation length: {len(conversation)}")
210
- print(f"πŸ” Input sample: {conversation[:200]}...")
211
-
212
- # Ensure model is on the correct device
213
- if self.device == "cuda" and self.model.device.type != "cuda":
214
- print(f"πŸ”„ Moving model from {self.model.device} to {self.device}")
215
- self.model = self.model.to(self.device)
216
-
217
- # Tokenize input with attention mask
218
- inputs = self.tokenizer(
219
- conversation,
220
- return_tensors="pt",
221
- padding=True,
222
- truncation=True,
223
- max_length=1024, # Reduce max length to avoid issues
224
- add_special_tokens=True
225
- )
226
-
227
- print(f"πŸ” Tokenized input_ids shape: {inputs['input_ids'].shape}")
228
- print(f"πŸ” First few tokens: {inputs['input_ids'][0][:10]}")
229
-
230
- # Move inputs to same device as model
231
- input_ids = inputs['input_ids'].to(self.device)
232
- attention_mask = inputs['attention_mask'].to(self.device)
233
-
234
- print(f"πŸ” Model device: {self.model.device}, Input device: {input_ids.device}")
235
-
236
- # Generate response with proper attention mask
237
- with torch.no_grad():
238
- outputs = self.model.generate(
239
- input_ids=input_ids,
240
- attention_mask=attention_mask, # Pass attention mask
241
- max_new_tokens=100, # Reduce to debug
242
- do_sample=True,
243
- temperature=0.7, # Lower temperature
244
- top_p=0.9,
245
- top_k=50,
246
- repetition_penalty=1.1,
247
- pad_token_id=self.tokenizer.pad_token_id,
248
- eos_token_id=self.tokenizer.eos_token_id,
249
- use_cache=True
250
- )
251
-
252
- print(f"πŸ” Generated output shape: {outputs.shape}")
253
- print(f"πŸ” Generated tokens: {outputs[0][-20:]}") # Last 20 tokens
254
 
255
- # Decode response
256
- full_response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
257
- input_text = self.tokenizer.decode(input_ids[0], skip_special_tokens=True)
258
- response = full_response[len(input_text):].strip()
259
 
260
- print(f"πŸ” Raw response: {response[:200]}...")
261
-
262
- cleaned_response = self._clean_response(response)
263
- print(f"πŸ” Cleaned response: {cleaned_response[:200]}...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
 
265
- return cleaned_response
 
 
 
 
 
 
266
 
267
- except Exception as e:
268
- print(f"❌ Generation error: {e}")
269
- import traceback
270
- traceback.print_exc()
271
- return f"🎸 *Creed scratches his head* Something weird happened... {str(e)[:100]}"
272
-
273
- def generate_response(self, message: str, history: List[Dict]) -> Iterator[str]:
274
- """Generate response using the trained Creed model - works with messages format"""
275
-
276
- if not self.model_loaded:
277
- if self.loading:
278
- yield "🧠 Creed's consciousness is still loading... give me a moment..."
279
- return
280
- else:
281
- yield "❌ Something went wrong loading Creed's mind. Try refreshing the page."
282
- return
283
-
284
- try:
285
- # Convert messages format to simple history
286
- formatted_history = []
287
- if history:
288
- for msg in history:
289
- if msg.get('role') == 'user':
290
- user_msg = msg.get('content', '')
291
- # Look for the next assistant message
292
- assistant_msg = ""
293
- formatted_history.append([user_msg, assistant_msg])
294
- elif msg.get('role') == 'assistant':
295
- # Update the last entry with assistant response
296
- if formatted_history:
297
- formatted_history[-1][1] = msg.get('content', '')
298
-
299
- # Format the conversation
300
- conversation = self._format_conversation(message, formatted_history)
301
-
302
- # Generate response using GPU function
303
- response = self.generate_response_gpu(conversation)
304
-
305
- # Stream the response word by word for effect
306
- words = response.split()
307
- current_response = ""
308
-
309
- for word in words:
310
- current_response += word + " "
311
- time.sleep(0.05)
312
- yield current_response.strip()
313
 
314
- except Exception as e:
315
- print(f"❌ Error generating response: {e}")
316
- yield f"🎸 *Creed scratches his head* Something weird happened in my brain... {str(e)[:100]}"
317
-
318
- def _format_conversation(self, message: str, history: List[List[str]]) -> str:
319
- """Format the conversation for the model with proper system prompt"""
 
 
 
 
 
 
 
 
 
320
 
321
- # Comprehensive Creed system prompt
322
- system_prompt = """You are Creed Bratton from The Office. You embody his complete personality and speaking patterns.
 
 
 
323
 
324
  CORE IDENTITY:
325
  - Former member of The Grass Roots (1960s rock band)
@@ -359,554 +290,542 @@ RESPONSE GUIDELINES:
359
  Remember: You're not trying to be helpful in a traditional sense - you're being Creed Bratton.
360
 
361
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
362
 
363
- # Add conversation history
364
- conversation = system_prompt
365
- for user_msg, creed_msg in history[-4:]: # Keep recent context
366
- if user_msg and creed_msg: # Only add complete exchanges
367
- conversation += f"Human: {user_msg}\n"
368
- conversation += f"Creed: {creed_msg}\n"
369
-
370
- # Add current message
371
- conversation += f"Human: {message}\n"
372
- conversation += "Creed:"
373
-
374
- return conversation
375
-
376
- def _clean_response(self, response: str) -> str:
377
- """Clean up the model response and format custom tokens"""
378
-
379
- # Remove common artifacts
380
- response = response.replace("Human:", "").replace("Creed:", "")
381
-
382
- # Format Creed's custom tokens for better UI display
383
- response = response.replace("<thinking>", "πŸ€” *thinking* ")
384
- response = response.replace("</thinking>", "")
385
- response = response.replace("<conspiracy>", "πŸ•΅οΈ *conspiracy mode* ")
386
- response = response.replace("</conspiracy>", "")
387
- response = response.replace("<tangent>", "πŸŒ€ *tangent* ")
388
- response = response.replace("</tangent>", "")
389
-
390
- # Remove excessive whitespace
391
- response = " ".join(response.split())
392
-
393
- # Ensure it ends properly
394
- if response and not response.endswith(('.', '!', '?', '...', '*')):
395
- response += "."
396
-
397
- return response
398
-
399
- def creed_wisdom_tool(self, topic: str = "life") -> str:
400
- """MCP tool: Get Creed's wisdom on a topic"""
401
- if not self.model_loaded:
402
- return "🧠 Creed's consciousness is still loading..."
403
-
404
- prompt = f"Give me your wisdom about {topic}."
405
-
406
- # Generate a one-shot response
407
- final_response = ""
408
- for response in self.generate_response(prompt, []):
409
- final_response = response
410
-
411
- return final_response
412
-
413
- def cleanup_gpu_memory(self):
414
- """Clean up GPU memory if using CUDA"""
415
- if self.device == "cuda" and torch.cuda.is_available():
416
- torch.cuda.empty_cache()
417
- print(f"🧹 GPU Memory cleaned. Current: {torch.cuda.memory_allocated() // 1024**2} MB")
418
-
419
- def creed_story_tool(self, situation: str = "mysterious") -> str:
420
- """MCP tool: Get a Creed story"""
421
- if not self.model_loaded:
422
- return "🧠 Creed's consciousness is still loading..."
423
 
424
- prompt = f"Tell me a {situation} story from your past."
 
 
 
 
 
 
 
 
 
 
 
 
425
 
426
- # Generate a one-shot response
427
- final_response = ""
428
- for response in self.generate_response(prompt, []):
429
- final_response = response
 
430
 
431
- return final_response
 
 
 
 
 
 
 
 
 
 
 
 
432
 
433
  def main():
434
- """Initialize and launch the real Creed AI with modern styling"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
 
436
- print("🎸 Initializing REAL Creed Bratton AI...")
437
- print("πŸ“‘ Loading Mark's trained model: phxdev/creed-qwen-0.5b-lora")
 
 
 
 
 
 
 
 
 
438
 
439
- # Initialize Creed AI
440
- creed_ai = CreedBrattonAI()
 
 
 
 
 
 
 
 
 
 
 
 
441
 
442
- # Test the model with a simple input
443
- if creed_ai.model_loaded:
444
- print("πŸ§ͺ Testing model with simple input...")
445
- test_response = creed_ai.generate_response_gpu("Hello, test.")
446
- print(f"πŸ§ͺ Test response: {test_response}")
447
-
448
- if "Woah:" in test_response or len(test_response) > 100 and any(ord(c) > 127 for c in test_response):
449
- print("❌ Model is outputting garbage! Trying fallback...")
450
- # Force fallback to base model
451
- creed_ai.model_loaded = False
452
- creed_ai.load_model()
453
-
454
- if SPACES_AVAILABLE:
455
- gpu_placeholder()
456
- print("βœ… Spaces GPU compatibility enabled")
457
-
458
- # Memory status if GPU available
459
- if torch.cuda.is_available() and creed_ai.model_loaded:
460
- print(f"🎯 Model device verification: {next(creed_ai.model.parameters()).device}")
461
- print(f"πŸ”₯ Final GPU Memory: {torch.cuda.memory_allocated() // 1024**2} MB allocated")
462
- print(f"πŸ“Š GPU Memory Reserved: {torch.cuda.memory_reserved() // 1024**2} MB reserved")
463
-
464
- # Modern glassmorphism CSS
465
- modern_css = """
466
- /* Creed AI - Modern Glassmorphism Design */
467
- :root {
468
- --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
469
- --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
470
- --glass-bg: rgba(255, 255, 255, 0.08);
471
- --glass-border: rgba(255, 255, 255, 0.18);
472
- --text-primary: #ffffff;
473
- --text-secondary: rgba(255, 255, 255, 0.8);
474
- --accent-purple: #8b5cf6;
475
- --accent-blue: #3b82f6;
476
- --shadow-glow: 0 8px 32px rgba(139, 92, 246, 0.3);
477
- }
478
-
479
- /* Main container with animated background */
480
- .gradio-container {
481
- min-height: 100vh !important;
482
- background: var(--primary-gradient) !important;
483
- background-attachment: fixed !important;
484
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
485
- color: var(--text-primary) !important;
486
- padding: 20px !important;
487
- position: relative !important;
488
- overflow-x: hidden !important;
489
- }
490
-
491
- .gradio-container::before {
492
- content: '';
493
- position: fixed;
494
- top: 0;
495
- left: 0;
496
- width: 100%;
497
- height: 100%;
498
- background:
499
- radial-gradient(circle at 20% 80%, rgba(139, 92, 246, 0.3) 0%, transparent 50%),
500
- radial-gradient(circle at 80% 20%, rgba(59, 130, 246, 0.3) 0%, transparent 50%),
501
- radial-gradient(circle at 40% 40%, rgba(167, 139, 250, 0.2) 0%, transparent 50%);
502
- pointer-events: none;
503
- z-index: -1;
504
- }
505
-
506
- /* Floating particles animation */
507
- .gradio-container::after {
508
- content: '';
509
- position: fixed;
510
- top: 0;
511
- left: 0;
512
- width: 100%;
513
- height: 100%;
514
- background-image:
515
- radial-gradient(2px 2px at 20px 30px, rgba(255, 255, 255, 0.3), transparent),
516
- radial-gradient(2px 2px at 40px 70px, rgba(139, 92, 246, 0.4), transparent),
517
- radial-gradient(1px 1px at 90px 40px, rgba(59, 130, 246, 0.3), transparent);
518
- background-size: 120px 120px;
519
- animation: float 20s ease-in-out infinite;
520
- pointer-events: none;
521
- z-index: -1;
522
- }
523
-
524
- @keyframes float {
525
- 0%, 100% { transform: translateY(0px) rotate(0deg); }
526
- 50% { transform: translateY(-20px) rotate(180deg); }
527
- }
528
-
529
- /* Header styling */
530
- .header {
531
- background: var(--glass-bg) !important;
532
- backdrop-filter: blur(20px) !important;
533
- border: 1px solid var(--glass-border) !important;
534
- border-radius: 24px !important;
535
- padding: 32px !important;
536
- margin-bottom: 24px !important;
537
- text-align: center !important;
538
- box-shadow: var(--shadow-glow) !important;
539
- position: relative !important;
540
- overflow: hidden !important;
541
- }
542
-
543
- .header::before {
544
- content: '';
545
- position: absolute;
546
- top: 0;
547
- left: 0;
548
- right: 0;
549
- height: 1px;
550
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
551
- }
552
-
553
- .header h1 {
554
- font-size: 36px !important;
555
- font-weight: 700 !important;
556
- background: linear-gradient(135deg, #ffffff 0%, #a855f7 50%, #3b82f6 100%) !important;
557
- -webkit-background-clip: text !important;
558
- -webkit-text-fill-color: transparent !important;
559
- background-clip: text !important;
560
- margin: 0 0 12px 0 !important;
561
- text-shadow: 0 0 30px rgba(168, 85, 247, 0.5) !important;
562
- }
563
-
564
- .header p {
565
- font-size: 16px !important;
566
- color: var(--text-secondary) !important;
567
- margin: 0 !important;
568
- font-weight: 500 !important;
569
- }
570
-
571
- /* Info boxes with glass effect */
572
- .info-box {
573
- background: rgba(255, 255, 255, 0.06) !important;
574
- backdrop-filter: blur(16px) !important;
575
- border: 1px solid rgba(255, 255, 255, 0.12) !important;
576
- border-radius: 16px !important;
577
- padding: 20px !important;
578
- margin: 16px 0 !important;
579
- color: var(--text-secondary) !important;
580
- font-size: 14px !important;
581
- line-height: 1.6 !important;
582
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1) !important;
583
- }
584
-
585
- .status-box {
586
- background: rgba(16, 185, 129, 0.1) !important;
587
- backdrop-filter: blur(16px) !important;
588
- border: 1px solid rgba(16, 185, 129, 0.3) !important;
589
- border-radius: 16px !important;
590
- padding: 16px 20px !important;
591
- margin: 16px 0 !important;
592
- color: #10b981 !important;
593
- font-weight: 600 !important;
594
- box-shadow: 0 4px 20px rgba(16, 185, 129, 0.2) !important;
595
- }
596
-
597
- /* Chat area styling */
598
- .chat-area {
599
- background: var(--glass-bg) !important;
600
- backdrop-filter: blur(20px) !important;
601
- border: 1px solid var(--glass-border) !important;
602
- border-radius: 20px !important;
603
- margin: 16px 0 !important;
604
- overflow: hidden !important;
605
- box-shadow: var(--shadow-glow) !important;
606
- }
607
-
608
- /* Tools section */
609
- .tools-area {
610
- background: var(--glass-bg) !important;
611
- backdrop-filter: blur(20px) !important;
612
- border: 1px solid var(--glass-border) !important;
613
- border-radius: 20px !important;
614
- padding: 28px !important;
615
- margin: 24px 0 !important;
616
- box-shadow: var(--shadow-glow) !important;
617
- }
618
-
619
- .tools-title {
620
- font-size: 22px !important;
621
- font-weight: 600 !important;
622
- color: var(--text-primary) !important;
623
- margin: 0 0 20px 0 !important;
624
- padding-bottom: 12px !important;
625
- border-bottom: 1px solid rgba(255, 255, 255, 0.2) !important;
626
- background: linear-gradient(135deg, #ffffff 0%, #a855f7 100%) !important;
627
- -webkit-background-clip: text !important;
628
- -webkit-text-fill-color: transparent !important;
629
- }
630
-
631
- /* Form elements */
632
- .gradio-textbox input,
633
- .gradio-textbox textarea {
634
- background: rgba(255, 255, 255, 0.08) !important;
635
- backdrop-filter: blur(10px) !important;
636
- border: 1px solid rgba(255, 255, 255, 0.16) !important;
637
- color: var(--text-primary) !important;
638
- border-radius: 12px !important;
639
- padding: 12px 16px !important;
640
- transition: all 0.3s ease !important;
641
- font-size: 14px !important;
642
- }
643
-
644
- .gradio-textbox input:focus,
645
- .gradio-textbox textarea:focus {
646
- border-color: var(--accent-purple) !important;
647
- outline: none !important;
648
- box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.3) !important;
649
- background: rgba(255, 255, 255, 0.12) !important;
650
- }
651
-
652
- .gradio-textbox input::placeholder,
653
- .gradio-textbox textarea::placeholder {
654
- color: rgba(255, 255, 255, 0.5) !important;
655
- }
656
-
657
- /* Labels */
658
- .gradio-container label {
659
- color: var(--text-secondary) !important;
660
- font-weight: 500 !important;
661
- font-size: 14px !important;
662
- margin-bottom: 6px !important;
663
- display: block !important;
664
- }
665
-
666
- /* Buttons */
667
- .gradio-container button {
668
- background: linear-gradient(135deg, var(--accent-purple) 0%, var(--accent-blue) 100%) !important;
669
- color: var(--text-primary) !important;
670
- border: none !important;
671
- border-radius: 12px !important;
672
- padding: 12px 24px !important;
673
- font-weight: 600 !important;
674
- cursor: pointer !important;
675
- transition: all 0.3s ease !important;
676
- box-shadow: 0 4px 15px rgba(139, 92, 246, 0.4) !important;
677
- backdrop-filter: blur(10px) !important;
678
- min-height: 44px !important;
679
- display: flex !important;
680
- align-items: center !important;
681
- justify-content: center !important;
682
- }
683
-
684
- .gradio-container button:hover {
685
- transform: translateY(-2px) !important;
686
- box-shadow: 0 8px 25px rgba(139, 92, 246, 0.6) !important;
687
- background: linear-gradient(135deg, #9333ea 0%, #2563eb 100%) !important;
688
- }
689
-
690
- .gradio-container button:active {
691
- transform: translateY(0px) !important;
692
- }
693
-
694
- /* Send button specific styling */
695
- .gradio-container .gr-button {
696
- background: linear-gradient(135deg, var(--accent-purple) 0%, var(--accent-blue) 100%) !important;
697
- border: 1px solid rgba(255, 255, 255, 0.2) !important;
698
- color: white !important;
699
- font-weight: 600 !important;
700
- text-transform: none !important;
701
- letter-spacing: 0.5px !important;
702
- }
703
-
704
- /* Chatbot specific styling */
705
- .gradio-chatbot {
706
- background: transparent !important;
707
- border: none !important;
708
- }
709
-
710
- /* Footer */
711
- .footer {
712
- text-align: center !important;
713
- padding: 28px !important;
714
- color: var(--text-secondary) !important;
715
- background: var(--glass-bg) !important;
716
- backdrop-filter: blur(20px) !important;
717
- border: 1px solid var(--glass-border) !important;
718
- border-radius: 20px !important;
719
- margin-top: 32px !important;
720
- box-shadow: var(--shadow-glow) !important;
721
- }
722
-
723
- /* Scrollbar styling */
724
- ::-webkit-scrollbar {
725
- width: 8px;
726
- }
727
-
728
- ::-webkit-scrollbar-track {
729
- background: rgba(255, 255, 255, 0.05);
730
- border-radius: 4px;
731
- }
732
-
733
- ::-webkit-scrollbar-thumb {
734
- background: linear-gradient(135deg, var(--accent-purple), var(--accent-blue));
735
- border-radius: 4px;
736
- }
737
-
738
- ::-webkit-scrollbar-thumb:hover {
739
- background: linear-gradient(135deg, #9333ea, #2563eb);
740
- }
741
-
742
- /* Responsive design */
743
- @media (max-width: 768px) {
744
- .gradio-container {
745
- padding: 12px !important;
746
  }
747
-
 
 
 
 
 
 
748
  .header {
749
- padding: 20px !important;
750
- border-radius: 16px !important;
 
 
 
 
 
 
 
 
751
  }
752
-
 
 
 
 
 
 
 
 
 
 
753
  .header h1 {
754
- font-size: 28px !important;
 
 
 
 
 
 
 
755
  }
756
-
757
- .tools-area,
758
- .chat-area {
 
 
 
 
 
 
 
 
 
 
759
  border-radius: 16px !important;
760
  padding: 20px !important;
 
 
 
 
 
761
  }
762
- }
763
- """
764
 
765
- # Create wrapper function for proper chat handling
766
- def respond(message, history):
767
- """Response handler for Gradio messages format"""
768
- for response_chunk in creed_ai.generate_response(message, history):
769
- # Update the history with the current response in messages format
770
- updated_history = history + [
771
- {"role": "user", "content": message},
772
- {"role": "assistant", "content": response_chunk}
773
- ]
774
- yield "", updated_history
775
-
776
- # Create the interface with modern theme
777
- with gr.Blocks(
778
- title="🎸 Creed Bratton AI",
779
- css=modern_css,
780
- theme=gr.themes.Base() # Use base theme for better CSS control
781
- ) as demo:
782
-
783
- # Modern header
784
- gr.HTML(f"""
785
- <div class="header">
786
- <h1>🎸 Creed Bratton AI</h1>
787
- <p>Powered by phxdev/creed-qwen-0.5b-lora β€’ Running on {'πŸš€ GPU' if creed_ai.device == 'cuda' else 'πŸ–₯️ CPU'}</p>
788
- </div>
789
- """)
790
-
791
- # Model info with glass styling
792
- gr.HTML("""
793
- <div class="info-box">
794
- <strong>Model:</strong> phxdev/creed-qwen-0.5b-lora<br>
795
- <strong>Base:</strong> Qwen 0.5B + LoRA fine-tuning<br>
796
- <strong>Tokens:</strong> &lt;thinking&gt;, &lt;conspiracy&gt;, &lt;tangent&gt;
797
- </div>
798
- """)
799
-
800
- # MCP status
801
- if os.environ.get('GRADIO_MCP_ENABLED'):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
802
  gr.HTML("""
803
- <div class="status-box">
804
- βœ“ MCP Server Active β€’ Available as tool for Claude Desktop
 
 
805
  </div>
806
  """)
807
-
808
- # Main chat interface with glass styling
809
- with gr.Row(elem_classes="chat-area"):
810
- chatbot = gr.Chatbot(
811
- type='messages', # Use messages format (modern)
812
- height=550,
813
- show_copy_button=True,
814
- show_share_button=False,
815
- avatar_images=["πŸ‘€", "🎸"],
816
- bubble_full_width=False,
817
- show_label=False,
818
- placeholder="🎸 Creed is ready...",
819
- container=False
820
- )
821
-
822
- # Input with explicit send button
823
- with gr.Row():
824
- with gr.Column(scale=7):
825
- msg = gr.Textbox(
826
- placeholder="Ask Creed anything...",
827
- container=False,
828
- submit_btn=False, # Disable built-in submit
829
- stop_btn=False
830
  )
831
- with gr.Column(scale=1, min_width=100):
832
- send_btn = gr.Button("Send", variant="primary", size="lg")
833
-
834
- # Wire up the chat - both Enter key and Send button
835
- msg.submit(
836
- respond,
837
- inputs=[msg, chatbot],
838
- outputs=[msg, chatbot],
839
- show_progress="hidden"
840
- )
841
-
842
- send_btn.click(
843
- respond,
844
- inputs=[msg, chatbot],
845
- outputs=[msg, chatbot],
846
- show_progress="hidden"
847
- )
848
-
849
- # MCP Tools section with glass styling
850
- with gr.Row(elem_classes="tools-area"):
851
- gr.HTML('<div class="tools-title">πŸ› οΈ MCP Tools</div>')
852
 
 
853
  with gr.Row():
854
- with gr.Column():
855
- wisdom_topic = gr.Textbox(
856
- label="Wisdom Topic",
857
- placeholder="life, business, relationships..."
 
 
858
  )
859
- wisdom_output = gr.Textbox(
860
- label="Creed's Response",
861
- interactive=False,
862
- lines=3
863
- )
864
- wisdom_btn = gr.Button("Ask Creed", variant="primary")
865
-
866
- with gr.Column():
867
- story_situation = gr.Textbox(
868
- label="Story Request",
869
- placeholder="Tell me about..."
870
- )
871
- story_output = gr.Textbox(
872
- label="Creed's Story",
873
- interactive=False,
874
- lines=3
875
- )
876
- story_btn = gr.Button("Get Story", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
877
 
878
- # Wire up the tools
879
- wisdom_btn.click(
880
- creed_ai.creed_wisdom_tool,
881
- inputs=[wisdom_topic],
882
- outputs=[wisdom_output]
883
- )
884
 
885
- story_btn.click(
886
- creed_ai.creed_story_tool,
887
- inputs=[story_situation],
888
- outputs=[story_output]
 
 
889
  )
890
-
891
- # Modern footer
892
- gr.HTML("""
893
- <div class="footer">
894
- <strong>Creed Bratton AI</strong><br>
895
- Model: phxdev/creed-qwen-0.5b-lora β€’ Trained by Mark Scott<br>
896
- <em>"Sometimes a guy's gotta ride the bull, am I right?"</em>
897
- </div>
898
- """)
899
-
900
- # Launch with modern styling and public sharing
901
- print("πŸš€ Launching Real Creed AI with modern glassmorphism design...")
902
-
903
- demo.launch(
904
- ssr_mode=False,
905
- server_name="0.0.0.0",
906
- server_port=7860,
907
- share=True, # Create public link
908
- show_error=True
909
- )
910
 
911
  if __name__ == "__main__":
912
- main()
 
1
  # Create wrapper function for proper chat handling
2
+ def respond(message, history):
3
+ """Response handler for Gradio messages format"""
4
+ if not message.strip():
5
+ return "", history
6
+
7
+ # Convert messages format to simple tuples
8
+ simple_history = []
9
+ for i in range(0, len(history), 2):
10
+ if i + 1 < len(history):
11
+ user_msg = history[i].get('content', '') if isinstance(history[i], dict) else str(history[i])
12
+ bot_msg = history[i + 1].get('content', '') if isinstance(history[i + 1], dict) else str(history[i + 1])
13
+ if user_msg and bot_msg:
14
+ simple_history.append([user_msg, bot_msg])
15
+
16
+ # Generate response
17
+ for response_chunk in creed_ai.generate_response(message, simple_history):
 
 
 
 
 
 
 
 
 
 
18
  # Create new history with the streaming response
19
  new_history = history + [
20
  {"role": "user", "content": message},
21
  {"role": "assistant", "content": response_chunk}
22
  ]
23
+ yield "", new_history#!/usr/bin/env python3
 
 
 
 
 
 
 
 
24
  """
25
  🎸 Creed Bratton AI - Using phxdev/creed-qwen-0.5b-lora
26
  The REAL Creed, trained by Mark, not some knockoff prompt engineering
 
41
 
42
  # Spaces compatibility
43
  try:
44
+ import spaces
45
+ SPACES_AVAILABLE = True
46
+ @spaces.GPU
47
+ def gpu_placeholder():
48
+ return "GPU satisfied"
49
  except ImportError:
50
+ SPACES_AVAILABLE = False
51
 
52
  class CreedBrattonAI:
53
+ """Real Creed AI using Mark's trained model - GPU optimized"""
 
 
 
 
 
 
 
54
 
55
+ def __init__(self):
56
+ self.model = None
57
+ self.tokenizer = None
58
+ self.model_loaded = False
59
+ self.loading = False
60
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
+ print(f"🎸 Initializing Creed AI")
63
+ print(f"πŸ–₯️ Device detected: {self.device}")
64
+ if torch.cuda.is_available():
65
+ print(f"πŸš€ GPU: {torch.cuda.get_device_name()}")
66
+ print(f"πŸ’Ύ GPU Memory: {torch.cuda.get_device_properties(0).total_memory // 1024**3} GB")
67
 
68
+ # Load model with proper GPU detection
69
+ self.load_model()
70
+
71
+ def load_model(self):
72
+ """Load the model with GPU optimization when available"""
73
+ if self.loading or self.model_loaded:
74
+ return
75
+
76
+ self.loading = True
77
 
78
+ try:
79
+ print(f"🧠 Loading Creed's consciousness on {self.device}...")
80
+
81
+ # Load model and tokenizer
82
+ model_name = "phxdev/creed-qwen-0.5b-lora"
83
+
84
+ print("πŸ“¦ Loading tokenizer...")
85
+ self.tokenizer = AutoTokenizer.from_pretrained(
 
 
 
 
 
 
 
86
  model_name,
 
 
87
  trust_remote_code=True,
88
+ padding_side="left"
89
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ # Add Creed's custom tokens
92
+ custom_tokens = ["<thinking>", "<conspiracy>", "<tangent>"]
93
+ print(f"🎸 Adding Creed's custom tokens: {custom_tokens}")
94
+
95
+ num_added_tokens = self.tokenizer.add_tokens(custom_tokens)
96
+ print(f"βœ… Added {num_added_tokens} custom tokens")
97
+
98
  if self.tokenizer.pad_token is None:
99
+ self.tokenizer.pad_token = self.tokenizer.eos_token
100
+
101
+ print(f"πŸ€– Loading model on {self.device}...")
102
 
103
+ # Load model with proper device handling
104
  if self.device == "cuda":
105
  self.model = AutoModelForCausalLM.from_pretrained(
106
+ model_name,
107
+ torch_dtype=torch.float16, # Use float16 for GPU efficiency
108
+ device_map="auto", # Auto device mapping for GPU
109
+ trust_remote_code=True,
110
+ low_cpu_mem_usage=True
111
  )
112
+ # Explicitly ensure model is on CUDA
113
  if self.model.device.type != "cuda":
114
+ print("πŸ”§ Explicitly moving model to CUDA...")
115
  self.model = self.model.to(self.device)
116
  else:
117
  self.model = AutoModelForCausalLM.from_pretrained(
118
+ model_name,
119
+ torch_dtype=torch.float32, # Use float32 for CPU
120
+ device_map=None,
121
+ trust_remote_code=True,
122
+ low_cpu_mem_usage=True
123
  )
124
  self.model = self.model.to("cpu")
125
 
126
+ # Resize embeddings for custom tokens
127
+ if num_added_tokens > 0:
128
+ print(f"πŸ”§ Resizing model embeddings for {num_added_tokens} custom tokens")
129
+ self.model.resize_token_embeddings(len(self.tokenizer))
130
+
131
  self.model.eval()
132
+
133
+ # Verify device placement
134
  model_device = next(self.model.parameters()).device
135
+ print(f"🎯 Model is actually on: {model_device}")
136
+
137
+ self.model_loaded = True
138
+ self.loading = False
139
+ print(f"βœ… Creed's consciousness loaded on {model_device}!")
140
+
141
+ # GPU memory info
142
+ if self.device == "cuda" and torch.cuda.is_available():
143
+ print(f"πŸ”₯ GPU Memory Used: {torch.cuda.memory_allocated() // 1024**2} MB")
144
+ print(f"πŸ“Š GPU Memory Cached: {torch.cuda.memory_reserved() // 1024**2} MB")
145
+
146
+ except Exception as e:
147
+ print(f"❌ Error loading Creed model: {e}")
148
+ print("πŸ”„ Falling back to base model...")
149
+ try:
150
+ base_model = "Qwen/Qwen2.5-0.5B-Instruct"
151
+ self.tokenizer = AutoTokenizer.from_pretrained(base_model)
152
+
153
+ # Use same pad token setup that was working
154
+ if self.tokenizer.pad_token is None:
155
+ self.tokenizer.pad_token = self.tokenizer.eos_token
156
+
157
+ if self.device == "cuda":
158
+ self.model = AutoModelForCausalLM.from_pretrained(
159
+ base_model,
160
+ torch_dtype=torch.float16,
161
+ device_map="auto"
162
+ )
163
+ if self.model.device.type != "cuda":
164
+ self.model = self.model.to(self.device)
165
+ else:
166
+ self.model = AutoModelForCausalLM.from_pretrained(
167
+ base_model,
168
+ torch_dtype=torch.float32,
169
+ device_map=None
170
+ )
171
+ self.model = self.model.to("cpu")
172
+
173
+ self.model.eval()
174
+ self.model_loaded = True
175
+ model_device = next(self.model.parameters()).device
176
+ print(f"βœ… Fallback model loaded on {model_device}")
177
+ except Exception as fallback_error:
178
+ print(f"❌ Fallback also failed: {fallback_error}")
179
+ self.loading = False
180
 
181
+ @spaces.GPU if SPACES_AVAILABLE else lambda func: func
182
+ def generate_response_gpu(self, conversation: str) -> str:
183
+ """Generate response using the loaded model - back to working version"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
 
185
+ if not self.model_loaded:
186
+ return "❌ Model not loaded"
 
 
187
 
188
+ try:
189
+ # Simple tokenization that was working before
190
+ inputs = self.tokenizer.encode(conversation, return_tensors="pt")
191
+ if self.device == "cuda":
192
+ inputs = inputs.to(self.device)
193
+
194
+ # Generate response with original settings that worked
195
+ with torch.no_grad():
196
+ outputs = self.model.generate(
197
+ inputs,
198
+ max_new_tokens=200,
199
+ do_sample=True,
200
+ temperature=0.9,
201
+ top_p=0.95,
202
+ top_k=40,
203
+ repetition_penalty=1.15,
204
+ pad_token_id=self.tokenizer.eos_token_id,
205
+ eos_token_id=self.tokenizer.eos_token_id,
206
+ use_cache=True
207
+ )
208
+
209
+ # Decode response
210
+ full_response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
211
+ response = full_response[len(self.tokenizer.decode(inputs[0], skip_special_tokens=True)):].strip()
212
+
213
+ return self._clean_response(response)
214
+
215
+ except Exception as e:
216
+ return f"🎸 *Creed scratches his head* Something weird happened... {str(e)[:100]}"
217
+
218
+ def generate_response(self, message: str, history: List[List[str]]) -> Iterator[str]:
219
+ """Generate response using the trained Creed model - back to working version"""
220
 
221
+ if not self.model_loaded:
222
+ if self.loading:
223
+ yield "🧠 Creed's consciousness is still loading... give me a moment..."
224
+ return
225
+ else:
226
+ yield "❌ Something went wrong loading Creed's mind. Try refreshing the page."
227
+ return
228
 
229
+ try:
230
+ # Format the conversation
231
+ conversation = self._format_conversation(message, history)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
 
233
+ # Generate response using GPU function
234
+ response = self.generate_response_gpu(conversation)
235
+
236
+ # Stream the response word by word for effect
237
+ words = response.split()
238
+ current_response = ""
239
+
240
+ for word in words:
241
+ current_response += word + " "
242
+ time.sleep(0.05)
243
+ yield current_response.strip()
244
+
245
+ except Exception as e:
246
+ print(f"❌ Error generating response: {e}")
247
+ yield f"🎸 *Creed scratches his head* Something weird happened in my brain... {str(e)[:100]}"
248
 
249
+ def _format_conversation(self, message: str, history: List[List[str]]) -> str:
250
+ """Format the conversation for the model with proper system prompt"""
251
+
252
+ # Comprehensive Creed system prompt
253
+ system_prompt = """You are Creed Bratton from The Office. You embody his complete personality and speaking patterns.
254
 
255
  CORE IDENTITY:
256
  - Former member of The Grass Roots (1960s rock band)
 
290
  Remember: You're not trying to be helpful in a traditional sense - you're being Creed Bratton.
291
 
292
  """
293
+
294
+ # Add conversation history
295
+ conversation = system_prompt
296
+ for user_msg, creed_msg in history[-4:]: # Keep recent context
297
+ if user_msg and creed_msg: # Only add complete exchanges
298
+ conversation += f"Human: {user_msg}\n"
299
+ conversation += f"Creed: {creed_msg}\n"
300
+
301
+ # Add current message
302
+ conversation += f"Human: {message}\n"
303
+ conversation += "Creed:"
304
+
305
+ return conversation
306
 
307
+ def _clean_response(self, response: str) -> str:
308
+ """Clean up the model response and format custom tokens"""
309
+
310
+ # Remove common artifacts
311
+ response = response.replace("Human:", "").replace("Creed:", "")
312
+
313
+ # Format Creed's custom tokens for better UI display
314
+ response = response.replace("<thinking>", "πŸ€” *thinking* ")
315
+ response = response.replace("</thinking>", "")
316
+ response = response.replace("<conspiracy>", "πŸ•΅οΈ *conspiracy mode* ")
317
+ response = response.replace("</conspiracy>", "")
318
+ response = response.replace("<tangent>", "πŸŒ€ *tangent* ")
319
+ response = response.replace("</tangent>", "")
320
+
321
+ # Remove excessive whitespace
322
+ response = " ".join(response.split())
323
+
324
+ # Ensure it ends properly
325
+ if response and not response.endswith(('.', '!', '?', '...', '*')):
326
+ response += "."
327
+
328
+ return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
 
330
+ def creed_wisdom_tool(self, topic: str = "life") -> str:
331
+ """MCP tool: Get Creed's wisdom on a topic"""
332
+ if not self.model_loaded:
333
+ return "🧠 Creed's consciousness is still loading..."
334
+
335
+ prompt = f"Give me your wisdom about {topic}."
336
+
337
+ # Generate a one-shot response
338
+ final_response = ""
339
+ for response in self.generate_response(prompt, []):
340
+ final_response = response
341
+
342
+ return final_response
343
 
344
+ def cleanup_gpu_memory(self):
345
+ """Clean up GPU memory if using CUDA"""
346
+ if self.device == "cuda" and torch.cuda.is_available():
347
+ torch.cuda.empty_cache()
348
+ print(f"🧹 GPU Memory cleaned. Current: {torch.cuda.memory_allocated() // 1024**2} MB")
349
 
350
+ def creed_story_tool(self, situation: str = "mysterious") -> str:
351
+ """MCP tool: Get a Creed story"""
352
+ if not self.model_loaded:
353
+ return "🧠 Creed's consciousness is still loading..."
354
+
355
+ prompt = f"Tell me a {situation} story from your past."
356
+
357
+ # Generate a one-shot response
358
+ final_response = ""
359
+ for response in self.generate_response(prompt, []):
360
+ final_response = response
361
+
362
+ return final_response
363
 
364
  def main():
365
+ """Initialize and launch the real Creed AI with modern styling"""
366
+
367
+ print("🎸 Initializing REAL Creed Bratton AI...")
368
+ print("πŸ“‘ Loading Mark's trained model: phxdev/creed-qwen-0.5b-lora")
369
+
370
+ # Initialize Creed AI
371
+ creed_ai = CreedBrattonAI()
372
+
373
+ if SPACES_AVAILABLE:
374
+ gpu_placeholder()
375
+ print("βœ… Spaces GPU compatibility enabled")
376
+
377
+ # Memory status if GPU available
378
+ if torch.cuda.is_available() and creed_ai.model_loaded:
379
+ print(f"🎯 Model device verification: {next(creed_ai.model.parameters()).device}")
380
+ print(f"πŸ”₯ Final GPU Memory: {torch.cuda.memory_allocated() // 1024**2} MB allocated")
381
+ print(f"πŸ“Š GPU Memory Reserved: {torch.cuda.memory_reserved() // 1024**2} MB reserved")
382
+
383
+ # Modern glassmorphism CSS
384
+ modern_css = """
385
+ /* Creed AI - Modern Glassmorphism Design */
386
+ :root {
387
+ --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
388
+ --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
389
+ --glass-bg: rgba(255, 255, 255, 0.08);
390
+ --glass-border: rgba(255, 255, 255, 0.18);
391
+ --text-primary: #ffffff;
392
+ --text-secondary: rgba(255, 255, 255, 0.8);
393
+ --accent-purple: #8b5cf6;
394
+ --accent-blue: #3b82f6;
395
+ --shadow-glow: 0 8px 32px rgba(139, 92, 246, 0.3);
396
+ }
397
 
398
+ /* Main container with animated background */
399
+ .gradio-container {
400
+ min-height: 100vh !important;
401
+ background: var(--primary-gradient) !important;
402
+ background-attachment: fixed !important;
403
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
404
+ color: var(--text-primary) !important;
405
+ padding: 20px !important;
406
+ position: relative !important;
407
+ overflow-x: hidden !important;
408
+ }
409
 
410
+ .gradio-container::before {
411
+ content: '';
412
+ position: fixed;
413
+ top: 0;
414
+ left: 0;
415
+ width: 100%;
416
+ height: 100%;
417
+ background:
418
+ radial-gradient(circle at 20% 80%, rgba(139, 92, 246, 0.3) 0%, transparent 50%),
419
+ radial-gradient(circle at 80% 20%, rgba(59, 130, 246, 0.3) 0%, transparent 50%),
420
+ radial-gradient(circle at 40% 40%, rgba(167, 139, 250, 0.2) 0%, transparent 50%);
421
+ pointer-events: none;
422
+ z-index: -1;
423
+ }
424
 
425
+ /* Floating particles animation */
426
+ .gradio-container::after {
427
+ content: '';
428
+ position: fixed;
429
+ top: 0;
430
+ left: 0;
431
+ width: 100%;
432
+ height: 100%;
433
+ background-image:
434
+ radial-gradient(2px 2px at 20px 30px, rgba(255, 255, 255, 0.3), transparent),
435
+ radial-gradient(2px 2px at 40px 70px, rgba(139, 92, 246, 0.4), transparent),
436
+ radial-gradient(1px 1px at 90px 40px, rgba(59, 130, 246, 0.3), transparent);
437
+ background-size: 120px 120px;
438
+ animation: float 20s ease-in-out infinite;
439
+ pointer-events: none;
440
+ z-index: -1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
441
  }
442
+
443
+ @keyframes float {
444
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
445
+ 50% { transform: translateY(-20px) rotate(180deg); }
446
+ }
447
+
448
+ /* Header styling */
449
  .header {
450
+ background: var(--glass-bg) !important;
451
+ backdrop-filter: blur(20px) !important;
452
+ border: 1px solid var(--glass-border) !important;
453
+ border-radius: 24px !important;
454
+ padding: 32px !important;
455
+ margin-bottom: 24px !important;
456
+ text-align: center !important;
457
+ box-shadow: var(--shadow-glow) !important;
458
+ position: relative !important;
459
+ overflow: hidden !important;
460
  }
461
+
462
+ .header::before {
463
+ content: '';
464
+ position: absolute;
465
+ top: 0;
466
+ left: 0;
467
+ right: 0;
468
+ height: 1px;
469
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
470
+ }
471
+
472
  .header h1 {
473
+ font-size: 36px !important;
474
+ font-weight: 700 !important;
475
+ background: linear-gradient(135deg, #ffffff 0%, #a855f7 50%, #3b82f6 100%) !important;
476
+ -webkit-background-clip: text !important;
477
+ -webkit-text-fill-color: transparent !important;
478
+ background-clip: text !important;
479
+ margin: 0 0 12px 0 !important;
480
+ text-shadow: 0 0 30px rgba(168, 85, 247, 0.5) !important;
481
  }
482
+
483
+ .header p {
484
+ font-size: 16px !important;
485
+ color: var(--text-secondary) !important;
486
+ margin: 0 !important;
487
+ font-weight: 500 !important;
488
+ }
489
+
490
+ /* Info boxes with glass effect */
491
+ .info-box {
492
+ background: rgba(255, 255, 255, 0.06) !important;
493
+ backdrop-filter: blur(16px) !important;
494
+ border: 1px solid rgba(255, 255, 255, 0.12) !important;
495
  border-radius: 16px !important;
496
  padding: 20px !important;
497
+ margin: 16px 0 !important;
498
+ color: var(--text-secondary) !important;
499
+ font-size: 14px !important;
500
+ line-height: 1.6 !important;
501
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1) !important;
502
  }
 
 
503
 
504
+ .status-box {
505
+ background: rgba(16, 185, 129, 0.1) !important;
506
+ backdrop-filter: blur(16px) !important;
507
+ border: 1px solid rgba(16, 185, 129, 0.3) !important;
508
+ border-radius: 16px !important;
509
+ padding: 16px 20px !important;
510
+ margin: 16px 0 !important;
511
+ color: #10b981 !important;
512
+ font-weight: 600 !important;
513
+ box-shadow: 0 4px 20px rgba(16, 185, 129, 0.2) !important;
514
+ }
515
+
516
+ /* Chat area styling */
517
+ .chat-area {
518
+ background: var(--glass-bg) !important;
519
+ backdrop-filter: blur(20px) !important;
520
+ border: 1px solid var(--glass-border) !important;
521
+ border-radius: 20px !important;
522
+ margin: 16px 0 !important;
523
+ overflow: hidden !important;
524
+ box-shadow: var(--shadow-glow) !important;
525
+ }
526
+
527
+ /* Tools section */
528
+ .tools-area {
529
+ background: var(--glass-bg) !important;
530
+ backdrop-filter: blur(20px) !important;
531
+ border: 1px solid var(--glass-border) !important;
532
+ border-radius: 20px !important;
533
+ padding: 28px !important;
534
+ margin: 24px 0 !important;
535
+ box-shadow: var(--shadow-glow) !important;
536
+ }
537
+
538
+ .tools-title {
539
+ font-size: 22px !important;
540
+ font-weight: 600 !important;
541
+ color: var(--text-primary) !important;
542
+ margin: 0 0 20px 0 !important;
543
+ padding-bottom: 12px !important;
544
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2) !important;
545
+ background: linear-gradient(135deg, #ffffff 0%, #a855f7 100%) !important;
546
+ -webkit-background-clip: text !important;
547
+ -webkit-text-fill-color: transparent !important;
548
+ }
549
+
550
+ /* Form elements */
551
+ .gradio-textbox input,
552
+ .gradio-textbox textarea {
553
+ background: rgba(255, 255, 255, 0.08) !important;
554
+ backdrop-filter: blur(10px) !important;
555
+ border: 1px solid rgba(255, 255, 255, 0.16) !important;
556
+ color: var(--text-primary) !important;
557
+ border-radius: 12px !important;
558
+ padding: 12px 16px !important;
559
+ transition: all 0.3s ease !important;
560
+ font-size: 14px !important;
561
+ }
562
+
563
+ .gradio-textbox input:focus,
564
+ .gradio-textbox textarea:focus {
565
+ border-color: var(--accent-purple) !important;
566
+ outline: none !important;
567
+ box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.3) !important;
568
+ background: rgba(255, 255, 255, 0.12) !important;
569
+ }
570
+
571
+ .gradio-textbox input::placeholder,
572
+ .gradio-textbox textarea::placeholder {
573
+ color: rgba(255, 255, 255, 0.5) !important;
574
+ }
575
+
576
+ /* Labels */
577
+ .gradio-container label {
578
+ color: var(--text-secondary) !important;
579
+ font-weight: 500 !important;
580
+ font-size: 14px !important;
581
+ margin-bottom: 6px !important;
582
+ display: block !important;
583
+ }
584
+
585
+ /* Buttons */
586
+ .gradio-container button {
587
+ background: linear-gradient(135deg, var(--accent-purple) 0%, var(--accent-blue) 100%) !important;
588
+ color: var(--text-primary) !important;
589
+ border: none !important;
590
+ border-radius: 12px !important;
591
+ padding: 12px 24px !important;
592
+ font-weight: 600 !important;
593
+ cursor: pointer !important;
594
+ transition: all 0.3s ease !important;
595
+ box-shadow: 0 4px 15px rgba(139, 92, 246, 0.4) !important;
596
+ backdrop-filter: blur(10px) !important;
597
+ min-height: 44px !important;
598
+ display: flex !important;
599
+ align-items: center !important;
600
+ justify-content: center !important;
601
+ }
602
+
603
+ .gradio-container button:hover {
604
+ transform: translateY(-2px) !important;
605
+ box-shadow: 0 8px 25px rgba(139, 92, 246, 0.6) !important;
606
+ background: linear-gradient(135deg, #9333ea 0%, #2563eb 100%) !important;
607
+ }
608
+
609
+ .gradio-container button:active {
610
+ transform: translateY(0px) !important;
611
+ }
612
+
613
+ /* Send button specific styling */
614
+ .gradio-container .gr-button {
615
+ background: linear-gradient(135deg, var(--accent-purple) 0%, var(--accent-blue) 100%) !important;
616
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
617
+ color: white !important;
618
+ font-weight: 600 !important;
619
+ text-transform: none !important;
620
+ letter-spacing: 0.5px !important;
621
+ }
622
+
623
+ /* Chatbot specific styling */
624
+ .gradio-chatbot {
625
+ background: transparent !important;
626
+ border: none !important;
627
+ }
628
+
629
+ /* Footer */
630
+ .footer {
631
+ text-align: center !important;
632
+ padding: 28px !important;
633
+ color: var(--text-secondary) !important;
634
+ background: var(--glass-bg) !important;
635
+ backdrop-filter: blur(20px) !important;
636
+ border: 1px solid var(--glass-border) !important;
637
+ border-radius: 20px !important;
638
+ margin-top: 32px !important;
639
+ box-shadow: var(--shadow-glow) !important;
640
+ }
641
+
642
+ /* Scrollbar styling */
643
+ ::-webkit-scrollbar {
644
+ width: 8px;
645
+ }
646
+
647
+ ::-webkit-scrollbar-track {
648
+ background: rgba(255, 255, 255, 0.05);
649
+ border-radius: 4px;
650
+ }
651
+
652
+ ::-webkit-scrollbar-thumb {
653
+ background: linear-gradient(135deg, var(--accent-purple), var(--accent-blue));
654
+ border-radius: 4px;
655
+ }
656
+
657
+ ::-webkit-scrollbar-thumb:hover {
658
+ background: linear-gradient(135deg, #9333ea, #2563eb);
659
+ }
660
+
661
+ /* Responsive design */
662
+ @media (max-width: 768px) {
663
+ .gradio-container {
664
+ padding: 12px !important;
665
+ }
666
+
667
+ .header {
668
+ padding: 20px !important;
669
+ border-radius: 16px !important;
670
+ }
671
+
672
+ .header h1 {
673
+ font-size: 28px !important;
674
+ }
675
+
676
+ .tools-area,
677
+ .chat-area {
678
+ border-radius: 16px !important;
679
+ padding: 20px !important;
680
+ }
681
+ }
682
+ """
683
+
684
+ # Create wrapper function for proper chat handling
685
+ def respond(message, history):
686
+ """Response handler for Gradio messages format"""
687
+ for response_chunk in creed_ai.generate_response(message, history):
688
+ # Update the history with the current response in messages format
689
+ updated_history = history + [
690
+ {"role": "user", "content": message},
691
+ {"role": "assistant", "content": response_chunk}
692
+ ]
693
+ yield "", updated_history
694
+
695
+ # Create the interface with modern theme
696
+ with gr.Blocks(
697
+ title="🎸 Creed Bratton AI",
698
+ css=modern_css,
699
+ theme=gr.themes.Base() # Use base theme for better CSS control
700
+ ) as demo:
701
+
702
+ # Modern header
703
+ gr.HTML(f"""
704
+ <div class="header">
705
+ <h1>🎸 Creed Bratton AI</h1>
706
+ <p>Powered by phxdev/creed-qwen-0.5b-lora β€’ Running on {'πŸš€ GPU' if creed_ai.device == 'cuda' else 'πŸ–₯️ CPU'}</p>
707
+ </div>
708
+ """)
709
+
710
+ # Model info with glass styling
711
  gr.HTML("""
712
+ <div class="info-box">
713
+ <strong>Model:</strong> phxdev/creed-qwen-0.5b-lora<br>
714
+ <strong>Base:</strong> Qwen 0.5B + LoRA fine-tuning<br>
715
+ <strong>Tokens:</strong> &lt;thinking&gt;, &lt;conspiracy&gt;, &lt;tangent&gt;
716
  </div>
717
  """)
718
+
719
+ # MCP status
720
+ if os.environ.get('GRADIO_MCP_ENABLED'):
721
+ gr.HTML("""
722
+ <div class="status-box">
723
+ βœ“ MCP Server Active β€’ Available as tool for Claude Desktop
724
+ </div>
725
+ """)
726
+
727
+ # Main chat interface with glass styling
728
+ with gr.Row(elem_classes="chat-area"):
729
+ chatbot = gr.Chatbot(
730
+ type='messages', # Use messages format (modern)
731
+ height=550,
732
+ show_copy_button=True,
733
+ show_share_button=False,
734
+ avatar_images=["πŸ‘€", "🎸"],
735
+ bubble_full_width=False,
736
+ show_label=False,
737
+ placeholder="🎸 Creed is ready...",
738
+ container=False
 
 
739
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
740
 
741
+ # Input with explicit send button
742
  with gr.Row():
743
+ with gr.Column(scale=7):
744
+ msg = gr.Textbox(
745
+ placeholder="Ask Creed anything...",
746
+ container=False,
747
+ submit_btn=False, # Disable built-in submit
748
+ stop_btn=False
749
  )
750
+ with gr.Column(scale=1, min_width=100):
751
+ send_btn = gr.Button("Send", variant="primary", size="lg")
752
+
753
+ # Wire up the chat - both Enter key and Send button
754
+ msg.submit(
755
+ respond,
756
+ inputs=[msg, chatbot],
757
+ outputs=[msg, chatbot],
758
+ show_progress="hidden"
759
+ )
760
+
761
+ send_btn.click(
762
+ respond,
763
+ inputs=[msg, chatbot],
764
+ outputs=[msg, chatbot],
765
+ show_progress="hidden"
766
+ )
767
+
768
+ # MCP Tools section with glass styling
769
+ with gr.Row(elem_classes="tools-area"):
770
+ gr.HTML('<div class="tools-title">πŸ› οΈ MCP Tools</div>')
771
+
772
+ with gr.Row():
773
+ with gr.Column():
774
+ wisdom_topic = gr.Textbox(
775
+ label="Wisdom Topic",
776
+ placeholder="life, business, relationships..."
777
+ )
778
+ wisdom_output = gr.Textbox(
779
+ label="Creed's Response",
780
+ interactive=False,
781
+ lines=3
782
+ )
783
+ wisdom_btn = gr.Button("Ask Creed", variant="primary")
784
+
785
+ with gr.Column():
786
+ story_situation = gr.Textbox(
787
+ label="Story Request",
788
+ placeholder="Tell me about..."
789
+ )
790
+ story_output = gr.Textbox(
791
+ label="Creed's Story",
792
+ interactive=False,
793
+ lines=3
794
+ )
795
+ story_btn = gr.Button("Get Story", variant="primary")
796
+
797
+ # Wire up the tools
798
+ wisdom_btn.click(
799
+ creed_ai.creed_wisdom_tool,
800
+ inputs=[wisdom_topic],
801
+ outputs=[wisdom_output]
802
+ )
803
+
804
+ story_btn.click(
805
+ creed_ai.creed_story_tool,
806
+ inputs=[story_situation],
807
+ outputs=[story_output]
808
+ )
809
+
810
+ # Modern footer
811
+ gr.HTML("""
812
+ <div class="footer">
813
+ <strong>Creed Bratton AI</strong><br>
814
+ Model: phxdev/creed-qwen-0.5b-lora β€’ Trained by Mark Scott<br>
815
+ <em>"Sometimes a guy's gotta ride the bull, am I right?"</em>
816
+ </div>
817
+ """)
818
 
819
+ # Launch with modern styling and public sharing
820
+ print("πŸš€ Launching Real Creed AI with modern glassmorphism design...")
 
 
 
 
821
 
822
+ demo.launch(
823
+ ssr_mode=False,
824
+ server_name="0.0.0.0",
825
+ server_port=7860,
826
+ share=True, # Create public link
827
+ show_error=True
828
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
829
 
830
  if __name__ == "__main__":
831
+ main()