Spaces:
No application file
No application file
| # -*- coding: utf-8 -*- | |
| """Face_Segmentation_Project.ipynb | |
| Automatically generated by Colab. | |
| Original file is located at | |
| https://colab.research.google.com/drive/1sLYDzM6pK7GBZW2JH7xMoVa0kOYYS9B5 | |
| ## STEP 1 β Google Drive Mount Karo | |
| """ | |
| from google.colab import drive | |
| drive.mount('/content/drive') | |
| """## β STEP 2 β Set Path | |
| """ | |
| # Pehle path define karo (Apne folder ke hisaab se check kar lena) | |
| TRAIN_NPY = "/content/drive/MyDrive/Face_Segmentation_Project/data/raw/Part 1- Train data - images.npy" | |
| import numpy as np | |
| print("Loading .npy file... (thoda time lagega 1.26GB hai)") | |
| data = np.load(TRAIN_NPY, allow_pickle=True) | |
| print("\n--- DATA INFO ---") | |
| print("Type :", type(data)) | |
| print("Shape :", data.shape) | |
| print("Dtype :", data.dtype) | |
| # Agar object/dictionary ho | |
| if data.dtype == object: | |
| print("\nObject type hai, keys dekho:") | |
| try: | |
| d = data.item() | |
| print("Keys:", d.keys()) | |
| except: | |
| print("Array of objects - length:", len(data)) | |
| print("First element type:", type(data[0])) | |
| print("First element shape:", data[0].shape if hasattr(data[0], 'shape') else "no shape") | |
| else: | |
| print("\nMin value :", data.min()) | |
| print("Max value :", data.max()) | |
| print("Total images:", data.shape[0]) | |
| # STEP 3 β Data Visualization (Andar kya hai dekho) | |
| import matplotlib.pyplot as plt | |
| # Pehla sample nikaalte hain | |
| sample = data[0] | |
| image_data = sample[0] # Pehla part image hona chahiye | |
| mask_data = sample[1] # Dusra part mask ya annotations | |
| print(f"Image shape: {image_data.shape}") | |
| print(f"Mask/Metadata type: {type(mask_data)}") | |
| # Ek bar visualize karke dekhte hain | |
| plt.imshow(image_data) | |
| plt.title("Sample Image") | |
| plt.show() | |
| # β STEP 4 β Mask Check Karo (Andar kya hai?) | |
| # List ka content check karte hain | |
| print("Mask List Content:") | |
| print(mask_data) | |
| # Agar list ke pehle element mein 'notes' ya 'points' jaisi koi key hai toh: | |
| if len(mask_data) > 0: | |
| print("\nFirst element in list:", mask_data[0]) | |
| # π οΈ STEP 5 β Coordinates se Binary Mask Banana | |
| import cv2 | |
| import numpy as np | |
| def create_mask(image_shape, mask_list): | |
| # Ek khali black image banao (0s) | |
| mask = np.zeros(image_shape[:2], dtype=np.uint8) | |
| h, w = image_shape[:2] | |
| for item in mask_list: | |
| # Normalized coordinates ko pixel values mein badlo | |
| p1 = item['points'][0] | |
| p2 = item['points'][1] | |
| x1, y1 = int(p1['x'] * w), int(p1['y'] * h) | |
| x2, y2 = int(p2['x'] * w), int(p2['y'] * h) | |
| # Is area ko white (255) kar do | |
| cv2.rectangle(mask, (x1, y1), (x2, y2), 255, -1) | |
| return mask | |
| # Test karte hain | |
| test_mask = create_mask(image_data.shape, mask_data) | |
| # Visualize Image + Mask | |
| plt.figure(figsize=(10, 5)) | |
| plt.subplot(1, 2, 1) | |
| plt.imshow(image_data); plt.title("Original Image") | |
| plt.subplot(1, 2, 2) | |
| plt.imshow(test_mask, cmap='gray'); plt.title("Generated Mask") | |
| plt.show() | |
| # β STEP 6 β Data Preprocessing for U-Net | |
| import cv2 | |
| import numpy as np | |
| from tqdm import tqdm | |
| IMG_HEIGHT = 256 | |
| IMG_WIDTH = 256 | |
| X = [] | |
| y = [] | |
| print("Processing 409 images and masks...") | |
| for i in tqdm(range(len(data))): | |
| img_array = data[i][0] | |
| mask_list = data[i][1] | |
| img_resized = cv2.resize(img_array, (IMG_WIDTH, IMG_HEIGHT)) | |
| if len(img_resized.shape) == 2: | |
| img_resized = cv2.cvtColor(img_resized, cv2.COLOR_GRAY2RGB) | |
| elif img_resized.shape[2] == 4: | |
| img_resized = cv2.cvtColor(img_resized, cv2.COLOR_RGBA2RGB) | |
| m_array = create_mask(img_array.shape, mask_list) | |
| mask_resized = cv2.resize(m_array, (IMG_WIDTH, IMG_HEIGHT)) | |
| img_norm = img_resized / 255.0 | |
| mask_norm = mask_resized / 255.0 | |
| # β Original image add karo | |
| X.append(img_norm) | |
| y.append(mask_norm) | |
| # β Augmentation 1 β Horizontal Flip | |
| X.append(cv2.flip(img_norm, 1)) | |
| y.append(cv2.flip(mask_norm, 1)) | |
| # β Augmentation 2 β Rotation 15 degree | |
| M = cv2.getRotationMatrix2D((128, 128), 15, 1.0) | |
| X.append(cv2.warpAffine(img_norm, M, (256, 256))) | |
| y.append(cv2.warpAffine(mask_norm, M, (256, 256))) | |
| # β Augmentation 3 β Brightness Change | |
| bright = np.clip(img_norm * 1.2, 0, 1) | |
| X.append(bright) | |
| y.append(mask_norm) | |
| X = np.array(X, dtype=np.float32) | |
| y = np.array(y, dtype=np.float32) | |
| y = np.expand_dims(y, axis=-1) | |
| print("\nβ Preprocessing Complete!") | |
| print(f"Images Shape: {X.shape}") | |
| print(f"Masks Shape : {y.shape}") | |
| # π STEP 7 β Model Building: U-Net with MobileNetV2 | |
| from sklearn.model_selection import train_test_split | |
| X_train, X_temp, y_train, y_temp = train_test_split( | |
| X, y, test_size=0.2, random_state=42 | |
| ) | |
| X_val, X_test, y_val, y_test = train_test_split( | |
| X_temp, y_temp, test_size=0.5, random_state=42 | |
| ) | |
| print(f"Training data : {X_train.shape}") | |
| print(f"Validation data : {X_val.shape}") | |
| print(f"Test data : {X_test.shape}") | |
| from tensorflow.keras.applications import MobileNetV2 | |
| from tensorflow.keras.layers import Input, Conv2D, UpSampling2D, Concatenate, BatchNormalization, Activation, Dropout | |
| from tensorflow.keras.models import Model | |
| import tensorflow as tf | |
| def build_unet(input_shape): | |
| inputs = Input(input_shape) | |
| base_model = MobileNetV2(input_tensor=inputs, weights="imagenet", include_top=False) | |
| # β FIX 1: Encoder freeze karo | |
| base_model.trainable = False | |
| for layer in base_model.layers[-30:]: | |
| layer.trainable = True | |
| # Skip connections | |
| s1 = inputs | |
| s2 = base_model.get_layer("block_1_expand_relu").output | |
| s3 = base_model.get_layer("block_3_expand_relu").output | |
| s4 = base_model.get_layer("block_6_expand_relu").output | |
| bridge = base_model.get_layer("block_13_expand_relu").output | |
| # β FIX 2: Dropout add kiya har decoder block mein | |
| u1 = UpSampling2D((2, 2))(bridge) | |
| u1 = Concatenate()([u1, s4]) | |
| u1 = Conv2D(256, 3, padding="same", kernel_initializer="he_normal")(u1) | |
| u1 = BatchNormalization()(u1) | |
| u1 = Activation("relu")(u1) | |
| u1 = Dropout(0.3)(u1) # β | |
| u2 = UpSampling2D((2, 2))(u1) | |
| u2 = Concatenate()([u2, s3]) | |
| u2 = Conv2D(128, 3, padding="same", kernel_initializer="he_normal")(u2) | |
| u2 = BatchNormalization()(u2) | |
| u2 = Activation("relu")(u2) | |
| u2 = Dropout(0.3)(u2) # β | |
| u3 = UpSampling2D((2, 2))(u2) | |
| u3 = Concatenate()([u3, s2]) | |
| u3 = Conv2D(64, 3, padding="same", kernel_initializer="he_normal")(u3) | |
| u3 = BatchNormalization()(u3) | |
| u3 = Activation("relu")(u3) | |
| u3 = Dropout(0.2)(u3) # β | |
| u4 = UpSampling2D((2, 2))(u3) | |
| u4 = Concatenate()([u4, s1]) | |
| u4 = Conv2D(32, 3, padding="same", kernel_initializer="he_normal")(u4) | |
| u4 = BatchNormalization()(u4) | |
| u4 = Activation("relu")(u4) | |
| outputs = Conv2D(1, 1, activation="sigmoid")(u4) | |
| return Model(inputs, outputs) | |
| model = build_unet((256, 256, 3)) | |
| # β FIX 3: Combined Loss | |
| def dice_coefficient(y_true, y_pred): | |
| y_true_f = tf.cast(tf.reshape(y_true, [-1]), tf.float32) | |
| y_pred_f = tf.cast(tf.reshape(y_pred, [-1]), tf.float32) | |
| intersection = tf.reduce_sum(y_true_f * y_pred_f) | |
| return (2. * intersection + 1.0) / (tf.reduce_sum(y_true_f) + tf.reduce_sum(y_pred_f) + 1.0) | |
| def dice_loss(y_true, y_pred): | |
| return 1 - dice_coefficient(y_true, y_pred) | |
| def combined_loss(y_true, y_pred): | |
| return dice_loss(y_true, y_pred) + tf.keras.losses.binary_crossentropy(y_true, y_pred) | |
| model.compile( | |
| optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3), | |
| loss=combined_loss, # β Combined loss | |
| metrics=[dice_coefficient, "accuracy"] | |
| ) | |
| print("β Model Compiled Successfully!") | |
| # Training se PEHLE yeh check karo: | |
| print(f"X_train shape: {X_train.shape}") | |
| print(f"X_val shape : {X_val.shape}") | |
| print(f"X_test shape : {X_test.shape}") | |
| # π STEP 9 β Model Training (Fit) | |
| from tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping | |
| callbacks = [ | |
| ModelCheckpoint("best_face_model.keras", monitor='val_dice_coefficient', | |
| mode='max', save_best_only=True, verbose=1), | |
| ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, | |
| min_lr=1e-7, verbose=1), | |
| EarlyStopping(monitor='val_loss', patience=12, | |
| restore_best_weights=True, verbose=1) | |
| ] | |
| print("π Training shuru ho rahi hai!") | |
| history = model.fit( | |
| X_train, y_train, | |
| validation_data=(X_val, y_val), | |
| epochs=50, | |
| batch_size=8, | |
| callbacks=callbacks, | |
| shuffle=True | |
| ) | |
| print("\nβ Training Complete!") | |
| # Step - Evaluation Metrix | |
| from sklearn.metrics import f1_score | |
| import time | |
| import numpy as np | |
| def evaluate_model(model, X_test, y_test): | |
| y_pred = model.predict(X_test) | |
| y_pred_binary = (y_pred > 0.5).astype(np.float32) | |
| # 1. Dice Coefficient | |
| intersection = np.sum(y_test * y_pred_binary) | |
| dice = (2. * intersection + 1.0) / ( | |
| np.sum(y_test) + np.sum(y_pred_binary) + 1.0 | |
| ) | |
| # 2. IoU Score | |
| union = np.sum(y_test) + np.sum(y_pred_binary) - intersection | |
| iou = intersection / union | |
| # 3. F1 Score | |
| f1 = f1_score( | |
| y_test.flatten().astype(int), | |
| y_pred_binary.flatten().astype(int) | |
| ) | |
| # 4. β Inference Speed β FIXED VERSION | |
| model.predict(X_test[:1], verbose=0) # Warmup 1 | |
| model.predict(X_test[:1], verbose=0) # Warmup 2 | |
| times = [] | |
| for _ in range(5): | |
| start = time.time() | |
| model.predict(X_test[:1], verbose=0) | |
| times.append((time.time() - start) * 1000) | |
| speed = np.mean(times) | |
| print("="*45) | |
| print(f"Dice Coefficient : {dice:.4f} (Target >0.92)") | |
| print(f"IoU Score : {iou:.4f} (Target >0.88)") | |
| print(f"F1 Score : {f1:.4f} (Target >0.90)") | |
| print(f"Inference Speed : {speed:.1f}ms (Target <100ms)") | |
| print("="*45) | |
| # Dobara chalao | |
| evaluate_model(model, X_test, y_test) | |
| # STEP 11 β Training Curves Plot | |
| import matplotlib.pyplot as plt | |
| plt.figure(figsize=(12, 4)) | |
| plt.subplot(1, 2, 1) | |
| plt.plot(history.history['dice_coefficient'], label='Train Dice') | |
| plt.plot(history.history['val_dice_coefficient'], label='Val Dice') | |
| plt.title('Dice Coefficient Progress') | |
| plt.xlabel('Epoch') | |
| plt.legend() | |
| plt.subplot(1, 2, 2) | |
| plt.plot(history.history['loss'], label='Train Loss') | |
| plt.plot(history.history['val_loss'], label='Val Loss') | |
| plt.title('Loss Progress') | |
| plt.xlabel('Epoch') | |
| plt.legend() | |
| plt.tight_layout() | |
| plt.show() | |
| import matplotlib.pyplot as plt | |
| def visualize_prediction(index): | |
| img = X_val[index] | |
| gt_mask = y_val[index] | |
| # Model se prediction lo | |
| pred_mask = model.predict(np.expand_dims(img, axis=0))[0] | |
| # Thresholding (0.5 se upar white, niche black) | |
| pred_mask_binary = (pred_mask > 0.5).astype(np.uint8) | |
| plt.figure(figsize=(12, 4)) | |
| plt.subplot(1, 3, 1) | |
| plt.imshow(img); plt.title("Original Image") | |
| plt.subplot(1, 3, 2) | |
| plt.imshow(gt_mask.squeeze(), cmap='gray'); plt.title("Ground Truth Mask") | |
| plt.subplot(1, 3, 3) | |
| plt.imshow(pred_mask_binary.squeeze(), cmap='gray'); plt.title("Predicted Mask") | |
| plt.show() | |
| # Pehli 3 validation images check karte hain | |
| for i in [0, 5, 10]: | |
| visualize_prediction(i) | |
| # π STEP 12 β Improving Accuracy with Hugging Face (SegFormer) | |
| !pip install -q transformers datasets | |
| from transformers import SegformerImageProcessor, SegformerForSemanticSegmentation | |
| import torch | |
| from PIL import Image | |
| # 1. Pre-trained Model Load Karein | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| # Processor images ko transform karega, model segmentation karega | |
| processor = SegformerImageProcessor.from_pretrained("nvidia/mit-b0") | |
| hf_model = SegformerForSemanticSegmentation.from_pretrained("nvidia/mit-b0", | |
| num_labels=1, | |
| ignore_mismatched_sizes=True).to(device) | |
| print("β Hugging Face SegFormer Model Loaded!") | |
| # π οΈ STEP 12 β SegFormer Dataset Class | |
| import torch | |
| from torch.utils.data import Dataset, DataLoader | |
| import numpy as np | |
| class FaceDataset(Dataset): | |
| def __init__(self, images, masks, processor): | |
| self.images = images | |
| self.masks = masks | |
| self.processor = processor | |
| def __len__(self): | |
| return len(self.images) | |
| def __getitem__(self, idx): | |
| # Image aur Mask uthayein | |
| # (X_train already normalized hai, hume original format chahiye processor ke liye) | |
| image = (self.images[idx] * 255).astype(np.uint8) | |
| mask = self.masks[idx].squeeze().astype(np.longlong) # SegFormer expects long for masks | |
| # Processor se transform karein | |
| encoded_inputs = self.processor(image, mask, return_tensors="pt") | |
| # Squeeze batch dimension jo processor add karta hai | |
| for k, v in encoded_inputs.items(): | |
| encoded_inputs[k] = v.squeeze(0) | |
| return encoded_inputs | |
| # 1. Dataset Objects Banayein | |
| train_dataset = FaceDataset(X_train, y_train, processor) | |
| val_dataset = FaceDataset(X_val, y_val, processor) | |
| # 2. DataLoaders Banayein | |
| train_dataloader = DataLoader(train_dataset, batch_size=4, shuffle=True) | |
| val_dataloader = DataLoader(val_dataset, batch_size=4) | |
| print(f"β DataLoaders Ready! Training samples: {len(train_dataset)}") | |
| # π STEP 13 β Fine-tuning SegFormer (Training Loop) | |
| from tqdm.notebook import tqdm | |
| from torch.optim import AdamW | |
| # 1. Optimizer setup | |
| optimizer = AdamW(hf_model.parameters(), lr=5e-5) | |
| # 2. Training Loop | |
| num_epochs = 10 # SegFormer jaldi seekh jata hai | |
| hf_model.train() | |
| print("π SegFormer Training shuru ho rahi hai...") | |
| for epoch in range(num_epochs): | |
| train_loss = 0 | |
| # Tqdm progress bar ke liye | |
| pbar = tqdm(train_dataloader, desc=f"Epoch {epoch+1}") | |
| for batch in pbar: | |
| # Data ko GPU/CPU par bhejein | |
| pixel_values = batch["pixel_values"].to(device) | |
| labels = batch["labels"].to(device) | |
| # Forward pass | |
| outputs = hf_model(pixel_values=pixel_values, labels=labels) | |
| loss = outputs.loss | |
| # Backward pass | |
| loss.backward() | |
| optimizer.step() | |
| optimizer.zero_grad() | |
| train_loss += loss.item() | |
| pbar.set_postfix({'loss': loss.item()}) | |
| avg_train_loss = train_loss / len(train_dataloader) | |
| print(f"β Epoch {epoch+1} Complete | Average Loss: {avg_train_loss:.4f}") | |
| print("\nπ SegFormer Fine-tuning Finished!") | |
| # π¨ STEP 14 β SegFormer Prediction & Visualization | |
| import torch.nn as nn | |
| def visualize_segformer_prediction(index): | |
| # 1. Validation set se data lein | |
| inputs = val_dataset[index] | |
| pixel_values = inputs["pixel_values"].unsqueeze(0).to(device) | |
| gt_mask = inputs["labels"].numpy() | |
| # 2. Prediction karein | |
| hf_model.eval() | |
| with torch.no_grad(): | |
| outputs = hf_model(pixel_values=pixel_values) | |
| logits = outputs.logits # [1, num_labels, height/4, width/4] | |
| # 3. Logits ko original image size (256x256) par upsample karein | |
| upsampled_logits = nn.functional.interpolate( | |
| logits, | |
| size=(256, 256), | |
| mode='bilinear', | |
| align_corners=False | |
| ) | |
| # 4. Binary mask banayein (Squeeze karke threshold lagayein) | |
| pred_mask = torch.sigmoid(upsampled_logits).cpu().numpy().squeeze() | |
| pred_mask_binary = (pred_mask > 0.5).astype(np.uint8) | |
| # 5. Plotting | |
| plt.figure(figsize=(12, 4)) | |
| # Original Image (Pixel values ko denormalize karke dikhayenge) | |
| display_img = pixel_values.cpu().squeeze().permute(1, 2, 0).numpy() | |
| display_img = (display_img - display_img.min()) / (display_img.max() - display_img.min()) | |
| plt.subplot(1, 3, 1) | |
| plt.imshow(display_img) | |
| plt.title("Original Image") | |
| plt.subplot(1, 3, 2) | |
| plt.imshow(gt_mask, cmap='gray') | |
| plt.title("Ground Truth Mask") | |
| plt.subplot(1, 3, 3) | |
| plt.imshow(pred_mask_binary, cmap='gray') | |
| plt.title("SegFormer Prediction") | |
| plt.show() | |
| # Pehle 3 validation images par results dekhein | |
| for i in [0, 5, 10]: | |
| visualize_segformer_prediction(i) | |
| # πΎ STEP 15 β Model aur Processor ko Save Karein | |
| import os | |
| # 1. Ek folder banate hain model ke liye | |
| save_directory = "my_face_segformer_model" | |
| os.makedirs(save_directory, exist_ok=True) | |
| # 2. Model ke weights aur config save karein | |
| hf_model.save_pretrained(save_directory) | |
| # 3. Processor (jo image resize aur normalize karta hai) bhi save karein | |
| processor.save_pretrained(save_directory) | |
| print(f"β Model successfully saved in: {save_directory}") | |
| # --- Google Colab Users ke liye --- | |
| # Agar aap chahte hain ki ye hamesha ke liye safe rahe, toh ise Zip karke download kar lein | |
| !zip -r face_model.zip my_face_segformer_model/ | |
| print("π¦ Zip file ban gayi hai! Ab aap ise left side ke 'Files' tab se download kar sakte hain.") | |
| from google.colab import drive | |
| import shutil | |
| import os | |
| # 1. Drive mount karein | |
| drive.mount('/content/drive') | |
| # 2. Aapka bataya hua path define karein | |
| # Hum Face_Segmentation_Project ke andar 'saved_model' naam ka folder banayenge | |
| base_path = '/content/drive/MyDrive/Face_Segmentation_Project' | |
| model_save_path = os.path.join(base_path, 'trained_segformer_model') | |
| # 3. Folder banayein agar nahi hai toh | |
| os.makedirs(model_save_path, exist_ok=True) | |
| # 4. Colab ki temporary files ko Drive par copy karein | |
| source_folder = '/content/my_face_segformer_model' | |
| # Purani files clear karke fresh copy karein | |
| if os.path.exists(model_save_path): | |
| shutil.rmtree(model_save_path) | |
| shutil.copytree(source_folder, model_save_path) | |
| print(f"β Kaam ho gaya! Aapka model yahan save hai:") | |
| print(f"π {model_save_path}") | |
| import os | |
| # Actor folders banao | |
| actors = [ | |
| "Robert_Downey_Jr", | |
| "Scarlett_Johansson", | |
| "Chris_Evans", | |
| "Tom_Cruise", | |
| "Leonardo_DiCaprio", | |
| "Brad_Pitt", | |
| "Chris Hemsworth" | |
| ] | |
| for actor in actors: | |
| os.makedirs(f"/content/actor_db/{actor}", exist_ok=True) | |
| print("β Actor folders ban gaye!") | |
| print(os.listdir("/content/actor_db")) | |
| import requests | |
| import os | |
| actor_images = { | |
| "Robert_Downey_Jr": [ | |
| "https://wallpapers.com/images/hd/focused-photography-robert-downey-jr-pjs7jatnx0yfofsc.jpg", | |
| "https://static1.srcdn.com/wordpress/wp-content/uploads/2024/07/instar53643496.jpg" | |
| ], | |
| "Scarlett_Johansson": [ | |
| "https://tse2.mm.bing.net/th/id/OIP.OwNfXHWEAynGbQwhmUNQWwHaKk?rs=1&pid=ImgDetMain&o=7&rm=3", | |
| "https://m.media-amazon.com/images/M/MV5BMjAyNjE1NjgyMF5BMl5BanBnXkFtZTcwMjg0ODY1NA@@._V1_.jpg" | |
| ], | |
| "Chris_Evans": [ | |
| "https://cdn.britannica.com/28/215028-050-94E9EA1E/American-actor-Chris-Evans-2019.jpg", | |
| "https://tse4.mm.bing.net/th/id/OIP._aupdpOey-23R2KHLQd0OgHaLH?rs=1&pid=ImgDetMain&o=7&rm=3" | |
| ], | |
| "Tom_Cruise": [ | |
| "https://image.tmdb.org/t/p/original/8qBylBsQf4llkGrWR3qAsOtOU8O.jpg", | |
| "https://m.media-amazon.com/images/M/MV5BMmU1YWU1NmMtMjAyMi00MjFiLWFmZmUtOTc1ZjI5ODkxYmQyXkEyXkFqcGc@._V1_FMjpg_UX1000_.jpg" | |
| ], | |
| "Leonardo_DiCaprio": [ | |
| "https://image.tmdb.org/t/p/original/aLUFp0zWpLVyIOgY0scIpuuKZLE.jpg", | |
| "https://wallpapers.com/images/hd/leonardo-dicaprio-actor-nl2l96xppg1rj9hz.jpg" | |
| ], | |
| "Brad_Pitt": [ | |
| "https://fr.web.img2.acsta.net/pictures/20/02/10/10/37/1374948.jpg", | |
| "https://www.gratistodo.com/wp-content/uploads/2016/09/Brad-Pitt-7.jpg" | |
| ], | |
| "Chris Hemsworth": [ | |
| "https://cdn.britannica.com/92/215392-050-96A4BC1D/Australian-actor-Chris-Hemsworth-2019.jpg", | |
| "https://static1.cbrimages.com/wordpress/wp-content/uploads/2023/06/chris-hemsworth-thor-love-and-thunder-mcu.jpg" | |
| ] | |
| } | |
| success = 0 | |
| fail = 0 | |
| for actor_name, urls in actor_images.items(): | |
| for i, url in enumerate(urls): | |
| try: | |
| response = requests.get(url, timeout=15) | |
| if response.status_code == 200: | |
| path = f"/content/actor_db/{actor_name}/{i}.jpg" | |
| with open(path, 'wb') as f: | |
| f.write(response.content) | |
| print(f"β {actor_name} β photo {i+1} downloaded") | |
| success += 1 | |
| else: | |
| print(f"β {actor_name} β photo {i+1} failed ({response.status_code})") | |
| fail += 1 | |
| except Exception as e: | |
| print(f"β {actor_name} β photo {i+1} error: {e}") | |
| fail += 1 | |
| print(f"\nβ Success: {success} | β Failed: {fail}") | |
| # Verify karo | |
| print("\nπ Database Status:") | |
| for actor in os.listdir("/content/actor_db"): | |
| photos = os.listdir(f"/content/actor_db/{actor}") | |
| print(f" {actor}: {len(photos)} photos") | |
| !pip install deepface -q | |
| !pip install tf-keras -q | |
| print("β DeepFace installed!") | |
| # Test Karo | |
| from deepface import DeepFace | |
| import cv2 | |
| import numpy as np | |
| # Test β ek image pe try karo | |
| test_img = "/content/actor_db/Robert_Downey_Jr/0.jpg" | |
| result = DeepFace.analyze( | |
| img_path=test_img, | |
| actions=['age', 'gender'], | |
| enforce_detection=False | |
| ) | |
| print("β DeepFace working!") | |
| print(f"Age: {result[0]['age']}") | |
| print(f"Gender: {result[0]['dominant_gender']}") | |
| # Step 1 β Sahi versions install karo | |
| !pip install tf-keras==2.19.0 -q | |
| !pip install keras==2.19.0 -q | |
| print("β Done!") | |
| import keras | |
| import tensorflow as tf | |
| def dice_coefficient(y_true, y_pred): | |
| y_true_f = tf.cast(tf.reshape(y_true,[-1]),tf.float32) | |
| y_pred_f = tf.cast(tf.reshape(y_pred,[-1]),tf.float32) | |
| i = tf.reduce_sum(y_true_f*y_pred_f) | |
| return (2.*i+1.)/(tf.reduce_sum(y_true_f)+tf.reduce_sum(y_pred_f)+1.) | |
| def combined_loss(y_true, y_pred): | |
| return 1-dice_coefficient(y_true,y_pred)+tf.keras.losses.binary_crossentropy(y_true,y_pred) | |
| # Pehle load karo | |
| model = keras.models.load_model( | |
| "/content/best_face_model.keras", | |
| custom_objects={ | |
| 'dice_coefficient': dice_coefficient, | |
| 'combined_loss': combined_loss | |
| } | |
| ) | |
| # Weights alag save karo | |
| model.save_weights("/content/model_weights.weights.h5") | |
| print("β Weights saved!") | |
| # Commented out IPython magic to ensure Python compatibility. | |
| # %%writefile /content/app.py | |
| # import os | |
| # os.environ['CUDA_VISIBLE_DEVICES'] = '-1' | |
| # os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' | |
| # | |
| # import streamlit as st | |
| # import numpy as np | |
| # import cv2 | |
| # from PIL import Image | |
| # import tensorflow as tf | |
| # import time | |
| # import io | |
| # | |
| # st.set_page_config(page_title="Scene Cast AI", page_icon="π¬", layout="wide") | |
| # | |
| # st.markdown("""<style> | |
| # @import url('https://fonts.googleapis.com/css2?family=Syne:wght@700;800&family=DM+Sans:wght@300;400&display=swap'); | |
| # :root{--bg:#0a0a0f;--card:#16161f;--gold:#f5c518;--blue:#4cc9f0;--text:#f0f0f5;--muted:#7a7a8c;--border:rgba(245,197,24,0.15);} | |
| # html,body,[class*="css"]{font-family:'DM Sans',sans-serif;background:var(--bg);color:var(--text);} | |
| # .stApp{background:var(--bg);} | |
| # #MainMenu,footer,header{visibility:hidden;} | |
| # [data-testid="stSidebar"]{background:#111118;border-right:1px solid var(--border);} | |
| # .hero-title{font-family:'Syne',sans-serif;font-size:3rem;font-weight:800;background:linear-gradient(135deg,#f5c518,#f0f0f5,#4cc9f0);-webkit-background-clip:text;-webkit-text-fill-color:transparent;margin:0;} | |
| # .card{background:var(--card);border:1px solid var(--border);border-radius:16px;padding:1.2rem;position:relative;overflow:hidden;} | |
| # .card::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,var(--gold),var(--blue));} | |
| # .label{font-family:'Syne',sans-serif;font-size:0.75rem;font-weight:700;letter-spacing:0.15em;text-transform:uppercase;color:var(--gold);margin-bottom:0.8rem;} | |
| # .metric-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:1rem;margin:1rem 0;} | |
| # .metric{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:1rem;text-align:center;} | |
| # .mval{font-family:'Syne',sans-serif;font-size:1.5rem;font-weight:800;color:var(--gold);} | |
| # .mval.warn{color:#fb923c;}.mval.fast{color:var(--blue);} | |
| # .mlbl{color:var(--muted);font-size:0.75rem;text-transform:uppercase;} | |
| # .mtgt{font-size:0.65rem;color:var(--muted);margin-top:0.2rem;} | |
| # .info{background:rgba(245,197,24,0.08);border-left:3px solid var(--gold);padding:0.8rem;border-radius:0 8px 8px 0;font-size:0.83rem;color:var(--muted);margin-top:0.8rem;} | |
| # .sec{display:flex;align-items:center;gap:0.8rem;margin:1.5rem 0 1rem;} | |
| # .sec-line{flex:1;height:1px;background:var(--border);} | |
| # .sec-title{font-family:'Syne',sans-serif;font-size:0.75rem;font-weight:700;letter-spacing:0.2em;text-transform:uppercase;color:var(--muted);} | |
| # .actor-card{background:var(--card);border:1px solid rgba(245,197,24,0.3);border-radius:16px;padding:1rem;text-align:center;} | |
| # .actor-name{font-family:'Syne',sans-serif;font-size:1rem;font-weight:800;color:var(--gold);margin:0.5rem 0 0.2rem;} | |
| # .stDownloadButton>button{background:linear-gradient(135deg,rgba(245,197,24,0.15),rgba(76,201,240,0.1))!important;border:1px solid rgba(245,197,24,0.4)!important;color:var(--gold)!important;font-family:'Syne',sans-serif!important;font-weight:700!important;border-radius:10px!important;width:100%!important;} | |
| # </style>""", unsafe_allow_html=True) | |
| # | |
| # # ββ Model Architecture Rebuild + Weights Load ββ | |
| # from tensorflow.keras.applications import MobileNetV2 | |
| # from tensorflow.keras.layers import Input, Conv2D, UpSampling2D, Concatenate, BatchNormalization, Activation, Dropout | |
| # from tensorflow.keras.models import Model | |
| # | |
| # def dice_coefficient(y_true, y_pred): | |
| # y_true_f = tf.cast(tf.reshape(y_true,[-1]),tf.float32) | |
| # y_pred_f = tf.cast(tf.reshape(y_pred,[-1]),tf.float32) | |
| # i = tf.reduce_sum(y_true_f*y_pred_f) | |
| # return (2.*i+1.)/(tf.reduce_sum(y_true_f)+tf.reduce_sum(y_pred_f)+1.) | |
| # | |
| # def combined_loss(y_true, y_pred): | |
| # return 1-dice_coefficient(y_true,y_pred)+tf.keras.losses.binary_crossentropy(y_true,y_pred) | |
| # | |
| # def build_unet(input_shape=(256,256,3)): | |
| # inputs = Input(input_shape) | |
| # base = MobileNetV2(input_tensor=inputs, weights=None, include_top=False) | |
| # base.trainable = False | |
| # s1=inputs | |
| # s2=base.get_layer("block_1_expand_relu").output | |
| # s3=base.get_layer("block_3_expand_relu").output | |
| # s4=base.get_layer("block_6_expand_relu").output | |
| # bridge=base.get_layer("block_13_expand_relu").output | |
| # u1=UpSampling2D((2,2))(bridge) | |
| # u1=Concatenate()([u1,s4]) | |
| # u1=Conv2D(256,3,padding="same",kernel_initializer="he_normal")(u1) | |
| # u1=BatchNormalization()(u1); u1=Activation("relu")(u1); u1=Dropout(0.3)(u1) | |
| # u2=UpSampling2D((2,2))(u1) | |
| # u2=Concatenate()([u2,s3]) | |
| # u2=Conv2D(128,3,padding="same",kernel_initializer="he_normal")(u2) | |
| # u2=BatchNormalization()(u2); u2=Activation("relu")(u2); u2=Dropout(0.3)(u2) | |
| # u3=UpSampling2D((2,2))(u2) | |
| # u3=Concatenate()([u3,s2]) | |
| # u3=Conv2D(64,3,padding="same",kernel_initializer="he_normal")(u3) | |
| # u3=BatchNormalization()(u3); u3=Activation("relu")(u3); u3=Dropout(0.2)(u3) | |
| # u4=UpSampling2D((2,2))(u3) | |
| # u4=Concatenate()([u4,s1]) | |
| # u4=Conv2D(32,3,padding="same",kernel_initializer="he_normal")(u4) | |
| # u4=BatchNormalization()(u4); u4=Activation("relu")(u4) | |
| # outputs=Conv2D(1,1,activation="sigmoid")(u4) | |
| # return Model(inputs,outputs) | |
| # | |
| # @st.cache_resource(show_spinner=False) | |
| # def load_model(): | |
| # with tf.device('/CPU:0'): | |
| # m = build_unet() | |
| # m.load_weights("/content/model_weights.weights.h5", by_name=True, skip_mismatch=True) | |
| # m.compile( | |
| # optimizer=tf.keras.optimizers.Adam(1e-4), | |
| # loss=combined_loss, | |
| # metrics=[dice_coefficient] | |
| # ) | |
| # return m | |
| # | |
| # def create_overlay(image, mask): | |
| # img=cv2.resize(np.array(image),(256,256)) | |
| # cm=np.zeros_like(img); cm[mask>127]=[245,197,24] | |
| # ov=cv2.addWeighted(img,0.55,cm,0.45,0) | |
| # ctrs,_=cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) | |
| # cv2.drawContours(ov,ctrs,-1,(245,197,24),2) | |
| # return ov | |
| # | |
| # def face_count(mask): | |
| # ctrs,_=cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) | |
| # return len([c for c in ctrs if cv2.contourArea(c)>256*256*0.005]) | |
| # | |
| # def img_bytes(arr): | |
| # buf=io.BytesIO(); Image.fromarray(arr).save(buf,format="PNG"); return buf.getvalue() | |
| # | |
| # def get_face_crops(image,mask): | |
| # img=cv2.resize(np.array(image),(256,256)) | |
| # ctrs,_=cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) | |
| # crops=[] | |
| # for c in ctrs: | |
| # if cv2.contourArea(c)>256*256*0.005: | |
| # x,y,w,h=cv2.boundingRect(c) | |
| # crop=img[max(0,y-10):min(255,y+h+10),max(0,x-10):min(255,x+w+10)] | |
| # if crop.size>0: crops.append(crop) | |
| # return crops | |
| # | |
| # def identify_actors(crops): | |
| # results=[]; db="/content/actor_db" | |
| # if not os.path.exists(db): return results | |
| # has_photos=any(len(os.listdir(f"{db}/{a}"))>0 for a in os.listdir(db) if os.path.isdir(f"{db}/{a}")) | |
| # if not has_photos: return results | |
| # try: | |
| # from deepface import DeepFace | |
| # for crop in crops: | |
| # try: | |
| # dfs=DeepFace.find(img_path=crop,db_path=db,model_name="VGG-Face",enforce_detection=False,silent=True) | |
| # if len(dfs)>0 and len(dfs[0])>0: | |
| # best=dfs[0].iloc[0] | |
| # name=best['identity'].split('/')[-2].replace('_',' ') | |
| # dist=best.get('distance',1) | |
| # conf=max(0,(1-dist)*100) | |
| # results.append({"name":name,"confidence":conf}) | |
| # else: | |
| # results.append({"name":"Unknown Actor","confidence":0}) | |
| # except: | |
| # results.append({"name":"Unknown Actor","confidence":0}) | |
| # except ImportError: | |
| # pass | |
| # return results | |
| # | |
| # with st.sidebar: | |
| # st.markdown("""<div style="text-align:center;padding:1rem 0 1.5rem;"> | |
| # <div style="font-size:2.5rem;">π¬</div> | |
| # <div style="font-family:'Syne',sans-serif;font-weight:800;color:#f5c518;">Scene Cast AI</div> | |
| # <div style="font-size:0.75rem;color:#7a7a8c;">Face Segmentation Engine</div> | |
| # </div>""",unsafe_allow_html=True) | |
| # st.markdown("**βοΈ SETTINGS**") | |
| # threshold=st.slider("Confidence Threshold",0.1,0.9,0.5,0.05) | |
| # show_ov=st.checkbox("Face Overlay",value=True) | |
| # show_mask=st.checkbox("Binary Mask",value=True) | |
| # show_conf=st.checkbox("Confidence Map",value=False) | |
| # show_actor=st.checkbox("π Actor Recognition",value=True) | |
| # st.markdown("---") | |
| # st.markdown("""**π MODEL INFO** | |
| # <div style="font-size:0.8rem;color:#7a7a8c;line-height:1.9;"> | |
| # ποΈ <b style="color:#f0f0f5;">Architecture:</b> U-Net<br> | |
| # π§ <b style="color:#f0f0f5;">Encoder:</b> MobileNetV2<br> | |
| # π¦ <b style="color:#f0f0f5;">Input:</b> 256Γ256<br> | |
| # π <b style="color:#f0f0f5;">Val Dice:</b> 0.8742 | |
| # </div>""",unsafe_allow_html=True) | |
| # | |
| # st.markdown("""<div style="text-align:center;padding:2rem 1rem 1.5rem;"> | |
| # <div style="display:inline-block;background:rgba(245,197,24,0.1);border:1px solid rgba(245,197,24,0.3);color:#f5c518;font-size:0.7rem;letter-spacing:0.2em;text-transform:uppercase;padding:0.3rem 1rem;border-radius:2rem;margin-bottom:1rem;">π¬ Powered by Deep Learning</div> | |
| # <h1 class="hero-title">Scene Cast AI</h1> | |
| # <p style="color:#7a7a8c;font-size:1rem;max-width:480px;margin:0.5rem auto;">Real-time face segmentation + actor identification.</p> | |
| # <div style="width:60px;height:2px;background:linear-gradient(90deg,#f5c518,#4cc9f0);margin:1.2rem auto 0;border-radius:2px;"></div> | |
| # </div>""",unsafe_allow_html=True) | |
| # | |
| # with st.spinner("π Loading AI Model..."): | |
| # try: | |
| # model=load_model() | |
| # st.success("β Model loaded!", icon="π€") | |
| # except Exception as e: | |
| # st.error(f"β Error: {e}") | |
| # st.stop() | |
| # | |
| # st.markdown('<div class="sec"><div class="sec-line"></div><div class="sec-title">π Upload Movie Scene</div><div class="sec-line"></div></div>',unsafe_allow_html=True) | |
| # f=st.file_uploader("Upload",type=["jpg","jpeg","png","webp"],label_visibility="collapsed") | |
| # | |
| # if f: | |
| # # π₯ FIX: Streamlit upload β OpenCV decode | |
| # file_bytes = np.asarray(bytearray(f.read()), dtype=np.uint8) | |
| # img = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR) | |
| # | |
| # if img is None: | |
| # st.error("β Image read nahi ho pa rahi. Dusri image try karo.") | |
| # st.stop() | |
| # | |
| # img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) | |
| # image = Image.fromarray(img) | |
| # | |
| # # π same code as before | |
| # ir = cv2.resize(np.array(image),(256,256))/255.0 | |
| # ii = np.expand_dims(ir,0).astype(np.float32) | |
| # | |
| # with st.spinner("π§ Analyzing..."): | |
| # with tf.device('/CPU:0'): | |
| # t0 = time.time() | |
| # pred = model.predict(ii,verbose=0)[0] | |
| # spd = (time.time()-t0)*1000 | |
| # | |
| # mask = (pred.squeeze()>threshold).astype(np.uint8)*255 | |
| # fc = face_count(mask) | |
| # cov = (np.sum(mask>0)/(256*256))*100 | |
| # | |
| # st.markdown('<div class="sec"><div class="sec-line"></div><div class="sec-title">π― Detection Results</div><div class="sec-line"></div></div>',unsafe_allow_html=True) | |
| # | |
| # ncols = 1+show_ov+show_mask+show_conf | |
| # dcols = st.columns(ncols) | |
| # with dcols[0]: | |
| # st.markdown('<div class="card"><div class="label">π¬ Original Frame</div>',unsafe_allow_html=True) | |
| # st.image(image,use_container_width=True) | |
| # st.markdown(f'<div class="info">π {image.width}Γ{image.height}px | π₯ ~{fc} face(s)</div></div>',unsafe_allow_html=True) | |
| # idx=1 | |
| # if show_ov: | |
| # ov=create_overlay(image,mask) | |
| # with dcols[idx]: | |
| # st.markdown('<div class="card"><div class="label">β¨ Face Overlay</div>',unsafe_allow_html=True) | |
| # st.image(ov,use_container_width=True) | |
| # st.markdown(f'<div class="info">π‘ Gold=face | {cov:.1f}%</div></div>',unsafe_allow_html=True) | |
| # idx+=1 | |
| # if show_mask: | |
| # with dcols[idx]: | |
| # st.markdown('<div class="card"><div class="label">π² Binary Mask</div>',unsafe_allow_html=True) | |
| # st.image(mask,use_container_width=True) | |
| # st.markdown(f'<div class="info">β¬ White=face | {threshold:.2f}</div></div>',unsafe_allow_html=True) | |
| # idx+=1 | |
| # if show_conf: | |
| # cm=cv2.applyColorMap((pred.squeeze()*255).astype(np.uint8),cv2.COLORMAP_INFERNO) | |
| # cm=cv2.cvtColor(cm,cv2.COLOR_BGR2RGB) | |
| # with dcols[idx]: | |
| # st.markdown('<div class="card"><div class="label">π‘οΈ Confidence</div>',unsafe_allow_html=True) | |
| # st.image(cm,use_container_width=True) | |
| # st.markdown('<div class="info">π΄ Hot=face</div></div>',unsafe_allow_html=True) | |
| # if show_actor: | |
| # st.markdown('<div class="sec"><div class="sec-line"></div><div class="sec-title">π Actor Recognition</div><div class="sec-line"></div></div>',unsafe_allow_html=True) | |
| # with st.spinner("π Identifying..."): | |
| # crops=get_face_crops(image,mask); actors=identify_actors(crops) | |
| # if actors: | |
| # acols=st.columns(min(len(actors),4)) | |
| # for i,a in enumerate(actors): | |
| # cc="#4ade80" if a['confidence']>60 else "#fb923c" | |
| # with acols[i%4]: | |
| # st.markdown(f"""<div class="actor-card"><div style="font-size:2rem;">π</div> | |
| # <div class="actor-name">{a['name']}</div> | |
| # <div style="font-size:0.78rem;color:{cc};">Confidence: {a['confidence']:.1f}%</div> | |
| # </div>""",unsafe_allow_html=True) | |
| # else: | |
| # st.info("π Actor DB mein photos upload karo!",icon="βΉοΈ") | |
| # st.markdown('<div class="sec"><div class="sec-line"></div><div class="sec-title">π Performance</div><div class="sec-line"></div></div>',unsafe_allow_html=True) | |
| # sc="fast" if spd<100 else "warn" | |
| # st.markdown(f"""<div class="metric-grid"> | |
| # <div class="metric"><div style="font-size:1.3rem;">π―</div><div class="mval warn">0.8845</div><div class="mlbl">Dice</div><div class="mtgt">>0.92</div></div> | |
| # <div class="metric"><div style="font-size:1.3rem;">π</div><div class="mval warn">0.7929</div><div class="mlbl">IoU</div><div class="mtgt">>0.88</div></div> | |
| # <div class="metric"><div style="font-size:1.3rem;">βοΈ</div><div class="mval warn">0.8849</div><div class="mlbl">F1</div><div class="mtgt">>0.90</div></div> | |
| # <div class="metric"><div style="font-size:1.3rem;">β‘</div><div class="mval {sc}">{spd:.0f}ms</div><div class="mlbl">Speed</div><div class="mtgt"><100ms</div></div> | |
| # </div>""",unsafe_allow_html=True) | |
| # c1,c2,c3=st.columns(3) | |
| # for col,icon,val,lbl,clr in [(c1,"π₯",str(fc),"Faces","#f5c518"),(c2,"π",f"{cov:.1f}%","Coverage","#4cc9f0"),(c3,"ποΈ",f"{threshold:.2f}","Threshold","#4ade80")]: | |
| # with col: | |
| # st.markdown(f"""<div class="card" style="text-align:center;padding:1rem;"> | |
| # <div style="font-size:2rem;">{icon}</div> | |
| # <div style="font-family:'Syne',sans-serif;font-size:1.8rem;font-weight:800;color:{clr};">{val}</div> | |
| # <div style="color:#7a7a8c;font-size:0.78rem;text-transform:uppercase;">{lbl}</div> | |
| # </div>""",unsafe_allow_html=True) | |
| # st.markdown('<div class="sec"><div class="sec-line"></div><div class="sec-title">π₯ Export</div><div class="sec-line"></div></div>',unsafe_allow_html=True) | |
| # d1,d2,d3=st.columns(3) | |
| # with d1: | |
| # st.download_button("β¬οΈ Mask",img_bytes(mask),"mask.png","image/png",use_container_width=True) | |
| # with d2: | |
| # ov2=create_overlay(image,mask) | |
| # st.download_button("β¬οΈ Overlay",img_bytes(ov2),"overlay.png","image/png",use_container_width=True) | |
| # with d3: | |
| # log=f"File:{f.name}\nFaces:{fc}\nSpeed:{spd:.1f}ms\nDice:0.8845\nIoU:0.7929" | |
| # st.download_button("β¬οΈ Log",log,"log.txt","text/plain",use_container_width=True) | |
| # else: | |
| # st.markdown("""<div style="background:#16161f;border:2px dashed rgba(245,197,24,0.2);border-radius:20px;padding:4rem 2rem;text-align:center;margin:2rem 0;"> | |
| # <div style="font-size:4rem;">π¬</div> | |
| # <div style="font-family:'Syne',sans-serif;font-size:1.4rem;font-weight:700;color:#f0f0f5;margin:0.8rem 0 0.4rem;">Ready to Detect & Identify</div> | |
| # <div style="color:#7a7a8c;">Upload movie screenshot β AI detects + identifies actors!</div> | |
| # </div>""",unsafe_allow_html=True) | |
| !sed -i 's/use_container_width=True/use_column_width=True/g' /content/app.py | |
| # Yeh cell chalao β warning fix hogi | |
| !sed -i 's/use_column_width=True/use_container_width=True/g' /content/app.py | |
| print("β Fixed!") | |
| !pip install streamlit pyngrok -q | |
| # Ek Cell Mein Sab | |
| !fuser -k 8501/tcp | |
| !pkill -f streamlit | |
| import time | |
| time.sleep(2) | |
| import subprocess, threading | |
| def run(): | |
| subprocess.Popen([ | |
| 'streamlit', 'run', '/content/app.py', | |
| '--server.port=8501', | |
| '--server.headless=true', | |
| '--server.enableCORS=false', | |
| '--server.enableXsrfProtection=false' | |
| ]) | |
| threading.Thread(target=run).start() | |
| time.sleep(15) | |
| from google.colab.output import eval_js | |
| url = eval_js("google.colab.kernel.proxyPort(8501)") | |
| print(f"β URL: {url}") |