{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "ddc93ea2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Classes: ['Kaleng', 'Residu', 'botol_plastik_PET_bening2', 'botol_plastik_PET_bewarna']\n",
      "✅ Model loaded\n",
      "\n",
      "🧠 Prediction: botol_plastik_PET_bening2\n",
      "📊 Confidence: 83.07%\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "from torchvision import models, transforms\n",
    "from PIL import Image\n",
    "\n",
    "# ==========================================\n",
    "# CONFIG\n",
    "# ==========================================\n",
    "MODEL_PATH = 'model_sampah_final_3.pth'\n",
    "LABEL_PATH = 'labels.txt'\n",
    "IMG_PATH   = '20260204_145002.jpg'\n",
    "\n",
    "DEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "\n",
    "# ==========================================\n",
    "# LOAD LABELS\n",
    "# ==========================================\n",
    "with open(LABEL_PATH, 'r') as f:\n",
    "    class_names = [line.strip() for line in f.readlines()]\n",
    "\n",
    "print(\"Classes:\", class_names)\n",
    "\n",
    "# ==========================================\n",
    "# LOAD MODEL\n",
    "# ==========================================\n",
    "model = models.mobilenet_v2(weights=None)\n",
    "num_ftrs = model.classifier[1].in_features\n",
    "model.classifier[1] = nn.Linear(num_ftrs, len(class_names))\n",
    "\n",
    "model.load_state_dict(torch.load(MODEL_PATH, map_location=DEVICE))\n",
    "model.to(DEVICE)\n",
    "model.eval()\n",
    "\n",
    "print(\"✅ Model loaded\")\n",
    "\n",
    "# ==========================================\n",
    "# PREPROCESS (SAME AS TRAINING)\n",
    "# ==========================================\n",
    "transform = transforms.Compose([\n",
    "    transforms.Resize((224, 224)),\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize(\n",
    "        mean=[0.485, 0.456, 0.406],\n",
    "        std=[0.229, 0.224, 0.225]\n",
    "    )\n",
    "])\n",
    "\n",
    "# ==========================================\n",
    "# LOAD IMAGE\n",
    "# ==========================================\n",
    "img = Image.open(IMG_PATH).convert(\"RGB\")\n",
    "input_tensor = transform(img).unsqueeze(0).to(DEVICE)\n",
    "\n",
    "# ==========================================\n",
    "# INFERENCE\n",
    "# ==========================================\n",
    "with torch.no_grad():\n",
    "    outputs = model(input_tensor)\n",
    "    probs = torch.softmax(outputs, dim=1)\n",
    "    confidence, pred = torch.max(probs, 1)\n",
    "\n",
    "# ==========================================\n",
    "# RESULT\n",
    "# ==========================================\n",
    "label = class_names[pred.item()]\n",
    "score = confidence.item()\n",
    "\n",
    "print(f\"\\n🧠 Prediction: {label}\")\n",
    "print(f\"📊 Confidence: {score*100:.2f}%\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "17588856",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Folder 'data_gambar' berhasil dibuat!\n",
      "\n",
      "--- INSTRUKSI ---\n",
      "Tekan 'S' untuk menyimpan gambar (Crop)\n",
      "Tekan 'Q' untuk keluar\n",
      "Berhasil disimpan: data_gambar/gambar_20260204_142759.jpg\n"
     ]
    }
   ],
   "source": [
    "import cv2\n",
    "import os\n",
    "import time\n",
    "\n",
    "# --- KONFIGURASI ---\n",
    "NAMA_FOLDER = \"data_gambar\"  # Nama folder penyimpanan\n",
    "UKURAN_BOX = 300             # Ukuran kotak ROI (piksel)\n",
    "\n",
    "# 1. CEK & BUAT FOLDER JIKA BELUM ADA\n",
    "if not os.path.exists(NAMA_FOLDER):\n",
    "    os.makedirs(NAMA_FOLDER)\n",
    "    print(f\"Folder '{NAMA_FOLDER}' berhasil dibuat!\")\n",
    "else:\n",
    "    print(f\"Folder '{NAMA_FOLDER}' sudah ada. Gambar akan disimpan di sana.\")\n",
    "\n",
    "# 2. SETUP KAMERA\n",
    "cap = cv2.VideoCapture(0)\n",
    "\n",
    "print(\"\\n--- INSTRUKSI ---\")\n",
    "print(\"Tekan 'S' untuk menyimpan gambar (Crop)\")\n",
    "print(\"Tekan 'Q' untuk keluar\")\n",
    "\n",
    "while True:\n",
    "    ret, frame = cap.read()\n",
    "    if not ret:\n",
    "        print(\"Gagal membaca kamera\")\n",
    "        break\n",
    "\n",
    "    # Flip frame (efek cermin)\n",
    "    frame = cv2.flip(frame, 1)\n",
    "\n",
    "    # 3. HITUNG KOORDINAT ROI (TENGAH)\n",
    "    height, width, _ = frame.shape\n",
    "    x1 = (width - UKURAN_BOX) // 2\n",
    "    y1 = (height - UKURAN_BOX) // 2\n",
    "    x2 = x1 + UKURAN_BOX\n",
    "    y2 = y1 + UKURAN_BOX\n",
    "\n",
    "    # 4. GAMBAR KOTAK PANDUAN (HIJAU)\n",
    "    # Ini hanya visualisasi, tidak ikut tersimpan saat di-crop nanti\n",
    "    cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)\n",
    "    \n",
    "    # Tambahkan teks instruksi di layar\n",
    "    cv2.putText(frame, \"Tekan 'S' untuk Simpan\", (x1, y2 + 25), \n",
    "                cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 1)\n",
    "\n",
    "    # Tampilkan layar\n",
    "    cv2.imshow('Kamera Pengumpul Data', frame)\n",
    "\n",
    "    # 5. BACA TOMBOL KEYBOARD\n",
    "    key = cv2.waitKey(1) & 0xFF\n",
    "\n",
    "    # --- LOGIKA SIMPAN (CROP) ---\n",
    "    if key == ord('s') or key == ord('S'):\n",
    "        # Ambil potongan gambar asli (bersih tanpa garis kotak hijau)\n",
    "        # Kita ambil dari koordinat yang sudah dihitung di atas\n",
    "        roi_crop = frame[y1:y2, x1:x2]\n",
    "\n",
    "        # Buat nama file unik (berdasarkan waktu detik ini)\n",
    "        timestamp = time.strftime(\"%Y%m%d_%H%M%S\")\n",
    "        filename = f\"{NAMA_FOLDER}/gambar_{timestamp}.jpg\"\n",
    "\n",
    "        # Simpan ke folder\n",
    "        cv2.imwrite(filename, roi_crop)\n",
    "        print(f\"Berhasil disimpan: {filename}\")\n",
    "        \n",
    "        # Efek visual sesaat (layar berkedip putih sedikit tanda tersimpan) - Opsional\n",
    "        cv2.putText(frame, \"TERSIMPAN!\", (x1, y1-10), \n",
    "                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)\n",
    "        cv2.imshow('Kamera Pengumpul Data', frame)\n",
    "        cv2.waitKey(200) # Jeda sebentar biar tulisan terbaca\n",
    "\n",
    "    # Keluar program\n",
    "    elif key == ord('q'):\n",
    "        break\n",
    "\n",
    "cap.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "724ac841",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sedang memuat model... (tunggu sebentar)\n",
      "Model siap!\n"
     ]
    }
   ],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2, preprocess_input, decode_predictions\n",
    "from tensorflow.keras.preprocessing import image\n",
    "\n",
    "# 1. INISIALISASI MODEL\n",
    "print(\"Sedang memuat model... (tunggu sebentar)\")\n",
    "model = MobileNetV2(weights='imagenet', include_top=True)\n",
    "print(\"Model siap!\")\n",
    "\n",
    "# 2. SETUP KAMERA\n",
    "cap = cv2.VideoCapture(0) \n",
    "\n",
    "# Ukuran kotak ROI\n",
    "BOX_SIZE = 300 \n",
    "\n",
    "while True:\n",
    "    ret, frame = cap.read()\n",
    "    if not ret:\n",
    "        break\n",
    "\n",
    "    # Flip frame (efek cermin)\n",
    "    frame = cv2.flip(frame, 1)\n",
    "\n",
    "    # Ambil ukuran frame\n",
    "    height, width, _ = frame.shape\n",
    "    \n",
    "    # Hitung koordinat tengah untuk kotak hijau\n",
    "    x1 = (width - BOX_SIZE) // 2\n",
    "    y1 = (height - BOX_SIZE) // 2\n",
    "    x2 = x1 + BOX_SIZE\n",
    "    y2 = y1 + BOX_SIZE\n",
    "\n",
    "    # --- PROSES AI (Latar Belakang) ---\n",
    "    # Kita tetap perlu crop gambar untuk diserahkan ke AI,\n",
    "    # tapi tidak kita tempel/tampilkan ke layar utama.\n",
    "    roi_frame = frame[y1:y2, x1:x2]\n",
    "\n",
    "    if roi_frame.size != 0:\n",
    "        # Resize ke 224x224 (Wajib untuk MobileNet)\n",
    "        img_input = cv2.resize(roi_frame, (224, 224))\n",
    "        \n",
    "        # Konversi ke array & preprocess\n",
    "        img_array = image.img_to_array(img_input)\n",
    "        img_array = np.expand_dims(img_array, axis=0)\n",
    "        img_array = preprocess_input(img_array)\n",
    "\n",
    "        # Prediksi\n",
    "        preds = model.predict(img_array, verbose=0)\n",
    "        results = decode_predictions(preds, top=1)[0]\n",
    "        \n",
    "        # Ambil Label & Akurasi\n",
    "        label = results[0][1]\n",
    "        confidence = results[0][2] * 100\n",
    "\n",
    "        # Tampilkan Teks Hasil Prediksi di atas kotak\n",
    "        text_display = f\"{label}: {confidence:.1f}%\"\n",
    "        cv2.putText(frame, text_display, (x1, y1 - 10), \n",
    "                    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)\n",
    "\n",
    "    # --- VISUALISASI UTAMA ---\n",
    "    # Hanya gambar kotak hijau panduan\n",
    "    cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)\n",
    "    \n",
    "    # Tampilkan layar utama saja\n",
    "    cv2.imshow('MobileNetV2 Clean View', frame)\n",
    "\n",
    "    if cv2.waitKey(1) & 0xFF == ord('q'):\n",
    "        break\n",
    "\n",
    "cap.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "95017f76",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Memulai proses download ke folder 'dataset_botol_bewarna_bing'...\n",
      "\n",
      "--> Sedang mencari gambar: Super O2\n",
      "[%] Downloading Images to g:\\My Drive\\Smart-Bin\\dataset\\dataset_botol_bewarna_bing\\Super O2\n",
      "[!] Issue getting: https://img.21food.com/img/product/2012/10/25/indogalung-01510470.jpg\n",
      "[!] Error:: Remote end closed connection without response\n",
      "[Error]Invalid image, not saving https://lookaside.fbsbx.com/lookaside/crawler/media/?media_id=4116299515060023\n",
      "\n",
      "[!] Issue getting: https://lookaside.fbsbx.com/lookaside/crawler/media/?media_id=4116299515060023\n",
      "[!] Error:: Invalid image, not saving https://lookaside.fbsbx.com/lookaside/crawler/media/?media_id=4116299515060023\n",
      "\n",
      "[Error]Invalid image, not saving https://down-id.img.susercontent.com/file/039e5682e363425a1b87b8a725a4253e\n",
      "\n",
      "[!] Issue getting: https://down-id.img.susercontent.com/file/039e5682e363425a1b87b8a725a4253e\n",
      "[!] Error:: Invalid image, not saving https://down-id.img.susercontent.com/file/039e5682e363425a1b87b8a725a4253e\n",
      "\n",
      "[Error]Invalid image, not saving https://cf.shopee.co.id/file/734aeebfee8922e2c5ec88523cb5e6e5_tn\n",
      "\n",
      "[!] Issue getting: https://cf.shopee.co.id/file/734aeebfee8922e2c5ec88523cb5e6e5_tn\n",
      "[!] Error:: Invalid image, not saving https://cf.shopee.co.id/file/734aeebfee8922e2c5ec88523cb5e6e5_tn\n",
      "\n",
      "[Error]Invalid image, not saving https://down-id.img.susercontent.com/file/9bd8bd58dc85b83e4944981ce2f97e73\n",
      "\n",
      "[!] Issue getting: https://down-id.img.susercontent.com/file/9bd8bd58dc85b83e4944981ce2f97e73\n",
      "[!] Error:: Invalid image, not saving https://down-id.img.susercontent.com/file/9bd8bd58dc85b83e4944981ce2f97e73\n",
      "\n",
      "[!] Issue getting: https://ceklist.id/wp-content/uploads/2023/12/2858-super-o2-air-mineral-sportivo-600ml-1-370x370.jpg\n",
      "[!] Error:: <urlopen error [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond>\n",
      "[Error]Invalid image, not saving https://down-id.img.susercontent.com/file/sg-11134201-23010-r89m6d1to1lv22\n",
      "\n",
      "[!] Issue getting: https://down-id.img.susercontent.com/file/sg-11134201-23010-r89m6d1to1lv22\n",
      "[!] Error:: Invalid image, not saving https://down-id.img.susercontent.com/file/sg-11134201-23010-r89m6d1to1lv22\n",
      "\n",
      "[Error]Invalid image, not saving https://down-id.img.susercontent.com/file/734aeebfee8922e2c5ec88523cb5e6e5\n",
      "\n",
      "[!] Issue getting: https://down-id.img.susercontent.com/file/734aeebfee8922e2c5ec88523cb5e6e5\n",
      "[!] Error:: Invalid image, not saving https://down-id.img.susercontent.com/file/734aeebfee8922e2c5ec88523cb5e6e5\n",
      "\n",
      "[Error]Invalid image, not saving https://down-id.img.susercontent.com/file/0859ac0c9a420144d06c20bd2a16d154\n",
      "\n",
      "[!] Issue getting: https://down-id.img.susercontent.com/file/0859ac0c9a420144d06c20bd2a16d154\n",
      "[!] Error:: Invalid image, not saving https://down-id.img.susercontent.com/file/0859ac0c9a420144d06c20bd2a16d154\n",
      "\n",
      "\n",
      "\n",
      "[%] Done. Downloaded 50 images.\n",
      "    Selesai download Super O2!\n",
      "\n",
      "========================================\n",
      "SEMUA SELESAI!\n",
      "Cek folder 'dataset_botol_bewarna_bing' di komputer Anda.\n"
     ]
    }
   ],
   "source": [
    "from bing_image_downloader import downloader\n",
    "import os\n",
    "\n",
    "# --- KONFIGURASI ---\n",
    "# 1. Tentukan folder penyimpanan utama\n",
    "NAMA_FOLDER_UTAMA = \"dataset_botol_bewarna_bing\"\n",
    "\n",
    "# 2. Tentukan kata kunci benda yang mau dicari\n",
    "# Format: \"Kata Kunci\"\n",
    "daftar_pencarian = [\n",
    "    \"Super O2\"\n",
    "]\n",
    "\n",
    "# 3. Berapa banyak gambar per benda?\n",
    "JUMLAH_GAMBAR = 50  # Jangan terlalu banyak dulu untuk tes (max 100-200 aman)\n",
    "\n",
    "# --- MULAI DOWNLOAD ---\n",
    "print(f\"Memulai proses download ke folder '{NAMA_FOLDER_UTAMA}'...\\n\")\n",
    "\n",
    "for kata_kunci in daftar_pencarian:\n",
    "    print(f\"--> Sedang mencari gambar: {kata_kunci}\")\n",
    "    \n",
    "    downloader.download(\n",
    "        kata_kunci, \n",
    "        limit=JUMLAH_GAMBAR, \n",
    "        output_dir=NAMA_FOLDER_UTAMA, \n",
    "        adult_filter_off=True, # Matikan filter konten dewasa (aman untuk objek umum)\n",
    "        force_replace=False, \n",
    "        timeout=60, \n",
    "        verbose=False\n",
    "    )\n",
    "    print(f\"    Selesai download {kata_kunci}!\\n\")\n",
    "\n",
    "print(\"=\"*40)\n",
    "print(\"SEMUA SELESAI!\")\n",
    "print(f\"Cek folder '{NAMA_FOLDER_UTAMA}' di komputer Anda.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "643a9a12",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ditemukan 339 gambar asli.\n",
      "Memproses dengan Threading...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 27%|██▋       | 90/339 [04:21<04:26,  1.07s/it] c:\\Users\\MSI-PC\\miniconda3\\envs\\skripsi\\lib\\site-packages\\PIL\\Image.py:1034: UserWarning: Palette images with Transparency expressed in bytes should be converted to RGBA images\n",
      "  warnings.warn(\n",
      "100%|██████████| 339/339 [06:42<00:00,  1.19s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "SUKSES!\n",
      "Cek hasil di folder: dataset_augmented/botol_plastik_PET_bewarna\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import cv2\n",
    "import numpy as np\n",
    "from tensorflow.keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img\n",
    "# GANTI DARI ProcessPoolExecutor KE ThreadPoolExecutor\n",
    "from concurrent.futures import ThreadPoolExecutor \n",
    "from tqdm import tqdm \n",
    "\n",
    "# --- KONFIGURASI ---\n",
    "FOLDER_SUMBER = \"botol_plastik_PET_bewarna2\"\n",
    "FOLDER_HASIL  = \"dataset_augmented/botol_plastik_PET_bewarna\"\n",
    "JUMLAH_COPY   = 5\n",
    "NAMA_BASE     = \"botol_pet\"\n",
    "# Threading lebih ringan, kita bisa set angka aman misal 4 atau 8 worker\n",
    "MAX_WORKERS   = 4  \n",
    "\n",
    "if not os.path.exists(FOLDER_HASIL):\n",
    "    os.makedirs(FOLDER_HASIL)\n",
    "\n",
    "# Fungsi Worker \n",
    "def proses_gambar_spesifik(data):\n",
    "    filepath, index_awal = data\n",
    "    \n",
    "    try:\n",
    "        # Load gambar\n",
    "        img = load_img(filepath)\n",
    "        x = img_to_array(img)\n",
    "        x = x.reshape((1,) + x.shape)\n",
    "\n",
    "        # Definisikan ImageDataGenerator DI DALAM fungsi agar thread-safe\n",
    "        datagen = ImageDataGenerator(\n",
    "            rotation_range=30,\n",
    "            width_shift_range=0.2,\n",
    "            height_shift_range=0.2,\n",
    "            shear_range=0.2,\n",
    "            zoom_range=0.2,\n",
    "            horizontal_flip=True,\n",
    "            fill_mode='nearest'\n",
    "        )\n",
    "        \n",
    "        # Loop generate gambar\n",
    "        i = 0\n",
    "        for batch in datagen.flow(x, batch_size=1):\n",
    "            gambar_aug = batch[0].astype('uint8') \n",
    "            gambar_aug = cv2.cvtColor(gambar_aug, cv2.COLOR_RGB2BGR)\n",
    "            \n",
    "            nomor_urut = index_awal + i\n",
    "            nama_file_baru = f\"{NAMA_BASE}_{nomor_urut:05d}.jpg\"\n",
    "            path_simpan = os.path.join(FOLDER_HASIL, nama_file_baru)\n",
    "            \n",
    "            cv2.imwrite(path_simpan, gambar_aug)\n",
    "            \n",
    "            i += 1\n",
    "            if i >= JUMLAH_COPY:\n",
    "                break\n",
    "                \n",
    "    except Exception as e:\n",
    "        print(f\"Error pada {filepath}: {e}\")\n",
    "\n",
    "# --- MAIN PROGRAM ---\n",
    "if __name__ == '__main__':\n",
    "    semua_file = [f for f in os.listdir(FOLDER_SUMBER) \n",
    "                  if f.lower().endswith(('.png', '.jpg', '.jpeg'))]\n",
    "    semua_file.sort()\n",
    "    \n",
    "    print(f\"Ditemukan {len(semua_file)} gambar asli.\")\n",
    "    print(f\"Memproses dengan Threading...\")\n",
    "\n",
    "    tasks = []\n",
    "    counter = 1\n",
    "    \n",
    "    for nama_file in semua_file:\n",
    "        full_path = os.path.join(FOLDER_SUMBER, nama_file)\n",
    "        tasks.append((full_path, counter))\n",
    "        counter += JUMLAH_COPY\n",
    "\n",
    "    # GUNAKAN ThreadPoolExecutor\n",
    "    with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:\n",
    "        list(tqdm(executor.map(proses_gambar_spesifik, tasks), total=len(tasks)))\n",
    "\n",
    "    print(\"\\nSUKSES!\")\n",
    "    print(f\"Cek hasil di folder: {FOLDER_HASIL}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "f865eb1c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ditemukan 1695 file. Memulai rename...\n",
      "Selesai! Semua file sudah direname.\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "# --- KONFIGURASI ---\n",
    "FOLDER_TARGET = \"dataset_augmented/botol_plastik_PET_bewarna\"  # Ganti dengan nama foldermu\n",
    "NAMA_BARU     = \"botol_pet_bewarna\"                  # Awalan nama file baru\n",
    "\n",
    "# 1. Ambil semua file gambar\n",
    "files = [f for f in os.listdir(FOLDER_TARGET) \n",
    "         if f.lower().endswith(('.png', '.jpg', '.jpeg'))]\n",
    "\n",
    "# 2. Urutkan dulu (biar tidak acak)\n",
    "files.sort()\n",
    "\n",
    "print(f\"Ditemukan {len(files)} file. Memulai rename...\")\n",
    "\n",
    "# 3. Proses Rename\n",
    "for index, nama_file_lama in enumerate(files):\n",
    "    # Ambil ekstensi file asli (.jpg atau .png)\n",
    "    ekstensi = os.path.splitext(nama_file_lama)[1]\n",
    "    \n",
    "    # Buat nama baru dengan format 5 digit angka (00001)\n",
    "    # index + 1 agar mulai dari 1, bukan 0\n",
    "    nama_file_baru = f\"{NAMA_BARU}_{index + 1:05d}{ekstensi}\"\n",
    "    \n",
    "    # Gabungkan dengan path folder\n",
    "    path_lama = os.path.join(FOLDER_TARGET, nama_file_lama)\n",
    "    path_baru = os.path.join(FOLDER_TARGET, nama_file_baru)\n",
    "    \n",
    "    # Lakukan rename\n",
    "    try:\n",
    "        os.rename(path_lama, path_baru)\n",
    "    except OSError as e:\n",
    "        print(f\"Error pada {nama_file_lama}: {e}\")\n",
    "\n",
    "print(\"Selesai! Semua file sudah direname.\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "skripsi",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
