Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -6,77 +6,214 @@ from selenium.webdriver.chrome.options import Options
|
|
6 |
from selenium.webdriver.support.ui import WebDriverWait
|
7 |
from selenium.webdriver.support import expected_conditions as EC
|
8 |
from selenium.webdriver.common.by import By
|
|
|
9 |
import tempfile
|
10 |
import logging
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
# Konfigurasi logging dasar
|
13 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
14 |
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
-
|
27 |
-
|
28 |
|
29 |
-
|
30 |
-
|
|
|
|
|
31 |
"""
|
32 |
-
# Validasi URL sederhana
|
33 |
if not url.startswith(('http://', 'https://')):
|
34 |
logging.info(f"Menambahkan 'http://' ke URL: {url}")
|
35 |
url = 'http://' + url
|
36 |
|
37 |
-
#
|
38 |
try:
|
39 |
window_width = int(window_width)
|
40 |
window_height = int(window_height)
|
41 |
-
internal_delay = int(internal_delay)
|
42 |
if window_width <= 0 or window_height <= 0 or internal_delay < 0:
|
43 |
raise ValueError("Width, Height harus positif dan Delay tidak boleh negatif")
|
44 |
except (ValueError, TypeError) as e:
|
45 |
logging.error(f"Input tidak valid untuk ukuran/delay: {e}")
|
46 |
raise gr.Error(f"Input tidak valid: Lebar, Tinggi harus angka positif dan Delay tidak boleh negatif.")
|
47 |
|
48 |
-
logging.info(f"
|
|
|
49 |
|
50 |
-
|
51 |
-
chrome_options.add_argument('--headless')
|
52 |
-
chrome_options.add_argument('--disable-gpu')
|
53 |
-
chrome_options.add_argument('--no-sandbox')
|
54 |
-
# Mengatur ukuran jendela sesuai input pengguna
|
55 |
-
chrome_options.add_argument(f'--window-size={window_width},{window_height}')
|
56 |
-
chrome_options.add_argument('--disable-dev-shm-usage')
|
57 |
-
chrome_options.add_argument('--remote-debugging-port=9222') # Opsi ini mungkin tidak selalu diperlukan
|
58 |
-
|
59 |
-
driver = None
|
60 |
screenshot_path = None
|
61 |
|
62 |
try:
|
63 |
-
|
64 |
-
#
|
65 |
-
|
66 |
-
|
67 |
-
#
|
68 |
-
|
69 |
-
|
70 |
|
71 |
-
logging.info(f"
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
|
74 |
# 1. Tunggu hingga status dokumen 'complete'
|
75 |
logging.info("Menunggu document.readyState menjadi 'complete'...")
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
|
|
|
|
|
|
|
|
80 |
|
81 |
# 2. Tambahkan delay internal setelah 'complete'
|
82 |
if internal_delay > 0:
|
@@ -91,85 +228,75 @@ def capture_screenshot_gradio(url, window_width, window_height, internal_delay):
|
|
91 |
screenshot_path = tmp_file.name
|
92 |
|
93 |
logging.info(f"Mengambil screenshot ke: {screenshot_path}")
|
94 |
-
# Ambil screenshot dari seluruh halaman (mungkin perlu scroll jika konten panjang,
|
95 |
-
# tapi save_screenshot biasanya mengambil viewport saat ini dalam mode headless)
|
96 |
driver.save_screenshot(screenshot_path)
|
97 |
logging.info("Screenshot berhasil diambil.")
|
98 |
|
99 |
return screenshot_path
|
100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
except Exception as e:
|
102 |
-
logging.error(f"Terjadi kesalahan saat memproses URL {url}: {e}", exc_info=True)
|
|
|
103 |
if screenshot_path and os.path.exists(screenshot_path):
|
104 |
try:
|
105 |
os.remove(screenshot_path)
|
106 |
logging.info(f"Membersihkan file sementara yang gagal: {screenshot_path}")
|
107 |
except OSError as remove_err:
|
108 |
logging.error(f"Gagal menghapus file sementara {screenshot_path}: {remove_err}")
|
|
|
109 |
raise gr.Error(f"Gagal mengambil screenshot: {e}")
|
110 |
|
111 |
-
finally:
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
|
117 |
-
# --- Membuat Antarmuka Gradio ---
|
118 |
|
119 |
# 1. Definisikan Komponen Input
|
120 |
url_input = gr.Textbox(
|
121 |
label="Masukkan URL Website",
|
122 |
placeholder="contoh: https://www.google.com atau example.com"
|
123 |
)
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
value=1920, # Nilai default
|
128 |
-
minimum=300, # Lebar minimum yang masuk akal
|
129 |
-
step=10, # Langkah penambahan/pengurangan
|
130 |
-
info="Lebar viewport browser saat mengambil screenshot."
|
131 |
-
)
|
132 |
-
|
133 |
-
height_input = gr.Number(
|
134 |
-
label="Tinggi Jendela (px)",
|
135 |
-
value=1080, # Nilai default
|
136 |
-
minimum=200, # Tinggi minimum yang masuk akal
|
137 |
-
step=10, # Langkah penambahan/pengurangan
|
138 |
-
info="Tinggi viewport browser. Untuk halaman panjang, ini mungkin tidak menangkap seluruhnya."
|
139 |
-
)
|
140 |
-
|
141 |
-
delay_input = gr.Number(
|
142 |
-
label="Delay Tambahan (detik)",
|
143 |
-
value=5, # Nilai default
|
144 |
-
minimum=0, # Boleh 0 detik
|
145 |
-
step=1, # Langkah penambahan/pengurangan
|
146 |
-
info="Waktu tunggu ekstra setelah halaman 'lengkap' untuk membiarkan konten dinamis (mis. JavaScript) selesai dimuat."
|
147 |
-
)
|
148 |
|
149 |
# 2. Definisikan Komponen Output
|
150 |
-
output_image = gr.Image(
|
151 |
-
type="filepath", # Mengharapkan path file sebagai output
|
152 |
-
label="Hasil Screenshot"
|
153 |
-
)
|
154 |
|
155 |
# 3. Membuat instance Interface Gradio
|
156 |
iface = gr.Interface(
|
157 |
-
fn=capture_screenshot_gradio,
|
158 |
-
inputs=[url_input, width_input, height_input, delay_input],
|
159 |
-
outputs=output_image,
|
160 |
-
title="Pengambil Screenshot Website
|
161 |
-
description="Masukkan URL, atur ukuran jendela dan delay
|
162 |
allow_flagging='never',
|
163 |
examples=[
|
164 |
["https://gradio.app", 1280, 720, 3],
|
165 |
["https://github.com", 1920, 1080, 5],
|
166 |
-
["https://www.google.com/maps", 1024, 768, 8]
|
167 |
]
|
168 |
)
|
169 |
|
170 |
# Menjalankan aplikasi Gradio
|
171 |
if __name__ == "__main__":
|
172 |
-
print("Menjalankan aplikasi Gradio...")
|
|
|
173 |
print("Pastikan Google Chrome dan ChromeDriver yang sesuai sudah terinstall.")
|
174 |
-
print("Anda mungkin perlu menginstal: pip install selenium webdriver-manager gradio")
|
175 |
-
iface.launch()
|
|
|
|
|
|
6 |
from selenium.webdriver.support.ui import WebDriverWait
|
7 |
from selenium.webdriver.support import expected_conditions as EC
|
8 |
from selenium.webdriver.common.by import By
|
9 |
+
from selenium.common.exceptions import WebDriverException # Import specific exception
|
10 |
import tempfile
|
11 |
import logging
|
12 |
+
import atexit # Untuk cleanup saat skrip exit
|
13 |
+
from threading import Lock # Untuk thread safety jika Gradio menangani request secara konkuren
|
14 |
+
|
15 |
+
# --- Konfigurasi ---
|
16 |
+
CHROME_INSTANCE_TIMEOUT = 600 # Detik (10 menit)
|
17 |
|
18 |
# Konfigurasi logging dasar
|
19 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
20 |
|
21 |
+
class ChromeDriverManager:
|
22 |
+
"""Mengelola satu instance WebDriver Chrome yang persisten dengan timeout."""
|
23 |
+
def __init__(self, timeout_seconds):
|
24 |
+
self.driver = None
|
25 |
+
self.last_used_time = None
|
26 |
+
self.timeout_seconds = timeout_seconds
|
27 |
+
self.lock = Lock() # Lock untuk mencegah race condition saat mengakses/membuat driver
|
28 |
+
self.options = self._configure_options()
|
29 |
+
logging.info(f"ChromeDriverManager diinisialisasi dengan timeout {timeout_seconds} detik.")
|
30 |
+
# Daftarkan fungsi cleanup untuk dijalankan saat skrip Python keluar
|
31 |
+
atexit.register(self.quit_driver)
|
32 |
+
|
33 |
+
def _configure_options(self):
|
34 |
+
"""Konfigurasi opsi Chrome (tanpa ukuran jendela awal)."""
|
35 |
+
chrome_options = Options()
|
36 |
+
chrome_options.add_argument('--headless')
|
37 |
+
chrome_options.add_argument('--disable-gpu')
|
38 |
+
chrome_options.add_argument('--no-sandbox')
|
39 |
+
chrome_options.add_argument('--disable-dev-shm-usage')
|
40 |
+
chrome_options.add_argument('--remote-debugging-port=9222') # Opsional
|
41 |
+
# Jangan set window size di sini, akan diatur per permintaan
|
42 |
+
# chrome_options.add_argument('--window-size=1920,1080')
|
43 |
+
return chrome_options
|
44 |
+
|
45 |
+
def _initialize_driver(self):
|
46 |
+
"""Membuat instance WebDriver baru."""
|
47 |
+
logging.info("Menginisialisasi instance WebDriver Chrome baru...")
|
48 |
+
try:
|
49 |
+
# Pertimbangkan menggunakan webdriver-manager jika perlu
|
50 |
+
# from selenium.webdriver.chrome.service import Service as ChromeService
|
51 |
+
# from webdriver_manager.chrome import ChromeDriverManager
|
52 |
+
# service = ChromeService(executable_path=ChromeDriverManager().install())
|
53 |
+
# driver = webdriver.Chrome(service=service, options=self.options)
|
54 |
+
driver = webdriver.Chrome(options=self.options)
|
55 |
+
self.last_used_time = time.time()
|
56 |
+
logging.info("Instance WebDriver baru berhasil dibuat.")
|
57 |
+
return driver
|
58 |
+
except Exception as e:
|
59 |
+
logging.error(f"Gagal menginisialisasi WebDriver: {e}", exc_info=True)
|
60 |
+
# Set driver ke None jika gagal agar dicoba lagi nanti
|
61 |
+
self.driver = None
|
62 |
+
self.last_used_time = None
|
63 |
+
return None
|
64 |
+
|
65 |
+
def _is_driver_alive(self):
|
66 |
+
"""Memeriksa apakah driver masih responsif."""
|
67 |
+
if self.driver is None:
|
68 |
+
return False
|
69 |
+
try:
|
70 |
+
# Perintah ringan untuk memeriksa koneksi, misal mendapatkan URL saat ini
|
71 |
+
_ = self.driver.current_url
|
72 |
+
return True
|
73 |
+
except WebDriverException as e:
|
74 |
+
# Tangkap error spesifik yang mengindikasikan driver mati/tidak terhubung
|
75 |
+
logging.warning(f"Driver tampaknya tidak responsif: {e}")
|
76 |
+
return False
|
77 |
+
except Exception as e:
|
78 |
+
# Tangkap error lain yang mungkin terjadi
|
79 |
+
logging.warning(f"Error tidak terduga saat memeriksa status driver: {e}")
|
80 |
+
return False
|
81 |
+
|
82 |
+
|
83 |
+
def get_driver(self, requested_width, requested_height):
|
84 |
+
"""Mendapatkan instance driver yang ada atau membuat yang baru jika perlu."""
|
85 |
+
with self.lock: # Pastikan operasi ini thread-safe
|
86 |
+
current_time = time.time()
|
87 |
+
needs_new_driver = False
|
88 |
+
|
89 |
+
if self.driver is None:
|
90 |
+
logging.info("Tidak ada driver aktif, membuat yang baru.")
|
91 |
+
needs_new_driver = True
|
92 |
+
elif not self._is_driver_alive():
|
93 |
+
logging.warning("Driver yang ada tidak responsif, membuat yang baru.")
|
94 |
+
self.quit_driver(acquire_lock=False) # Tutup driver lama (lock sudah dipegang)
|
95 |
+
needs_new_driver = True
|
96 |
+
elif self.last_used_time and (current_time - self.last_used_time > self.timeout_seconds):
|
97 |
+
logging.info(f"Driver melewati batas waktu idle ({self.timeout_seconds}s). Membuat yang baru.")
|
98 |
+
self.quit_driver(acquire_lock=False) # Tutup driver lama (lock sudah dipegang)
|
99 |
+
needs_new_driver = True
|
100 |
+
|
101 |
+
if needs_new_driver:
|
102 |
+
self.driver = self._initialize_driver()
|
103 |
+
# Jika inisialisasi gagal, driver akan None, tangani di luar
|
104 |
+
if self.driver is None:
|
105 |
+
logging.error("Gagal membuat instance driver baru setelah mencoba.")
|
106 |
+
return None # Kembalikan None untuk menandakan kegagalan
|
107 |
+
|
108 |
+
# Jika driver berhasil didapatkan (baru atau lama)
|
109 |
+
if self.driver:
|
110 |
+
try:
|
111 |
+
# Atur ukuran jendela sesuai permintaan SETIAP kali driver digunakan
|
112 |
+
logging.info(f"Mengatur ukuran jendela driver ke {requested_width}x{requested_height}")
|
113 |
+
self.driver.set_window_size(requested_width, requested_height)
|
114 |
+
# Update waktu penggunaan terakhir HANYA jika berhasil mendapatkan/menggunakan driver
|
115 |
+
self.last_used_time = current_time
|
116 |
+
logging.info("Menggunakan instance driver yang ada/baru.")
|
117 |
+
except WebDriverException as e:
|
118 |
+
logging.error(f"Gagal mengatur ukuran jendela atau driver bermasalah: {e}. Menutup driver.", exc_info=True)
|
119 |
+
self.quit_driver(acquire_lock=False) # Tutup driver bermasalah
|
120 |
+
self.driver = None # Pastikan driver di-reset
|
121 |
+
return None # Kembalikan None untuk menandakan kegagalan
|
122 |
+
else:
|
123 |
+
# Kasus di mana _initialize_driver gagal dan self.driver masih None
|
124 |
+
logging.warning("Tidak dapat menyediakan instance driver.")
|
125 |
+
|
126 |
+
|
127 |
+
return self.driver # Kembalikan driver (bisa None jika gagal total)
|
128 |
+
|
129 |
|
130 |
+
def quit_driver(self, acquire_lock=True):
|
131 |
+
"""Menutup instance WebDriver jika ada."""
|
132 |
+
# Fungsi ini bisa dipanggil dari atexit atau saat timeout/error,
|
133 |
+
# jadi perlu penanganan lock yang fleksibel
|
134 |
+
if acquire_lock:
|
135 |
+
acquired = self.lock.acquire(timeout=5) # Coba kunci, timeout jika macet
|
136 |
+
if not acquired:
|
137 |
+
logging.error("Gagal mendapatkan lock untuk quit_driver. Melewati penutupan.")
|
138 |
+
return
|
139 |
+
try:
|
140 |
+
if self.driver:
|
141 |
+
logging.info("Menutup instance WebDriver...")
|
142 |
+
try:
|
143 |
+
self.driver.quit()
|
144 |
+
logging.info("WebDriver berhasil ditutup.")
|
145 |
+
except Exception as e:
|
146 |
+
logging.error(f"Error saat menutup WebDriver: {e}", exc_info=True)
|
147 |
+
finally:
|
148 |
+
# Selalu set ke None meskipun quit gagal
|
149 |
+
self.driver = None
|
150 |
+
self.last_used_time = None
|
151 |
+
else:
|
152 |
+
logging.debug("Tidak ada instance WebDriver aktif untuk ditutup.") # Log level debug
|
153 |
+
finally:
|
154 |
+
if acquire_lock and acquired: # Hanya release jika lock didapatkan di sini
|
155 |
+
self.lock.release()
|
156 |
|
157 |
+
# --- Buat instance manager global ---
|
158 |
+
chrome_manager = ChromeDriverManager(timeout_seconds=CHROME_INSTANCE_TIMEOUT)
|
159 |
|
160 |
+
# Function to capture a screenshot using the managed driver
|
161 |
+
def capture_screenshot_gradio(url, window_width, window_height, internal_delay):
|
162 |
+
"""
|
163 |
+
Mengambil screenshot halaman web menggunakan instance Chrome yang dikelola.
|
164 |
"""
|
165 |
+
# Validasi URL sederhana
|
166 |
if not url.startswith(('http://', 'https://')):
|
167 |
logging.info(f"Menambahkan 'http://' ke URL: {url}")
|
168 |
url = 'http://' + url
|
169 |
|
170 |
+
# Validasi input ukuran dan delay
|
171 |
try:
|
172 |
window_width = int(window_width)
|
173 |
window_height = int(window_height)
|
174 |
+
internal_delay = int(internal_delay)
|
175 |
if window_width <= 0 or window_height <= 0 or internal_delay < 0:
|
176 |
raise ValueError("Width, Height harus positif dan Delay tidak boleh negatif")
|
177 |
except (ValueError, TypeError) as e:
|
178 |
logging.error(f"Input tidak valid untuk ukuran/delay: {e}")
|
179 |
raise gr.Error(f"Input tidak valid: Lebar, Tinggi harus angka positif dan Delay tidak boleh negatif.")
|
180 |
|
181 |
+
logging.info(f"Permintaan screenshot untuk URL: {url}")
|
182 |
+
logging.info(f"Opsi: Lebar={window_width}, Tinggi={window_height}, Delay={internal_delay} detik")
|
183 |
|
184 |
+
driver = None # Inisialisasi driver di scope ini
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
screenshot_path = None
|
186 |
|
187 |
try:
|
188 |
+
# Dapatkan driver dari manager (akan membuat baru atau menggunakan yang ada)
|
189 |
+
# Ukuran jendela akan diatur di dalam get_driver
|
190 |
+
driver = chrome_manager.get_driver(window_width, window_height)
|
191 |
+
|
192 |
+
# Jika get_driver gagal mengembalikan driver
|
193 |
+
if driver is None:
|
194 |
+
raise gr.Error("Gagal mendapatkan atau menginisialisasi instance WebDriver Chrome.")
|
195 |
|
196 |
+
logging.info(f"Navigasi ke URL: {url}")
|
197 |
+
# Set page load timeout untuk mencegah hang jika halaman sangat lambat
|
198 |
+
driver.set_page_load_timeout(60) # Timeout 60 detik untuk memuat halaman
|
199 |
+
try:
|
200 |
+
driver.get(url)
|
201 |
+
except Exception as page_load_error:
|
202 |
+
logging.error(f"Timeout atau error saat memuat URL {url}: {page_load_error}")
|
203 |
+
# Pertimbangkan apakah driver harus ditutup jika hanya load gagal
|
204 |
+
# chrome_manager.quit_driver() # Opsional: tutup driver jika load gagal total
|
205 |
+
raise gr.Error(f"Gagal memuat URL {url}: {page_load_error}")
|
206 |
|
207 |
# 1. Tunggu hingga status dokumen 'complete'
|
208 |
logging.info("Menunggu document.readyState menjadi 'complete'...")
|
209 |
+
try:
|
210 |
+
WebDriverWait(driver, 45).until( # Timeout sedikit lebih lama
|
211 |
+
lambda d: d.execute_script('return document.readyState') == 'complete'
|
212 |
+
)
|
213 |
+
logging.info("document.readyState sudah 'complete'.")
|
214 |
+
except Exception as wait_error:
|
215 |
+
logging.warning(f"Timeout atau error saat menunggu readyState complete untuk {url}: {wait_error}")
|
216 |
+
# Lanjutkan saja, mungkin halaman masih bisa di-screenshot sebagian
|
217 |
|
218 |
# 2. Tambahkan delay internal setelah 'complete'
|
219 |
if internal_delay > 0:
|
|
|
228 |
screenshot_path = tmp_file.name
|
229 |
|
230 |
logging.info(f"Mengambil screenshot ke: {screenshot_path}")
|
|
|
|
|
231 |
driver.save_screenshot(screenshot_path)
|
232 |
logging.info("Screenshot berhasil diambil.")
|
233 |
|
234 |
return screenshot_path
|
235 |
|
236 |
+
except WebDriverException as wd_error:
|
237 |
+
# Jika terjadi error spesifik WebDriver, kemungkinan besar instance-nya bermasalah
|
238 |
+
logging.error(f"WebDriverException terjadi saat memproses {url}: {wd_error}", exc_info=True)
|
239 |
+
logging.warning("Menutup instance driver karena WebDriverException.")
|
240 |
+
chrome_manager.quit_driver() # Paksa tutup driver yang bermasalah
|
241 |
+
# Hapus file sementara jika ada
|
242 |
+
if screenshot_path and os.path.exists(screenshot_path):
|
243 |
+
try: os.remove(screenshot_path)
|
244 |
+
except OSError: pass
|
245 |
+
raise gr.Error(f"Terjadi masalah dengan browser: {wd_error}")
|
246 |
+
|
247 |
except Exception as e:
|
248 |
+
logging.error(f"Terjadi kesalahan umum saat memproses URL {url}: {e}", exc_info=True)
|
249 |
+
# Hapus file sementara jika ada
|
250 |
if screenshot_path and os.path.exists(screenshot_path):
|
251 |
try:
|
252 |
os.remove(screenshot_path)
|
253 |
logging.info(f"Membersihkan file sementara yang gagal: {screenshot_path}")
|
254 |
except OSError as remove_err:
|
255 |
logging.error(f"Gagal menghapus file sementara {screenshot_path}: {remove_err}")
|
256 |
+
# Tidak perlu menutup driver di sini kecuali errornya WebDriverException (sudah ditangani)
|
257 |
raise gr.Error(f"Gagal mengambil screenshot: {e}")
|
258 |
|
259 |
+
# finally:
|
260 |
+
# TIDAK ADA driver.quit() di sini lagi. Dikelola oleh ChromeDriverManager.
|
261 |
+
# Cukup pastikan instance manager dibuat di luar dan atexit terdaftar.
|
262 |
+
# logging.debug("Blok finally capture_screenshot_gradio selesai.") # Untuk debugging jika perlu
|
263 |
+
|
264 |
|
265 |
+
# --- Membuat Antarmuka Gradio (Sama seperti sebelumnya) ---
|
266 |
|
267 |
# 1. Definisikan Komponen Input
|
268 |
url_input = gr.Textbox(
|
269 |
label="Masukkan URL Website",
|
270 |
placeholder="contoh: https://www.google.com atau example.com"
|
271 |
)
|
272 |
+
width_input = gr.Number(label="Lebar Jendela (px)", value=1920, minimum=300, step=10, info="Lebar viewport browser.")
|
273 |
+
height_input = gr.Number(label="Tinggi Jendela (px)", value=1080, minimum=200, step=10, info="Tinggi viewport browser.")
|
274 |
+
delay_input = gr.Number(label="Delay Tambahan (detik)", value=5, minimum=0, step=1, info="Waktu tunggu ekstra setelah halaman 'lengkap'.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
|
276 |
# 2. Definisikan Komponen Output
|
277 |
+
output_image = gr.Image(type="filepath", label="Hasil Screenshot")
|
|
|
|
|
|
|
278 |
|
279 |
# 3. Membuat instance Interface Gradio
|
280 |
iface = gr.Interface(
|
281 |
+
fn=capture_screenshot_gradio,
|
282 |
+
inputs=[url_input, width_input, height_input, delay_input],
|
283 |
+
outputs=output_image,
|
284 |
+
title="Pengambil Screenshot Website Cepat (Chrome Persisten)",
|
285 |
+
description="Masukkan URL, atur ukuran jendela dan delay. Instance Chrome akan berjalan hingga 10 menit untuk mempercepat respons.",
|
286 |
allow_flagging='never',
|
287 |
examples=[
|
288 |
["https://gradio.app", 1280, 720, 3],
|
289 |
["https://github.com", 1920, 1080, 5],
|
290 |
+
["https://www.google.com/maps", 1024, 768, 8]
|
291 |
]
|
292 |
)
|
293 |
|
294 |
# Menjalankan aplikasi Gradio
|
295 |
if __name__ == "__main__":
|
296 |
+
print("Menjalankan aplikasi Gradio dengan instance Chrome persisten...")
|
297 |
+
print(f"Instance Chrome akan ditutup otomatis setelah {CHROME_INSTANCE_TIMEOUT} detik tidak aktif atau saat aplikasi berhenti.")
|
298 |
print("Pastikan Google Chrome dan ChromeDriver yang sesuai sudah terinstall.")
|
299 |
+
print("Anda mungkin perlu menginstal: pip install selenium webdriver-manager gradio") # webdriver-manager jika digunakan
|
300 |
+
iface.launch()
|
301 |
+
print("Aplikasi Gradio ditutup.")
|
302 |
+
# atexit akan memanggil chrome_manager.quit_driver() secara otomatis di sini
|