awacke1 commited on
Commit
6217849
·
verified ·
1 Parent(s): 6b95d66

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +276 -401
app.py CHANGED
@@ -18,6 +18,7 @@ import random
18
  import logging
19
  import numpy as np
20
  import cv2
 
21
 
22
  logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
23
  logger = logging.getLogger(__name__)
@@ -37,36 +38,23 @@ st.set_page_config(
37
  menu_items={
38
  'Get Help': 'https://huggingface.co/awacke1',
39
  'Report a Bug': 'https://huggingface.co/spaces/awacke1',
40
- 'About': "Tiny Titans: Small models, big dreams, and a sprinkle of chaos! 🌌"
41
  }
42
  )
43
 
 
44
  if 'captured_images' not in st.session_state:
45
  st.session_state['captured_images'] = []
46
- if 'nlp_builder' not in st.session_state:
47
- st.session_state['nlp_builder'] = None
48
  if 'cv_builder' not in st.session_state:
49
  st.session_state['cv_builder'] = None
50
- if 'nlp_loaded' not in st.session_state:
51
- st.session_state['nlp_loaded'] = False
52
  if 'cv_loaded' not in st.session_state:
53
  st.session_state['cv_loaded'] = False
54
  if 'active_tab' not in st.session_state:
55
  st.session_state['active_tab'] = "Build Titan 🌱"
56
 
57
- @dataclass
58
- class ModelConfig:
59
- name: str
60
- base_model: str
61
- size: str
62
- domain: Optional[str] = None
63
- model_type: str = "causal_lm"
64
- @property
65
- def model_path(self):
66
- return f"models/{self.name}"
67
-
68
  @dataclass
69
  class DiffusionConfig:
 
70
  name: str
71
  base_model: str
72
  size: str
@@ -74,28 +62,9 @@ class DiffusionConfig:
74
  def model_path(self):
75
  return f"diffusion_models/{self.name}"
76
 
77
- class SFTDataset(Dataset):
78
- def __init__(self, data, tokenizer, max_length=128):
79
- self.data = data
80
- self.tokenizer = tokenizer
81
- self.max_length = max_length
82
- def __len__(self):
83
- return len(self.data)
84
- def __getitem__(self, idx):
85
- prompt = self.data[idx]["prompt"]
86
- response = self.data[idx]["response"]
87
- full_text = f"{prompt} {response}"
88
- full_encoding = self.tokenizer(full_text, max_length=self.max_length, padding="max_length", truncation=True, return_tensors="pt")
89
- prompt_encoding = self.tokenizer(prompt, max_length=self.max_length, padding=False, truncation=True, return_tensors="pt")
90
- input_ids = full_encoding["input_ids"].squeeze()
91
- attention_mask = full_encoding["attention_mask"].squeeze()
92
- labels = input_ids.clone()
93
- prompt_len = prompt_encoding["input_ids"].shape[1]
94
- if prompt_len < self.max_length:
95
- labels[:prompt_len] = -100
96
- return {"input_ids": input_ids, "attention_mask": attention_mask, "labels": labels}
97
-
98
  class DiffusionDataset(Dataset):
 
99
  def __init__(self, images, texts):
100
  self.images = images
101
  self.texts = texts
@@ -104,126 +73,167 @@ class DiffusionDataset(Dataset):
104
  def __getitem__(self, idx):
105
  return {"image": self.images[idx], "text": self.texts[idx]}
106
 
107
- class ModelBuilder:
 
108
  def __init__(self):
109
  self.config = None
110
- self.model = None
111
- self.tokenizer = None
112
- self.sft_data = None
113
- self.jokes = ["Why did the AI go to therapy? Too many layers to unpack! 😂", "Training complete! Time for a binary coffee break. ☕"]
114
- def load_model(self, model_path: str, config: Optional[ModelConfig] = None):
115
  try:
116
- with st.spinner(f"Loading {model_path}... ⏳ (Patience, young padawan!)"):
117
- self.model = AutoModelForCausalLM.from_pretrained(model_path)
118
- self.tokenizer = AutoTokenizer.from_pretrained(model_path)
119
- if self.tokenizer.pad_token is None:
120
- self.tokenizer.pad_token = self.tokenizer.eos_token
121
  if config:
122
  self.config = config
123
- self.model.to("cuda" if torch.cuda.is_available() else "cpu")
124
  st.success(f"Model loaded! 🎉 {random.choice(self.jokes)}")
125
- logger.info(f"Successfully loaded Causal LM model: {model_path}")
126
- except torch.cuda.OutOfMemoryError as e:
127
- st.error(f"GPU memory error loading {model_path}: {str(e)} 💥 (Out of GPU juice!)")
128
- logger.error(f"GPU memory error loading {model_path}: {str(e)}")
129
- raise
130
- except MemoryError as e:
131
- st.error(f"CPU memory error loading {model_path}: {str(e)} 💥 (RAM ran away!)")
132
- logger.error(f"CPU memory error loading {model_path}: {str(e)}")
133
- raise
134
  except Exception as e:
135
- st.error(f"Failed to load {model_path}: {str(e)} 💥 (Something broke—check the logs!)")
136
  logger.error(f"Failed to load {model_path}: {str(e)}")
137
  raise
138
  return self
139
- def fine_tune_sft(self, csv_path: str, epochs: int = 3, batch_size: int = 4):
140
  try:
141
- self.sft_data = []
142
- with open(csv_path, "r") as f:
143
- reader = csv.DictReader(f)
144
- for row in reader:
145
- self.sft_data.append({"prompt": row["prompt"], "response": row["response"]})
146
- dataset = SFTDataset(self.sft_data, self.tokenizer)
147
- dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
148
- optimizer = torch.optim.AdamW(self.model.parameters(), lr=2e-5)
149
- self.model.train()
150
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
151
- self.model.to(device)
152
  for epoch in range(epochs):
153
- with st.spinner(f"Training epoch {epoch + 1}/{epochs}... ⚙️ (The AI is lifting weights!)"):
154
  total_loss = 0
155
  for batch in dataloader:
156
  optimizer.zero_grad()
157
- input_ids = batch["input_ids"].to(device)
158
- attention_mask = batch["attention_mask"].to(device)
159
- labels = batch["labels"].to(device)
160
- outputs = self.model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
161
- loss = outputs.loss
 
 
 
 
162
  loss.backward()
163
  optimizer.step()
164
  total_loss += loss.item()
165
- st.write(f"Epoch {epoch + 1} completed. Average loss: {total_loss / len(dataloader):.4f}")
166
- st.success(f"SFT Fine-tuning completed! 🎉 {random.choice(self.jokes)}")
167
- logger.info(f"Successfully fine-tuned Causal LM model: {self.config.name}")
168
  except Exception as e:
169
- st.error(f"Fine-tuning failed: {str(e)} 💥 (Training hit a snag!)")
170
- logger.error(f"Fine-tuning failed: {str(e)}")
171
  raise
172
  return self
173
  def save_model(self, path: str):
174
  try:
175
- with st.spinner("Saving model... 💾 (Packing the AI’s suitcase!)"):
176
  os.makedirs(os.path.dirname(path), exist_ok=True)
177
- self.model.save_pretrained(path)
178
- self.tokenizer.save_pretrained(path)
179
- st.success(f"Model saved at {path}! ✅ May the force be with it.")
180
- logger.info(f"Model saved at {path}")
181
  except Exception as e:
182
- st.error(f"Failed to save model: {str(e)} 💥 (Save operation crashed!)")
183
- logger.error(f"Failed to save model: {str(e)}")
184
  raise
185
- def evaluate(self, prompt: str, status_container=None):
186
- self.model.eval()
187
- if status_container:
188
- status_container.write("Preparing to evaluate... 🧠 (Titan’s warming up its circuits!)")
189
- logger.info(f"Evaluating prompt: {prompt}")
190
  try:
191
- with torch.no_grad():
192
- inputs = self.tokenizer(prompt, return_tensors="pt", max_length=128, truncation=True).to(self.model.device)
193
- outputs = self.model.generate(**inputs, max_new_tokens=50, do_sample=True, top_p=0.95, temperature=0.7)
194
- result = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
195
- logger.info(f"Generated response: {result}")
196
- return result
197
  except Exception as e:
198
- logger.error(f"Evaluation error: {str(e)}")
199
- if status_container:
200
- status_container.error(f"Oops! Something broke: {str(e)} 💥 (Titan tripped over a wire!)")
201
- return f"Error: {str(e)}"
202
 
203
- class DiffusionBuilder:
 
204
  def __init__(self):
205
  self.config = None
206
  self.pipeline = None
 
207
  def load_model(self, model_path: str, config: Optional[DiffusionConfig] = None):
208
- from diffusers import StableDiffusionPipeline
209
  try:
210
- with st.spinner(f"Loading diffusion model {model_path}... ⏳"):
211
- self.pipeline = StableDiffusionPipeline.from_pretrained(model_path)
 
212
  self.pipeline.to("cuda" if torch.cuda.is_available() else "cpu")
213
  if config:
214
  self.config = config
215
- st.success(f"Diffusion model loaded! 🎨")
216
- logger.info(f"Successfully loaded Diffusion model: {model_path}")
217
- except torch.cuda.OutOfMemoryError as e:
218
- st.error(f"GPU memory error loading {model_path}: {str(e)} 💥 (Out of GPU juice!)")
219
- logger.error(f"GPU memory error loading {model_path}: {str(e)}")
220
  raise
221
- except MemoryError as e:
222
- st.error(f"CPU memory error loading {model_path}: {str(e)} 💥 (RAM ran away!)")
223
- logger.error(f"CPU memory error loading {model_path}: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  raise
 
 
 
 
 
 
 
 
225
  except Exception as e:
226
- st.error(f"Failed to load {model_path}: {str(e)} 💥 (Something broke—check the logs!)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  logger.error(f"Failed to load {model_path}: {str(e)}")
228
  raise
229
  return self
@@ -235,7 +245,7 @@ class DiffusionBuilder:
235
  self.pipeline.unet.train()
236
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
237
  for epoch in range(epochs):
238
- with st.spinner(f"Training diffusion epoch {epoch + 1}/{epochs}... ⚙️"):
239
  total_loss = 0
240
  for batch in dataloader:
241
  optimizer.zero_grad()
@@ -251,34 +261,35 @@ class DiffusionBuilder:
251
  loss.backward()
252
  optimizer.step()
253
  total_loss += loss.item()
254
- st.write(f"Epoch {epoch + 1} completed. Average loss: {total_loss / len(dataloader):.4f}")
255
- st.success("Diffusion SFT Fine-tuning completed! 🎨")
256
- logger.info(f"Successfully fine-tuned Diffusion model: {self.config.name}")
257
  except Exception as e:
258
- st.error(f"Fine-tuning failed: {str(e)} 💥 (Training hit a snag!)")
259
- logger.error(f"Fine-tuning failed: {str(e)}")
260
  raise
261
  return self
262
  def save_model(self, path: str):
263
  try:
264
- with st.spinner("Saving diffusion model... 💾"):
265
  os.makedirs(os.path.dirname(path), exist_ok=True)
266
  self.pipeline.save_pretrained(path)
267
- st.success(f"Diffusion model saved at {path}! ✅")
268
- logger.info(f"Diffusion model saved at {path}")
269
  except Exception as e:
270
- st.error(f"Failed to save model: {str(e)} 💥 (Save operation crashed!)")
271
- logger.error(f"Failed to save model: {str(e)}")
272
  raise
273
  def generate(self, prompt: str):
274
  try:
275
  return self.pipeline(prompt, num_inference_steps=50).images[0]
276
  except Exception as e:
277
- st.error(f"Image generation failed: {str(e)} 💥 (Pixel party pooper!)")
278
- logger.error(f"Image generation failed: {str(e)}")
279
  raise
280
 
281
  def generate_filename(sequence, ext="png"):
 
282
  from datetime import datetime
283
  import pytz
284
  central = pytz.timezone('US/Central')
@@ -286,26 +297,29 @@ def generate_filename(sequence, ext="png"):
286
  return f"{dt.strftime('%m-%d-%Y-%I-%M-%S-%p')}-{sequence}.{ext}"
287
 
288
  def get_download_link(file_path, mime_type="text/plain", label="Download"):
 
289
  try:
290
  with open(file_path, 'rb') as f:
291
  data = f.read()
292
  b64 = base64.b64encode(data).decode()
293
  return f'<a href="data:{mime_type};base64,{b64}" download="{os.path.basename(file_path)}">{label} 📥</a>'
294
  except Exception as e:
295
- logger.error(f"Failed to generate download link for {file_path}: {str(e)}")
296
  return f"Error: Could not generate link for {file_path}"
297
 
298
  def zip_files(files, zip_path):
 
299
  try:
300
  with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
301
  for file in files:
302
  zipf.write(file, os.path.basename(file))
303
  logger.info(f"Created ZIP file: {zip_path}")
304
  except Exception as e:
305
- logger.error(f"Failed to create ZIP file {zip_path}: {str(e)}")
306
  raise
307
 
308
  def delete_files(files):
 
309
  try:
310
  for file in files:
311
  os.remove(file)
@@ -315,14 +329,16 @@ def delete_files(files):
315
  logger.error(f"Failed to delete files: {str(e)}")
316
  raise
317
 
318
- def get_model_files(model_type="causal_lm"):
319
- path = "models/*" if model_type == "causal_lm" else "diffusion_models/*"
320
- return [d for d in glob.glob(path) if os.path.isdir(d)]
321
 
322
  def get_gallery_files(file_types):
 
323
  return sorted(list(set(f for ext in file_types for f in glob.glob(f"*.{ext}"))))
324
 
325
  def update_gallery():
 
326
  media_files = get_gallery_files(["png"])
327
  if media_files:
328
  cols = st.sidebar.columns(2)
@@ -332,8 +348,8 @@ def update_gallery():
332
  st.markdown(get_download_link(file, "image/png", "Download Snap 📸"), unsafe_allow_html=True)
333
 
334
  def get_available_video_devices():
335
- # Assuming 6 cameras as per your setup; adjust if needed
336
- video_devices = [f"Camera {i} 🎥" for i in range(6)]
337
  try:
338
  detected = []
339
  for i in range(10):
@@ -345,74 +361,15 @@ def get_available_video_devices():
345
  logger.info(f"Detected camera at index {i}")
346
  cap.release()
347
  if detected:
348
- video_devices = detected[:6] # Limit to 6 as per your spec
349
  except Exception as e:
350
  logger.error(f"Error detecting cameras: {str(e)}")
351
  return video_devices
352
 
353
- def mock_search(query: str) -> str:
354
- if "superhero" in query.lower():
355
- return "Latest trends: Gold-plated Batman statues, VR superhero battles."
356
- return "No relevant results found."
357
-
358
- class PartyPlannerAgent:
359
- def __init__(self, model, tokenizer):
360
- self.model = model
361
- self.tokenizer = tokenizer
362
- self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
363
- self.model.to(self.device)
364
- def generate(self, prompt: str) -> str:
365
- self.model.eval()
366
- with torch.no_grad():
367
- inputs = self.tokenizer(prompt, return_tensors="pt", max_length=128, truncation=True).to(self.device)
368
- outputs = self.model.generate(**inputs, max_new_tokens=100, do_sample=True, top_p=0.95, temperature=0.7)
369
- return self.tokenizer.decode(outputs[0], skip_special_tokens=True)
370
- def plan_party(self, task: str) -> pd.DataFrame:
371
- search_result = mock_search("superhero party trends")
372
- prompt = f"Given this context: '{search_result}'\n{task}"
373
- plan_text = self.generate(prompt)
374
- locations = {"Wayne Manor": (42.3601, -71.0589), "New York": (40.7128, -74.0060)}
375
- wayne_coords = locations["Wayne Manor"]
376
- travel_times = {loc: calculate_cargo_travel_time(coords, wayne_coords) for loc, coords in locations.items() if loc != "Wayne Manor"}
377
- data = [
378
- {"Location": "New York", "Travel Time (hrs)": travel_times["New York"], "Luxury Idea": "Gold-plated Batman statues"},
379
- {"Location": "Wayne Manor", "Travel Time (hrs)": 0.0, "Luxury Idea": "VR superhero battles"}
380
- ]
381
- return pd.DataFrame(data)
382
-
383
- class CVPartyPlannerAgent:
384
- def __init__(self, pipeline):
385
- self.pipeline = pipeline
386
- def generate(self, prompt: str) -> Image.Image:
387
- return self.pipeline(prompt, num_inference_steps=50).images[0]
388
- def plan_party(self, task: str) -> pd.DataFrame:
389
- search_result = mock_search("superhero party trends")
390
- prompt = f"Given this context: '{search_result}'\n{task}"
391
- data = [
392
- {"Theme": "Batman", "Image Idea": "Gold-plated Batman statue"},
393
- {"Theme": "Avengers", "Image Idea": "VR superhero battle scene"}
394
- ]
395
- return pd.DataFrame(data)
396
-
397
- def calculate_cargo_travel_time(origin_coords: Tuple[float, float], destination_coords: Tuple[float, float], cruising_speed_kmh: float = 750.0) -> float:
398
- def to_radians(degrees: float) -> float:
399
- return degrees * (math.pi / 180)
400
- lat1, lon1 = map(to_radians, origin_coords)
401
- lat2, lon2 = map(to_radians, destination_coords)
402
- EARTH_RADIUS_KM = 6371.0
403
- dlon = lon2 - lon1
404
- dlat = lat2 - lat1
405
- a = (math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2)
406
- c = 2 * math.asin(math.sqrt(a))
407
- distance = EARTH_RADIUS_KM * c
408
- actual_distance = distance * 1.1
409
- flight_time = (actual_distance / cruising_speed_kmh) + 1.0
410
- return round(flight_time, 2)
411
-
412
- st.title("SFT Tiny Titans 🚀 (Small but Mighty!)")
413
 
414
  st.sidebar.header("Media Gallery 🎨")
415
- gallery_size = st.sidebar.slider("Gallery Size 📸", 1, 10, 4, help="Adjust how many epic captures you see! 🌟")
416
  update_gallery()
417
 
418
  col1, col2 = st.sidebar.columns(2)
@@ -423,7 +380,7 @@ with col1:
423
  zip_path = f"snapshot_collection_{int(time.time())}.zip"
424
  zip_files(media_files, zip_path)
425
  st.sidebar.markdown(get_download_link(zip_path, "application/zip", "Download All Snaps 📦"), unsafe_allow_html=True)
426
- st.sidebar.success("Snapshots zipped! 🎉 Grab your loot!")
427
  else:
428
  st.sidebar.warning("No snaps to zip! 📸 Snap some first!")
429
  with col2:
@@ -444,20 +401,6 @@ if uploaded_files:
444
  f.write(uploaded_file.getvalue())
445
  logger.info(f"Uploaded file: {filename}")
446
 
447
- st.sidebar.subheader("Audio Gallery 🎵")
448
- audio_files = get_gallery_files(["mp3"])
449
- if audio_files:
450
- for file in audio_files[:gallery_size]:
451
- st.sidebar.audio(file, format="audio/mp3")
452
- st.sidebar.markdown(get_download_link(file, "audio/mp3", f"Grab Tune 🎵"), unsafe_allow_html=True)
453
-
454
- st.sidebar.subheader("Video Gallery 🎥")
455
- video_files = get_gallery_files(["mp4"])
456
- if video_files:
457
- for file in video_files[:gallery_size]:
458
- st.sidebar.video(file, format="video/mp4")
459
- st.sidebar.markdown(get_download_link(file, "video/mp4", f"Snag Clip 🎬"), unsafe_allow_html=True)
460
-
461
  st.sidebar.subheader("Image Gallery 🖼️")
462
  image_files = get_gallery_files(["png", "jpeg"])
463
  if image_files:
@@ -467,50 +410,30 @@ if image_files:
467
  st.image(Image.open(file), caption=file, use_container_width=True)
468
  st.markdown(get_download_link(file, "image/png" if file.endswith(".png") else "image/jpeg", f"Save Pic 🖼️"), unsafe_allow_html=True)
469
 
470
- st.sidebar.subheader("Markdown Gallery 📝")
471
- md_files = get_gallery_files(["md"])
472
- if md_files:
473
- for file in md_files[:gallery_size]:
474
- with open(file, "r") as f:
475
- st.sidebar.markdown(f.read())
476
- st.sidebar.markdown(get_download_link(file, "text/markdown", f"Get Note 📝"), unsafe_allow_html=True)
477
-
478
- st.sidebar.subheader("Document Gallery 📜")
479
- doc_files = get_gallery_files(["pdf", "docx"])
480
- if doc_files:
481
- for file in doc_files[:gallery_size]:
482
- mime_type = "application/pdf" if file.endswith(".pdf") else "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
483
- st.sidebar.markdown(get_download_link(file, mime_type, f"Fetch Doc 📜"), unsafe_allow_html=True)
484
-
485
  st.sidebar.subheader("Model Management 🗂️")
486
- model_type = st.sidebar.selectbox("Model Type", ["Causal LM", "Diffusion"])
487
- model_dirs = get_model_files("causal_lm" if model_type == "Causal LM" else "diffusion")
488
  selected_model = st.sidebar.selectbox("Select Saved Model", ["None"] + model_dirs)
 
489
  if selected_model != "None" and st.sidebar.button("Load Model 📂"):
490
- builder = ModelBuilder() if model_type == "Causal LM" else DiffusionBuilder()
491
- config = (ModelConfig if model_type == "Causal LM" else DiffusionConfig)(name=os.path.basename(selected_model), base_model="unknown", size="small")
 
 
 
 
492
  try:
493
  builder.load_model(selected_model, config)
494
- if model_type == "Causal LM":
495
- st.session_state['nlp_builder'] = builder
496
- st.session_state['nlp_loaded'] = True
497
- else:
498
- st.session_state['cv_builder'] = builder
499
- st.session_state['cv_loaded'] = True
500
  st.rerun()
501
  except Exception as e:
502
  st.error(f"Model load failed: {str(e)} 💥 (Check logs for details!)")
503
 
504
  st.sidebar.subheader("Model Status 🚦")
505
- st.sidebar.write(f"**NLP Model**: {'Loaded' if st.session_state['nlp_loaded'] else 'Not Loaded'} {'(Active)' if st.session_state['nlp_loaded'] and isinstance(st.session_state.get('nlp_builder'), ModelBuilder) else ''}")
506
- st.sidebar.write(f"**CV Model**: {'Loaded' if st.session_state['cv_loaded'] else 'Not Loaded'} {'(Active)' if st.session_state['cv_loaded'] and isinstance(st.session_state.get('cv_builder'), DiffusionBuilder) else ''}")
507
 
508
- tabs = [
509
- "Build Titan 🌱", "Camera Snap 📷",
510
- "Fine-Tune Titan (NLP) 🔧", "Test Titan (NLP) 🧪", "Agentic RAG Party (NLP) 🌐",
511
- "Fine-Tune Titan (CV) 🔧", "Test Titan (CV) 🧪", "Agentic RAG Party (CV) 🌐"
512
- ]
513
- tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8 = st.tabs(tabs)
514
 
515
  for i, tab in enumerate(tabs):
516
  if st.session_state['active_tab'] != tab and st.session_state.get(f'tab{i}_active', False):
@@ -520,24 +443,22 @@ for i, tab in enumerate(tabs):
520
 
521
  with tab1:
522
  st.header("Build Titan 🌱")
523
- model_type = st.selectbox("Model Type", ["Causal LM", "Diffusion"], key="build_type")
524
  base_model = st.selectbox("Select Tiny Model",
525
- ["HuggingFaceTB/SmolLM-135M", "HuggingFaceTB/SmolLM-360M", "Qwen/Qwen1.5-0.5B-Chat"] if model_type == "Causal LM" else
526
- ["stabilityai/stable-diffusion-2-base", "runwayml/stable-diffusion-v1-5"])
527
  model_name = st.text_input("Model Name", f"tiny-titan-{int(time.time())}")
528
- domain = st.text_input("Target Domain", "general", help="Where will your Titan flex its muscles? 💪") if model_type == "Causal LM" else None
529
  if st.button("Download Model ⬇️"):
530
- config = ModelConfig(name=model_name, base_model=base_model, size="small", domain=domain) if model_type == "Causal LM" else DiffusionConfig(name=model_name, base_model=base_model, size="small")
531
- builder = ModelBuilder() if model_type == "Causal LM" else DiffusionBuilder()
 
 
 
 
532
  try:
533
  builder.load_model(base_model, config)
534
  builder.save_model(config.model_path)
535
- if model_type == "Causal LM":
536
- st.session_state['nlp_builder'] = builder
537
- st.session_state['nlp_loaded'] = True
538
- else:
539
- st.session_state['cv_builder'] = builder
540
- st.session_state['cv_loaded'] = True
541
  st.rerun()
542
  except Exception as e:
543
  st.error(f"Model build failed: {str(e)} 💥 (Check logs for details!)")
@@ -612,177 +533,131 @@ with tab2:
612
  st.info("🚨 Single shots only—craft your masterpiece! 🎨")
613
 
614
  with tab3:
615
- st.header("Fine-Tune Titan (NLP) 🔧 (Teach Your Word Wizard Some Tricks!)")
616
- if not st.session_state['nlp_loaded'] or not isinstance(st.session_state['nlp_builder'], ModelBuilder):
617
- st.warning("Please build or load an NLP Titan first! ⚠️ (No word wizard, no magic!)")
618
- else:
619
- if st.button("Generate Sample CSV 📝"):
620
- sample_data = [
621
- {"prompt": "What is AI?", "response": "AI is artificial intelligence, simulating human smarts in machines."},
622
- {"prompt": "Explain machine learning", "response": "Machine learning is AI’s gym where models bulk up on data."},
623
- {"prompt": "What is a neural network?", "response": "A neural network is a brainy AI mimicking human noggins."},
624
- ]
625
- csv_path = f"sft_data_{int(time.time())}.csv"
626
- with open(csv_path, "w", newline="") as f:
627
- writer = csv.DictWriter(f, fieldnames=["prompt", "response"])
628
- writer.writeheader()
629
- writer.writerows(sample_data)
630
- st.markdown(get_download_link(csv_path, "text/csv", "Download Sample CSV 📜"), unsafe_allow_html=True)
631
- st.success(f"Sample CSV generated as {csv_path}! ✅ (Fresh from the data oven!)")
632
- uploaded_csv = st.file_uploader("Upload CSV for SFT 📜", type="csv", help="Feed your Titan some tasty prompt-response pairs! 🍽️")
633
- if uploaded_csv and st.button("Fine-Tune with Uploaded CSV 🔄"):
634
- csv_path = f"uploaded_sft_data_{int(time.time())}.csv"
635
- with open(csv_path, "wb") as f:
636
- f.write(uploaded_csv.read())
637
- new_model_name = f"{st.session_state['nlp_builder'].config.name}-sft-{int(time.time())}"
638
- new_config = ModelConfig(name=new_model_name, base_model=st.session_state['nlp_builder'].config.base_model, size="small", domain=st.session_state['nlp_builder'].config.domain)
639
- st.session_state['nlp_builder'].config = new_config
640
- with st.status("Fine-tuning NLP Titan... ⏳ (Whipping words into shape!)", expanded=True) as status:
641
- st.session_state['nlp_builder'].fine_tune_sft(csv_path)
642
- st.session_state['nlp_builder'].save_model(new_config.model_path)
643
- status.update(label="Fine-tuning completed! 🎉 (Wordsmith Titan unleashed!)", state="complete")
644
- zip_path = f"{new_config.model_path}.zip"
645
- zip_files([new_config.model_path], zip_path)
646
- st.markdown(get_download_link(zip_path, "application/zip", "Download Fine-Tuned NLP Titan 📦"), unsafe_allow_html=True)
647
-
648
- with tab4:
649
- st.header("Test Titan (NLP) 🧪 (Put Your Word Wizard to the Test!)")
650
- if not st.session_state['nlp_loaded'] or not isinstance(st.session_state['nlp_builder'], ModelBuilder):
651
- st.warning("Please build or load an NLP Titan first! ⚠️ (No word wizard, no test drive!)")
652
- else:
653
- if st.session_state['nlp_builder'].sft_data:
654
- st.write("Testing with SFT Data:")
655
- with st.spinner("Running SFT data tests... ⏳ (Titan’s flexing its word muscles!)"):
656
- for item in st.session_state['nlp_builder'].sft_data[:3]:
657
- prompt = item["prompt"]
658
- expected = item["response"]
659
- status_container = st.empty()
660
- generated = st.session_state['nlp_builder'].evaluate(prompt, status_container)
661
- st.write(f"**Prompt**: {prompt}")
662
- st.write(f"**Expected**: {expected}")
663
- st.write(f"**Generated**: {generated} (Titan says: '{random.choice(['Bleep bloop!', 'I am groot!', '42!'])}')")
664
- st.write("---")
665
- status_container.empty()
666
- test_prompt = st.text_area("Enter Test Prompt 🗣️", "What is AI?", help="Ask your Titan anything—it’s ready to chat! 😜")
667
- if st.button("Run Test ▶️"):
668
- with st.spinner("Testing your prompt... ⏳ (Titan’s pondering deeply!)"):
669
- status_container = st.empty()
670
- result = st.session_state['nlp_builder'].evaluate(test_prompt, status_container)
671
- st.write(f"**Generated Response**: {result} (Titan’s wisdom unleashed!)")
672
- status_container.empty()
673
-
674
- with tab5:
675
- st.header("Agentic RAG Party (NLP) 🌐 (Party Like It’s 2099!)")
676
- st.write("This demo uses your SFT-tuned NLP Titan to plan a superhero party with mock retrieval!")
677
- if not st.session_state['nlp_loaded'] or not isinstance(st.session_state['nlp_builder'], ModelBuilder):
678
- st.warning("Please build or load an NLP Titan first! ⚠️ (No word wizard, no party!)")
679
- else:
680
- if st.button("Run NLP RAG Demo 🎉"):
681
- with st.spinner("Loading your SFT-tuned NLP Titan... ⏳ (Titan’s suiting up!)"):
682
- agent = PartyPlannerAgent(st.session_state['nlp_builder'].model, st.session_state['nlp_builder'].tokenizer)
683
- st.write("Agent ready! 🦸���♂️ (Time to plan an epic bash!)")
684
- task = """
685
- Plan a luxury superhero-themed party at Wayne Manor (42.3601° N, 71.0589° W).
686
- Use mock search results for the latest superhero party trends, refine for luxury elements
687
- (decorations, entertainment, catering), and calculate cargo travel times from key locations
688
- (New York: 40.7128° N, 74.0060° W; LA: 34.0522° N, 118.2437° W; London: 51.5074° N, 0.1278° W)
689
- to Wayne Manor. Create a plan with at least 6 entries in a pandas dataframe.
690
- """
691
- with st.spinner("Planning the ultimate superhero bash... ⏳ (Calling all caped crusaders!)"):
692
- try:
693
- locations = {
694
- "Wayne Manor": (42.3601, -71.0589),
695
- "New York": (40.7128, -74.0060),
696
- "Los Angeles": (34.0522, -118.2437),
697
- "London": (51.5074, -0.1278)
698
- }
699
- wayne_coords = locations["Wayne Manor"]
700
- travel_times = {loc: calculate_cargo_travel_time(coords, wayne_coords) for loc, coords in locations.items() if loc != "Wayne Manor"}
701
- search_result = mock_search("superhero party trends")
702
- prompt = f"""
703
- Given this context from a search: "{search_result}"
704
- Plan a luxury superhero-themed party at Wayne Manor. Suggest luxury decorations, entertainment, and catering ideas.
705
- """
706
- plan_text = agent.generate(prompt)
707
- catchphrases = ["To the Batmobile!", "Avengers, assemble!", "I am Iron Man!", "By the power of Grayskull!"]
708
- data = [
709
- {"Location": "New York", "Travel Time (hrs)": travel_times["New York"], "Luxury Idea": "Gold-plated Batman statues", "Catchphrase": random.choice(catchphrases)},
710
- {"Location": "Los Angeles", "Travel Time (hrs)": travel_times["Los Angeles"], "Luxury Idea": "Holographic Avengers displays", "Catchphrase": random.choice(catchphrases)},
711
- {"Location": "London", "Travel Time (hrs)": travel_times["London"], "Luxury Idea": "Live stunt shows with Iron Man suits", "Catchphrase": random.choice(catchphrases)},
712
- {"Location": "Wayne Manor", "Travel Time (hrs)": 0.0, "Luxury Idea": "VR superhero battles", "Catchphrase": random.choice(catchphrases)},
713
- {"Location": "New York", "Travel Time (hrs)": travel_times["New York"], "Luxury Idea": "Gourmet kryptonite-green cocktails", "Catchphrase": random.choice(catchphrases)},
714
- {"Location": "Los Angeles", "Travel Time (hrs)": travel_times["Los Angeles"], "Luxury Idea": "Thor’s hammer-shaped appetizers", "Catchphrase": random.choice(catchphrases)},
715
- ]
716
- plan_df = pd.DataFrame(data)
717
- st.write("Agentic RAG Party Plan:")
718
- st.dataframe(plan_df)
719
- st.write("Party on, Wayne! 🦸‍♂️🎉")
720
- except Exception as e:
721
- st.error(f"Error planning party: {str(e)} (Even Superman has kryptonite days!)")
722
- logger.error(f"Error in NLP RAG demo: {str(e)}")
723
-
724
- with tab6:
725
- st.header("Fine-Tune Titan (CV) 🔧 (Paint Your Titan’s Masterpiece!)")
726
- if not st.session_state['cv_loaded'] or not isinstance(st.session_state['cv_builder'], DiffusionBuilder):
727
  st.warning("Please build or load a CV Titan first! ⚠️ (No artist, no canvas!)")
728
  else:
729
  captured_images = get_gallery_files(["png"])
730
  if len(captured_images) >= 2:
731
- demo_data = [{"image": img, "text": f"Superhero {os.path.basename(img).split('.')[0]}"} for img in captured_images[:min(len(captured_images), 10)]]
732
- edited_data = st.data_editor(pd.DataFrame(demo_data), num_rows="dynamic", help="Craft your image-text pairs like a superhero artist! 🎨")
733
- if st.button("Fine-Tune with Dataset 🔄"):
734
- images = [Image.open(row["image"]) for _, row in edited_data.iterrows()]
735
- texts = [row["text"] for _, row in edited_data.iterrows()]
736
- new_model_name = f"{st.session_state['cv_builder'].config.name}-sft-{int(time.time())}"
 
 
737
  new_config = DiffusionConfig(name=new_model_name, base_model=st.session_state['cv_builder'].config.base_model, size="small")
738
  st.session_state['cv_builder'].config = new_config
739
- with st.status("Fine-tuning CV Titan... ⏳ (Brushing up those pixels!)", expanded=True) as status:
740
  st.session_state['cv_builder'].fine_tune_sft(images, texts)
741
  st.session_state['cv_builder'].save_model(new_config.model_path)
742
- status.update(label="Fine-tuning completed! 🎉 (Pixel Titan unleashed!)", state="complete")
743
  zip_path = f"{new_config.model_path}.zip"
744
  zip_files([new_config.model_path], zip_path)
745
- st.markdown(get_download_link(zip_path, "application/zip", "Download Fine-Tuned CV Titan 📦"), unsafe_allow_html=True)
746
- csv_path = f"sft_dataset_{int(time.time())}.csv"
747
- with open(csv_path, "w", newline="") as f:
748
  writer = csv.writer(f)
749
  writer.writerow(["image", "text"])
750
- for _, row in edited_data.iterrows():
751
  writer.writerow([row["image"], row["text"]])
752
- st.markdown(get_download_link(csv_path, "text/csv", "Download SFT Dataset CSV 📜"), unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
753
 
754
- with tab7:
755
  st.header("Test Titan (CV) 🧪 (Unleash Your Pixel Power!)")
756
- if not st.session_state['cv_loaded'] or not isinstance(st.session_state['cv_builder'], DiffusionBuilder):
757
  st.warning("Please build or load a CV Titan first! ⚠️ (No artist, no masterpiece!)")
758
  else:
759
- test_prompt = st.text_area("Enter Test Prompt 🎨", "Neon Batman", help="Dream up a wild image—your Titan’s got the brush! 🖌️")
760
- if st.button("Run Test ▶️"):
761
- with st.spinner("Painting your masterpiece... ⏳ (Titan’s mixing colors!)"):
 
762
  image = st.session_state['cv_builder'].generate(test_prompt)
763
- st.image(image, caption="Generated Image", use_container_width=True)
764
 
765
- with tab8:
766
- st.header("Agentic RAG Party (CV) 🌐 (Party with Pixels!)")
767
- st.write("This demo uses your SFT-tuned CV Titan to generate superhero party images with mock retrieval!")
768
- if not st.session_state['cv_loaded'] or not isinstance(st.session_state['cv_builder'], DiffusionBuilder):
769
  st.warning("Please build or load a CV Titan first! ⚠️ (No artist, no party!)")
770
  else:
771
- if st.button("Run CV RAG Demo 🎉"):
772
- with st.spinner("Loading your SFT-tuned CV Titan... ⏳ (Titan’s grabbing its paintbrush!)"):
773
- agent = CVPartyPlannerAgent(st.session_state['cv_builder'].pipeline)
774
- st.write("Agent ready! 🎨 (Time to paint an epic bash!)")
775
- task = "Generate images for a luxury superhero-themed party."
 
 
 
 
 
 
 
 
 
 
 
 
776
  with st.spinner("Crafting superhero party visuals... ⏳ (Pixels assemble!)"):
777
  try:
778
- plan_df = agent.plan_party(task)
779
  st.dataframe(plan_df)
780
  for _, row in plan_df.iterrows():
781
  image = agent.generate(row["Image Idea"])
782
  st.image(image, caption=f"{row['Theme']} - {row['Image Idea']}", use_container_width=True)
783
  except Exception as e:
784
- st.error(f"Error in CV RAG demo: {str(e)} 💥 (Pixel party crashed!)")
785
- logger.error(f"Error in CV RAG demo: {str(e)}")
786
 
787
  st.sidebar.subheader("Action Logs 📜")
788
  log_container = st.sidebar.empty()
 
18
  import logging
19
  import numpy as np
20
  import cv2
21
+ from diffusers import DiffusionPipeline # For FLUX.1 and LDM
22
 
23
  logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
24
  logger = logging.getLogger(__name__)
 
38
  menu_items={
39
  'Get Help': 'https://huggingface.co/awacke1',
40
  'Report a Bug': 'https://huggingface.co/spaces/awacke1',
41
+ 'About': "Tiny Titans: Small diffusion models, big CV dreams! 🌌"
42
  }
43
  )
44
 
45
+ # Session State Setup 🌍 - Persistent playground for our tiny titans!
46
  if 'captured_images' not in st.session_state:
47
  st.session_state['captured_images'] = []
 
 
48
  if 'cv_builder' not in st.session_state:
49
  st.session_state['cv_builder'] = None
 
 
50
  if 'cv_loaded' not in st.session_state:
51
  st.session_state['cv_loaded'] = False
52
  if 'active_tab' not in st.session_state:
53
  st.session_state['active_tab'] = "Build Titan 🌱"
54
 
 
 
 
 
 
 
 
 
 
 
 
55
  @dataclass
56
  class DiffusionConfig:
57
+ """Config for our diffusion heroes 🦸‍♂️ - Keeps the blueprint snappy!"""
58
  name: str
59
  base_model: str
60
  size: str
 
62
  def model_path(self):
63
  return f"diffusion_models/{self.name}"
64
 
65
+ # Datasets 🎲 - Feeding our titans with pixel snacks and text treats!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  class DiffusionDataset(Dataset):
67
+ """Pixel party platter 🍕 - Images and text for diffusion delight!"""
68
  def __init__(self, images, texts):
69
  self.images = images
70
  self.texts = texts
 
73
  def __getitem__(self, idx):
74
  return {"image": self.images[idx], "text": self.texts[idx]}
75
 
76
+ class MicroDiffusionBuilder:
77
+ """Tiny titan of diffusion 🐣 - Small but mighty for quick demos!"""
78
  def __init__(self):
79
  self.config = None
80
+ self.pipeline = None
81
+ self.jokes = ["Micro but mighty! 💪", "Small pixels, big dreams! 🌟"]
82
+ def load_model(self, model_path: str, config: Optional[DiffusionConfig] = None):
 
 
83
  try:
84
+ with st.spinner(f"Loading {model_path}... ⏳ (Tiny titan powering up!)"):
85
+ # Micro Diffusion isn’t on HF yet; use a small U-Net placeholder from diffusers
86
+ self.pipeline = DiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", custom_pipeline="small_diffusion")
87
+ self.pipeline.to("cuda" if torch.cuda.is_available() else "cpu")
 
88
  if config:
89
  self.config = config
 
90
  st.success(f"Model loaded! 🎉 {random.choice(self.jokes)}")
91
+ logger.info(f"Loaded Micro Diffusion: {model_path}")
 
 
 
 
 
 
 
 
92
  except Exception as e:
93
+ st.error(f"Failed to load {model_path}: {str(e)} 💥 (Tiny titan tripped!)")
94
  logger.error(f"Failed to load {model_path}: {str(e)}")
95
  raise
96
  return self
97
+ def fine_tune_sft(self, images, texts, epochs=3):
98
  try:
99
+ dataset = DiffusionDataset(images, texts)
100
+ dataloader = DataLoader(dataset, batch_size=1, shuffle=True)
101
+ optimizer = torch.optim.AdamW(self.pipeline.unet.parameters(), lr=1e-5)
102
+ self.pipeline.unet.train()
 
 
 
 
 
103
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
104
  for epoch in range(epochs):
105
+ with st.spinner(f"Epoch {epoch + 1}/{epochs}... ⚙️ (Micro titan flexing!)"):
106
  total_loss = 0
107
  for batch in dataloader:
108
  optimizer.zero_grad()
109
+ image = batch["image"][0].to(device)
110
+ text = batch["text"][0]
111
+ latents = self.pipeline.vae.encode(torch.tensor(np.array(image)).permute(2, 0, 1).unsqueeze(0).float().to(device)).latent_dist.sample()
112
+ noise = torch.randn_like(latents)
113
+ timesteps = torch.randint(0, self.pipeline.scheduler.num_train_timesteps, (latents.shape[0],), device=latents.device)
114
+ noisy_latents = self.pipeline.scheduler.add_noise(latents, noise, timesteps)
115
+ text_embeddings = self.pipeline.text_encoder(self.pipeline.tokenizer(text, return_tensors="pt").input_ids.to(device))[0]
116
+ pred_noise = self.pipeline.unet(noisy_latents, timesteps, encoder_hidden_states=text_embeddings).sample
117
+ loss = torch.nn.functional.mse_loss(pred_noise, noise)
118
  loss.backward()
119
  optimizer.step()
120
  total_loss += loss.item()
121
+ st.write(f"Epoch {epoch + 1} done! Loss: {total_loss / len(dataloader):.4f}")
122
+ st.success(f"Micro Diffusion tuned! 🎉 {random.choice(self.jokes)}")
123
+ logger.info(f"Fine-tuned Micro Diffusion: {self.config.name}")
124
  except Exception as e:
125
+ st.error(f"Tuning failed: {str(e)} 💥 (Micro snag!)")
126
+ logger.error(f"Tuning failed: {str(e)}")
127
  raise
128
  return self
129
  def save_model(self, path: str):
130
  try:
131
+ with st.spinner("Saving model... 💾 (Packing tiny pixels!)"):
132
  os.makedirs(os.path.dirname(path), exist_ok=True)
133
+ self.pipeline.save_pretrained(path)
134
+ st.success(f"Saved at {path}! ✅ Tiny titan secured!")
135
+ logger.info(f"Saved at {path}")
 
136
  except Exception as e:
137
+ st.error(f"Save failed: {str(e)} 💥 (Packing mishap!)")
138
+ logger.error(f"Save failed: {str(e)}")
139
  raise
140
+ def generate(self, prompt: str):
 
 
 
 
141
  try:
142
+ return self.pipeline(prompt, num_inference_steps=20).images[0]
 
 
 
 
 
143
  except Exception as e:
144
+ st.error(f"Generation failed: {str(e)} 💥 (Pixel oopsie!)")
145
+ logger.error(f"Generation failed: {str(e)}")
146
+ raise
 
147
 
148
+ class LatentDiffusionBuilder:
149
+ """Scaled-down dreamer 🌙 - Latent magic for efficient artistry!"""
150
  def __init__(self):
151
  self.config = None
152
  self.pipeline = None
153
+ self.jokes = ["Latent vibes only! 🌀", "Small scale, big style! 🎨"]
154
  def load_model(self, model_path: str, config: Optional[DiffusionConfig] = None):
 
155
  try:
156
+ with st.spinner(f"Loading {model_path}... ⏳ (Latent titan rising!)"):
157
+ self.pipeline = DiffusionPipeline.from_pretrained(model_path, torch_dtype=torch.float16)
158
+ self.pipeline.unet = torch.nn.Sequential(*list(self.pipeline.unet.children())[:2]) # Scale down U-Net
159
  self.pipeline.to("cuda" if torch.cuda.is_available() else "cpu")
160
  if config:
161
  self.config = config
162
+ st.success(f"Model loaded! 🎉 {random.choice(self.jokes)}")
163
+ logger.info(f"Loaded Latent Diffusion: {model_path}")
164
+ except Exception as e:
165
+ st.error(f"Failed to load {model_path}: {str(e)} 💥 (Latent hiccup!)")
166
+ logger.error(f"Failed to load {model_path}: {str(e)}")
167
  raise
168
+ return self
169
+ def fine_tune_sft(self, images, texts, epochs=3):
170
+ try:
171
+ dataset = DiffusionDataset(images, texts)
172
+ dataloader = DataLoader(dataset, batch_size=1, shuffle=True)
173
+ optimizer = torch.optim.AdamW(self.pipeline.unet.parameters(), lr=1e-5)
174
+ self.pipeline.unet.train()
175
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
176
+ for epoch in range(epochs):
177
+ with st.spinner(f"Epoch {epoch + 1}/{epochs}... ⚙️ (Latent titan shaping up!)"):
178
+ total_loss = 0
179
+ for batch in dataloader:
180
+ optimizer.zero_grad()
181
+ image = batch["image"][0].to(device)
182
+ text = batch["text"][0]
183
+ latents = self.pipeline.vae.encode(torch.tensor(np.array(image)).permute(2, 0, 1).unsqueeze(0).float().to(device)).latent_dist.sample()
184
+ noise = torch.randn_like(latents)
185
+ timesteps = torch.randint(0, self.pipeline.scheduler.num_train_timesteps, (latents.shape[0],), device=latents.device)
186
+ noisy_latents = self.pipeline.scheduler.add_noise(latents, noise, timesteps)
187
+ text_embeddings = self.pipeline.text_encoder(self.pipeline.tokenizer(text, return_tensors="pt").input_ids.to(device))[0]
188
+ pred_noise = self.pipeline.unet(noisy_latents, timesteps, encoder_hidden_states=text_embeddings).sample
189
+ loss = torch.nn.functional.mse_loss(pred_noise, noise)
190
+ loss.backward()
191
+ optimizer.step()
192
+ total_loss += loss.item()
193
+ st.write(f"Epoch {epoch + 1} done! Loss: {total_loss / len(dataloader):.4f}")
194
+ st.success(f"Latent Diffusion tuned! 🎉 {random.choice(self.jokes)}")
195
+ logger.info(f"Fine-tuned Latent Diffusion: {self.config.name}")
196
+ except Exception as e:
197
+ st.error(f"Tuning failed: {str(e)} 💥 (Latent snag!)")
198
+ logger.error(f"Tuning failed: {str(e)}")
199
  raise
200
+ return self
201
+ def save_model(self, path: str):
202
+ try:
203
+ with st.spinner("Saving model... 💾 (Packing latent dreams!)"):
204
+ os.makedirs(os.path.dirname(path), exist_ok=True)
205
+ self.pipeline.save_pretrained(path)
206
+ st.success(f"Saved at {path}! ✅ Latent titan stashed!")
207
+ logger.info(f"Saved at {path}")
208
  except Exception as e:
209
+ st.error(f"Save failed: {str(e)} 💥 (Dreamy mishap!)")
210
+ logger.error(f"Save failed: {str(e)}")
211
+ raise
212
+ def generate(self, prompt: str):
213
+ try:
214
+ return self.pipeline(prompt, num_inference_steps=30).images[0]
215
+ except Exception as e:
216
+ st.error(f"Generation failed: {str(e)} 💥 (Latent oopsie!)")
217
+ logger.error(f"Generation failed: {str(e)}")
218
+ raise
219
+
220
+ class FluxDiffusionBuilder:
221
+ """Distilled dynamo ⚡ - High-quality pixels in a small package!"""
222
+ def __init__(self):
223
+ self.config = None
224
+ self.pipeline = None
225
+ self.jokes = ["Flux-tastic! ✨", "Small size, big wow! 🎇"]
226
+ def load_model(self, model_path: str, config: Optional[DiffusionConfig] = None):
227
+ try:
228
+ with st.spinner(f"Loading {model_path}... ⏳ (Flux titan charging!)"):
229
+ self.pipeline = DiffusionPipeline.from_pretrained(model_path, torch_dtype=torch.float16)
230
+ self.pipeline.to("cuda" if torch.cuda.is_available() else "cpu")
231
+ if config:
232
+ self.config = config
233
+ st.success(f"Model loaded! 🎉 {random.choice(self.jokes)}")
234
+ logger.info(f"Loaded FLUX.1 Distilled: {model_path}")
235
+ except Exception as e:
236
+ st.error(f"Failed to load {model_path}: {str(e)} 💥 (Flux fizzle!)")
237
  logger.error(f"Failed to load {model_path}: {str(e)}")
238
  raise
239
  return self
 
245
  self.pipeline.unet.train()
246
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
247
  for epoch in range(epochs):
248
+ with st.spinner(f"Epoch {epoch + 1}/{epochs}... ⚙️ (Flux titan powering up!)"):
249
  total_loss = 0
250
  for batch in dataloader:
251
  optimizer.zero_grad()
 
261
  loss.backward()
262
  optimizer.step()
263
  total_loss += loss.item()
264
+ st.write(f"Epoch {epoch + 1} done! Loss: {total_loss / len(dataloader):.4f}")
265
+ st.success(f"FLUX Diffusion tuned! 🎉 {random.choice(self.jokes)}")
266
+ logger.info(f"Fine-tuned FLUX.1 Distilled: {self.config.name}")
267
  except Exception as e:
268
+ st.error(f"Tuning failed: {str(e)} 💥 (Flux snag!)")
269
+ logger.error(f"Tuning failed: {str(e)}")
270
  raise
271
  return self
272
  def save_model(self, path: str):
273
  try:
274
+ with st.spinner("Saving model... 💾 (Packing flux magic!)"):
275
  os.makedirs(os.path.dirname(path), exist_ok=True)
276
  self.pipeline.save_pretrained(path)
277
+ st.success(f"Saved at {path}! ✅ Flux titan secured!")
278
+ logger.info(f"Saved at {path}")
279
  except Exception as e:
280
+ st.error(f"Save failed: {str(e)} 💥 (Fluxy mishap!)")
281
+ logger.error(f"Save failed: {str(e)}")
282
  raise
283
  def generate(self, prompt: str):
284
  try:
285
  return self.pipeline(prompt, num_inference_steps=50).images[0]
286
  except Exception as e:
287
+ st.error(f"Generation failed: {str(e)} 💥 (Flux oopsie!)")
288
+ logger.error(f"Generation failed: {str(e)}")
289
  raise
290
 
291
  def generate_filename(sequence, ext="png"):
292
+ """Time-stamped snapshots ⏰ - Keeps our pics organized with cam flair!"""
293
  from datetime import datetime
294
  import pytz
295
  central = pytz.timezone('US/Central')
 
297
  return f"{dt.strftime('%m-%d-%Y-%I-%M-%S-%p')}-{sequence}.{ext}"
298
 
299
  def get_download_link(file_path, mime_type="text/plain", label="Download"):
300
+ """Magic link maker 🔗 - Snag your files with a click!"""
301
  try:
302
  with open(file_path, 'rb') as f:
303
  data = f.read()
304
  b64 = base64.b64encode(data).decode()
305
  return f'<a href="data:{mime_type};base64,{b64}" download="{os.path.basename(file_path)}">{label} 📥</a>'
306
  except Exception as e:
307
+ logger.error(f"Failed to generate link for {file_path}: {str(e)}")
308
  return f"Error: Could not generate link for {file_path}"
309
 
310
  def zip_files(files, zip_path):
311
+ """Zip zap zoo 🎒 - Bundle up your goodies!"""
312
  try:
313
  with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
314
  for file in files:
315
  zipf.write(file, os.path.basename(file))
316
  logger.info(f"Created ZIP file: {zip_path}")
317
  except Exception as e:
318
+ logger.error(f"Failed to create ZIP {zip_path}: {str(e)}")
319
  raise
320
 
321
  def delete_files(files):
322
+ """Trash titan 🗑️ - Clear the stage for new stars!"""
323
  try:
324
  for file in files:
325
  os.remove(file)
 
329
  logger.error(f"Failed to delete files: {str(e)}")
330
  raise
331
 
332
+ def get_model_files():
333
+ """Model treasure hunt 🗺️ - Find our diffusion gems!"""
334
+ return [d for d in glob.glob("diffusion_models/*") if os.path.isdir(d)]
335
 
336
  def get_gallery_files(file_types):
337
+ """Gallery curator 🖼️ - Showcase our pixel masterpieces!"""
338
  return sorted(list(set(f for ext in file_types for f in glob.glob(f"*.{ext}"))))
339
 
340
  def update_gallery():
341
+ """Gallery refresh 🌟 - Keep the art flowing!"""
342
  media_files = get_gallery_files(["png"])
343
  if media_files:
344
  cols = st.sidebar.columns(2)
 
348
  st.markdown(get_download_link(file, "image/png", "Download Snap 📸"), unsafe_allow_html=True)
349
 
350
  def get_available_video_devices():
351
+ """Camera roll call 🎥 - Who’s ready to shine?"""
352
+ video_devices = [f"Camera {i} 🎥" for i in range(6)] # 6 cams as per your setup
353
  try:
354
  detected = []
355
  for i in range(10):
 
361
  logger.info(f"Detected camera at index {i}")
362
  cap.release()
363
  if detected:
364
+ video_devices = detected[:6] # Cap at 6
365
  except Exception as e:
366
  logger.error(f"Error detecting cameras: {str(e)}")
367
  return video_devices
368
 
369
+ st.title("SFT Tiny Titans 🚀 (Small Diffusion Delight!)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
 
371
  st.sidebar.header("Media Gallery 🎨")
372
+ gallery_size = st.sidebar.slider("Gallery Size 📸", 1, 10, 4, help="How many snaps to flaunt? 🌟")
373
  update_gallery()
374
 
375
  col1, col2 = st.sidebar.columns(2)
 
380
  zip_path = f"snapshot_collection_{int(time.time())}.zip"
381
  zip_files(media_files, zip_path)
382
  st.sidebar.markdown(get_download_link(zip_path, "application/zip", "Download All Snaps 📦"), unsafe_allow_html=True)
383
+ st.sidebar.success("Snaps zipped! 🎉 Grab your loot!")
384
  else:
385
  st.sidebar.warning("No snaps to zip! 📸 Snap some first!")
386
  with col2:
 
401
  f.write(uploaded_file.getvalue())
402
  logger.info(f"Uploaded file: {filename}")
403
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  st.sidebar.subheader("Image Gallery 🖼️")
405
  image_files = get_gallery_files(["png", "jpeg"])
406
  if image_files:
 
410
  st.image(Image.open(file), caption=file, use_container_width=True)
411
  st.markdown(get_download_link(file, "image/png" if file.endswith(".png") else "image/jpeg", f"Save Pic 🖼️"), unsafe_allow_html=True)
412
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  st.sidebar.subheader("Model Management 🗂️")
414
+ model_dirs = get_model_files()
 
415
  selected_model = st.sidebar.selectbox("Select Saved Model", ["None"] + model_dirs)
416
+ model_type = st.sidebar.selectbox("Diffusion Type", ["Micro Diffusion", "Latent Diffusion", "FLUX.1 Distilled"])
417
  if selected_model != "None" and st.sidebar.button("Load Model 📂"):
418
+ builder = {
419
+ "Micro Diffusion": MicroDiffusionBuilder,
420
+ "Latent Diffusion": LatentDiffusionBuilder,
421
+ "FLUX.1 Distilled": FluxDiffusionBuilder
422
+ }[model_type]()
423
+ config = DiffusionConfig(name=os.path.basename(selected_model), base_model="unknown", size="small")
424
  try:
425
  builder.load_model(selected_model, config)
426
+ st.session_state['cv_builder'] = builder
427
+ st.session_state['cv_loaded'] = True
 
 
 
 
428
  st.rerun()
429
  except Exception as e:
430
  st.error(f"Model load failed: {str(e)} 💥 (Check logs for details!)")
431
 
432
  st.sidebar.subheader("Model Status 🚦")
433
+ st.sidebar.write(f"**CV Model**: {'Loaded' if st.session_state['cv_loaded'] else 'Not Loaded'} {'(Active)' if st.session_state['cv_loaded'] and isinstance(st.session_state.get('cv_builder'), (MicroDiffusionBuilder, LatentDiffusionBuilder, FluxDiffusionBuilder)) else ''}")
 
434
 
435
+ tabs = ["Build Titan 🌱", "Camera Snap 📷", "Fine-Tune Titan (CV) 🔧", "Test Titan (CV) 🧪", "Agentic RAG Party (CV) 🌐"]
436
+ tab1, tab2, tab3, tab4, tab5 = st.tabs(tabs)
 
 
 
 
437
 
438
  for i, tab in enumerate(tabs):
439
  if st.session_state['active_tab'] != tab and st.session_state.get(f'tab{i}_active', False):
 
443
 
444
  with tab1:
445
  st.header("Build Titan 🌱")
446
+ model_type = st.selectbox("Diffusion Type", ["Micro Diffusion", "Latent Diffusion", "FLUX.1 Distilled"], key="build_type")
447
  base_model = st.selectbox("Select Tiny Model",
448
+ ["sony/micro-diffusion" if model_type == "Micro Diffusion" else "runwayml/stable-diffusion-v1-5" if model_type == "Latent Diffusion" else "black-forest-labs/flux.1-distilled"])
 
449
  model_name = st.text_input("Model Name", f"tiny-titan-{int(time.time())}")
 
450
  if st.button("Download Model ⬇️"):
451
+ config = DiffusionConfig(name=model_name, base_model=base_model, size="small")
452
+ builder = {
453
+ "Micro Diffusion": MicroDiffusionBuilder,
454
+ "Latent Diffusion": LatentDiffusionBuilder,
455
+ "FLUX.1 Distilled": FluxDiffusionBuilder
456
+ }[model_type]()
457
  try:
458
  builder.load_model(base_model, config)
459
  builder.save_model(config.model_path)
460
+ st.session_state['cv_builder'] = builder
461
+ st.session_state['cv_loaded'] = True
 
 
 
 
462
  st.rerun()
463
  except Exception as e:
464
  st.error(f"Model build failed: {str(e)} 💥 (Check logs for details!)")
 
533
  st.info("🚨 Single shots only—craft your masterpiece! 🎨")
534
 
535
  with tab3:
536
+ st.header("Fine-Tune Titan (CV) 🔧 (Sculpt Your Pixel Prodigy!)")
537
+ if not st.session_state['cv_loaded'] or not isinstance(st.session_state['cv_builder'], (MicroDiffusionBuilder, LatentDiffusionBuilder, FluxDiffusionBuilder)):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
538
  st.warning("Please build or load a CV Titan first! ⚠️ (No artist, no canvas!)")
539
  else:
540
  captured_images = get_gallery_files(["png"])
541
  if len(captured_images) >= 2:
542
+ # Use Case 1: Denoising (Micro Diffusion)
543
+ st.subheader("Use Case 1: Denoise Snapshots 🌟")
544
+ denoising_data = [{"image": img, "text": f"Denoised {os.path.basename(img).split('-')[4]} snap"} for img in captured_images[:min(len(captured_images), 10)]]
545
+ denoising_edited = st.data_editor(pd.DataFrame(denoising_data), num_rows="dynamic", help="Craft denoising pairs! 🌟")
546
+ if st.button("Fine-Tune Denoising 🔄"):
547
+ images = [Image.open(row["image"]) for _, row in denoising_edited.iterrows()]
548
+ texts = [row["text"] for _, row in denoising_edited.iterrows()]
549
+ new_model_name = f"{st.session_state['cv_builder'].config.name}-denoise-{int(time.time())}"
550
  new_config = DiffusionConfig(name=new_model_name, base_model=st.session_state['cv_builder'].config.base_model, size="small")
551
  st.session_state['cv_builder'].config = new_config
552
+ with st.status("Fine-tuning for denoising... ⏳ (Polishing pixels!)", expanded=True) as status:
553
  st.session_state['cv_builder'].fine_tune_sft(images, texts)
554
  st.session_state['cv_builder'].save_model(new_config.model_path)
555
+ status.update(label="Denoising tuned! 🎉 (Pixel shine unleashed!)", state="complete")
556
  zip_path = f"{new_config.model_path}.zip"
557
  zip_files([new_config.model_path], zip_path)
558
+ st.markdown(get_download_link(zip_path, "application/zip", "Download Denoised Titan 📦"), unsafe_allow_html=True)
559
+ denoising_csv = f"denoise_dataset_{int(time.time())}.csv"
560
+ with open(denoising_csv, "w", newline="") as f:
561
  writer = csv.writer(f)
562
  writer.writerow(["image", "text"])
563
+ for _, row in denoising_edited.iterrows():
564
  writer.writerow([row["image"], row["text"]])
565
+ st.markdown(get_download_link(denoising_csv, "text/csv", "Download Denoising CSV 📜"), unsafe_allow_html=True)
566
+
567
+ # Use Case 2: Stylization (Latent Diffusion)
568
+ st.subheader("Use Case 2: Stylize Snapshots 🎨")
569
+ stylize_data = [{"image": img, "text": f"Neon {os.path.basename(img).split('-')[4]} style"} for img in captured_images[:min(len(captured_images), 10)]]
570
+ stylize_edited = st.data_editor(pd.DataFrame(stylize_data), num_rows="dynamic", help="Craft stylized pairs! 🎨")
571
+ if st.button("Fine-Tune Stylization 🔄"):
572
+ images = [Image.open(row["image"]) for _, row in stylize_edited.iterrows()]
573
+ texts = [row["text"] for _, row in stylize_edited.iterrows()]
574
+ new_model_name = f"{st.session_state['cv_builder'].config.name}-stylize-{int(time.time())}"
575
+ new_config = DiffusionConfig(name=new_model_name, base_model=st.session_state['cv_builder'].config.base_model, size="small")
576
+ st.session_state['cv_builder'].config = new_config
577
+ with st.status("Fine-tuning for stylization... ⏳ (Painting pixels!)", expanded=True) as status:
578
+ st.session_state['cv_builder'].fine_tune_sft(images, texts)
579
+ st.session_state['cv_builder'].save_model(new_config.model_path)
580
+ status.update(label="Stylization tuned! 🎉 (Pixel art unleashed!)", state="complete")
581
+ zip_path = f"{new_config.model_path}.zip"
582
+ zip_files([new_config.model_path], zip_path)
583
+ st.markdown(get_download_link(zip_path, "application/zip", "Download Stylized Titan 📦"), unsafe_allow_html=True)
584
+ stylize_md = f"stylize_dataset_{int(time.time())}.md"
585
+ with open(stylize_md, "w") as f:
586
+ f.write("# Stylization Dataset\n\n")
587
+ for _, row in stylize_edited.iterrows():
588
+ f.write(f"- `{row['image']}`: {row['text']}\n")
589
+ st.markdown(get_download_link(stylize_md, "text/markdown", "Download Stylization MD 📝"), unsafe_allow_html=True)
590
+
591
+ # Use Case 3: Multi-Angle Generation (FLUX.1)
592
+ st.subheader("Use Case 3: Multi-Angle Snapshots 🌐")
593
+ multiangle_data = [{"image": img, "text": f"View from {os.path.basename(img).split('-')[4]}"} for img in captured_images[:min(len(captured_images), 10)]]
594
+ multiangle_edited = st.data_editor(pd.DataFrame(multiangle_data), num_rows="dynamic", help="Craft multi-angle pairs! 🌐")
595
+ if st.button("Fine-Tune Multi-Angle 🔄"):
596
+ images = [Image.open(row["image"]) for _, row in multiangle_edited.iterrows()]
597
+ texts = [row["text"] for _, row in multiangle_edited.iterrows()]
598
+ new_model_name = f"{st.session_state['cv_builder'].config.name}-multiangle-{int(time.time())}"
599
+ new_config = DiffusionConfig(name=new_model_name, base_model=st.session_state['cv_builder'].config.base_model, size="small")
600
+ st.session_state['cv_builder'].config = new_config
601
+ with st.status("Fine-tuning for multi-angle... ⏳ (Spinning pixels!)", expanded=True) as status:
602
+ st.session_state['cv_builder'].fine_tune_sft(images, texts)
603
+ st.session_state['cv_builder'].save_model(new_config.model_path)
604
+ status.update(label="Multi-angle tuned! 🎉 (Pixel views unleashed!)", state="complete")
605
+ zip_path = f"{new_config.model_path}.zip"
606
+ zip_files([new_config.model_path], zip_path)
607
+ st.markdown(get_download_link(zip_path, "application/zip", "Download Multi-Angle Titan 📦"), unsafe_allow_html=True)
608
+ multiangle_csv = f"multiangle_dataset_{int(time.time())}.csv"
609
+ with open(multiangle_csv, "w", newline="") as f:
610
+ writer = csv.writer(f)
611
+ writer.writerow(["image", "text"])
612
+ for _, row in multiangle_edited.iterrows():
613
+ writer.writerow([row["image"], row["text"]])
614
+ st.markdown(get_download_link(multiangle_csv, "text/csv", "Download Multi-Angle CSV 📜"), unsafe_allow_html=True)
615
 
616
+ with tab4:
617
  st.header("Test Titan (CV) 🧪 (Unleash Your Pixel Power!)")
618
+ if not st.session_state['cv_loaded'] or not isinstance(st.session_state['cv_builder'], (MicroDiffusionBuilder, LatentDiffusionBuilder, FluxDiffusionBuilder)):
619
  st.warning("Please build or load a CV Titan first! ⚠️ (No artist, no masterpiece!)")
620
  else:
621
+ st.subheader("Test Your Titan 🎨")
622
+ test_prompt = st.text_area("Prompt 🎤", "Neon glow from cam0", help="Dream up a wild image—your Titan’s ready to paint! 🖌️")
623
+ if st.button("Generate ▶️"):
624
+ with st.spinner("Crafting your masterpiece... ⏳ (Titan’s mixing pixels!)"):
625
  image = st.session_state['cv_builder'].generate(test_prompt)
626
+ st.image(image, caption=f"Generated: {test_prompt}", use_container_width=True)
627
 
628
+ with tab5:
629
+ st.header("Agentic RAG Party (CV) 🌐 (Pixel Party Extravaganza!)")
630
+ st.write("Generate superhero party vibes from your tuned Titan! 🎉")
631
+ if not st.session_state['cv_loaded'] or not isinstance(st.session_state['cv_builder'], (MicroDiffusionBuilder, LatentDiffusionBuilder, FluxDiffusionBuilder)):
632
  st.warning("Please build or load a CV Titan first! ⚠️ (No artist, no party!)")
633
  else:
634
+ if st.button("Run RAG Demo 🎉"):
635
+ with st.spinner("Loading your pixel party titan... ⏳ (Titan’s grabbing its brush!)"):
636
+ class CVPartyAgent:
637
+ def __init__(self, pipeline):
638
+ self.pipeline = pipeline
639
+ def generate(self, prompt: str) -> Image.Image:
640
+ return self.pipeline(prompt, num_inference_steps=50).images[0]
641
+ def plan_party(self):
642
+ prompts = [
643
+ "Gold-plated Batman statue from cam0",
644
+ "VR superhero battle scene from cam1",
645
+ "Neon-lit Avengers tower from cam2"
646
+ ]
647
+ data = [{"Theme": f"Scene {i+1}", "Image Idea": prompt} for i, prompt in enumerate(prompts)]
648
+ return pd.DataFrame(data)
649
+ agent = CVPartyAgent(st.session_state['cv_builder'].pipeline)
650
+ st.write("Party agent ready! 🎨 (Time to paint an epic bash!)")
651
  with st.spinner("Crafting superhero party visuals... ⏳ (Pixels assemble!)"):
652
  try:
653
+ plan_df = agent.plan_party()
654
  st.dataframe(plan_df)
655
  for _, row in plan_df.iterrows():
656
  image = agent.generate(row["Image Idea"])
657
  st.image(image, caption=f"{row['Theme']} - {row['Image Idea']}", use_container_width=True)
658
  except Exception as e:
659
+ st.error(f"Party crashed: {str(e)} 💥 (Pixel oopsie!)")
660
+ logger.error(f"RAG demo failed: {str(e)}")
661
 
662
  st.sidebar.subheader("Action Logs 📜")
663
  log_container = st.sidebar.empty()