Spaces:
Sleeping
Sleeping
File size: 20,693 Bytes
b14496c c93a052 d7c999c 365e16f 93fdff4 6d59268 cf0a188 83a70ce 36e0c32 3577a12 ab4cd3f d9b382b b14496c 5dae4c9 b14496c d9b382b 5dae4c9 b14496c 3577a12 1afb483 3577a12 1afb483 3577a12 ab4cd3f b14496c f9f33fc 77d971f b14496c 1afb483 e424366 1afb483 5fce78b 1afb483 5fce78b 1afb483 5fce78b 1afb483 5fce78b 8dea28a 5fce78b 8dea28a 1afb483 5fce78b 1afb483 8dea28a 1afb483 5fce78b 1afb483 5fce78b 1afb483 5fce78b 1afb483 9947b29 5fce78b 1afb483 5fce78b 1afb483 5fce78b 1afb483 5fce78b 8dea28a 1afb483 5fce78b 1afb483 36e0c32 2c980f5 1afb483 2c980f5 1afb483 36e0c32 1afb483 36e0c32 1afb483 2c980f5 36e0c32 2c980f5 36e0c32 b16468e 1afb483 8a7e328 5fc32ab fac6fbc 9df4a7b 1afb483 8a7e328 2637922 1afb483 b14496c d9b382b f9f33fc 36e0c32 91919c3 36e0c32 cf0a188 91919c3 36e0c32 8664d07 cf0a188 c036f4a 36e0c32 04e5c11 2c980f5 04e5c11 36e0c32 a6a52ce 36e0c32 77d971f cf0a188 77d971f cf0a188 83a70ce cf0a188 2637922 cf0a188 d9b382b cf0a188 caf5e05 83a70ce cf0a188 83e3607 cf0a188 d9b382b cf0a188 b14496c 9ce4500 d9b382b 9ce4500 cf0a188 d9b382b 9ce4500 cf0a188 8664d07 d9b382b f9f33fc b14496c d9b382b b14496c f7daf2e f720f34 f7daf2e f720f34 b14496c f7daf2e d9b382b 3577a12 cf0a188 6d59268 d9b382b c0dfddb 143d251 8a7e328 c0dfddb 143d251 c0dfddb d9b382b 54e78d8 b14496c f7daf2e b14496c 99a3af4 2637922 fce9cbb bb438b6 f9f33fc 5dae4c9 b5581dc 5dae4c9 1afb483 6e7765f 5dae4c9 d9b382b ac0c572 d9b382b 54e78d8 2c980f5 99a3af4 529a353 99a3af4 36e0c32 99a3af4 8a7e328 99a3af4 529a353 54e78d8 dc5888d a6a52ce d9b382b f9f33fc 54e78d8 d9b382b b14496c 5dae4c9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
import os
from pdf2image import convert_from_path
from datetime import date
from PIL import Image
import gradio as gr
from google import genai
import zipfile
import tempfile
os.system("apt-get install poppler-utils")
import datetime
from docx import Document
import time
import random
from google.genai.types import GenerateContentConfig
import json
from PIL import ImageEnhance, ImageFilter
def extract_zip_and_collect_files(zip_file_path):
"""
Extract zip file to a temp directory and return list of pdf/image file paths inside.
"""
temp_dir = tempfile.mkdtemp()
with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
zip_ref.extractall(temp_dir)
# Collect all pdf and image files in extracted folder recursively
collected_files = []
for root, _, files in os.walk(temp_dir):
for f in files:
if f.lower().endswith(('.pdf', '.jpg', '.jpeg', '.png')):
collected_files.append(os.path.join(root, f))
return collected_files
# Function to process a list of PDF files and convert them to images
def process_pdfs(pdf_files, dpi):
"""
Process a list of PDF files, convert each to images, and return all images.
"""
all_images = []
for pdf_file in pdf_files:
if not os.path.isfile(pdf_file):
raise ValueError(f"File {pdf_file} does not exist.")
images = convert_from_path(pdf_file, dpi=dpi)
all_images.extend(images)
return all_images
def preprocess_image(img):
# Enhance contrast and sharpness
img = ImageEnhance.Contrast(img).enhance(1.75)
img = ImageEnhance.Sharpness(img).enhance(2.25)
# Resize for optimal resolution (maintain aspect ratio)
max_size = (1600, 1600)
img.thumbnail(max_size, Image.LANCZOS)
return img
# Function to analyze the extracted image using Google GenAI
def gemini_analysis(images, tanggal_berangkat, tanggal_pulang, tanggal_biometrik):
client = genai.Client(api_key='AIzaSyBpviFHkaEF-GAjMMl28dIS1poikhBqq_w')
# Define your prompt
prompt = '''Anda adalah petugas pemeriksaan kelengkapan dan kesesuaian dokumen untuk pengajuan Visa. Berikut ini adalah alur kerja anda:
1. Ekstrak metadata dari setiap file/gambar yang diberikan berdasarkan data yang dibutuhkan masing-masing dokumen.
2. Dari setiap data yang anda dapat, bandingkan dengan persyaratan per dokumen dan periksa konsistensi data kunci antar dokumen.
3. Berikan analisis per dokumen termasuk kelengkapan dan konsistensi data antar dokumen.
4. Output pemrosesan berupa JSON dengan template di bawah.
5. Data boleh berupa fotokopi (bukan gambar asli).
---
List Dokumen wajib diserahkan seluruh peserta:
KTP:
Wajib ada untuk setiap peserta. Nama harus sama dengan paspor rekening koran, surat referensi bank, bukti kelahiran dan tertera di Kartu Keluarga. Jika ada perbedaan nama, wajib ada surat keterangan beda nama.
Paspor
Wajib ada untuk setiap peserta. Nama harus sama dengan KTP, rekening koran, surat referensi bank, bukti kelahiran dan tertera di kartu keluarga. Jika ada perbedaan nama, wajib ada surat keterangan beda nama.
Menampilkan nama, nomor paspor dan detail identitas lainnya, serta masa aktif minimal 6 bulan setelah tanggal pulang, dan sudah ada tanda tangan.
Kartu Keluarga (KK)
Wajib ada untuk setiap peserta. Nama harus sama dengan KTP, paspor, bukti kelahiran & dokumen lain. Jika ada perbedaan nama, wajib ada surat keterangan beda nama.
Kartu keluarga harus sudah terdapat barcode, dan terbit minimal tahun 2019.
REKENING KORAN PESERTA
Wajib ada untuk setiap peserta. Nama nasabah (pemilik) harus sama dengan KTP, paspor & dokumen lain. Jika ada perbedaan nama, wajib ada surat keterangan beda nama.
Sudah tertera cap dan logo bank, nama pserta dan nomor rekening, saldo minimal Rp 40 juta/orang.
Berikan peringatan di bagian analisis jika ada transaksi mencurigakan dengan nominal yang tidak wajar.
Wajib terupdate hingga 7 hari sebelum tanggal biometrik.
SURAT REFERENSI BANK
Wajib ada untuk setiap peserta. Nama nasabah (pemilik) harus sama dengan KTP, paspor dan dokumen lain.
Harus berupa surat resmi dari bank yang menjelaskan bahwa nama peserta tersebut adalah nasabah bank tersebut. Bukan rekening koran dan tidak bisa digantikan dengan rekening koran
PAS FOTO
Background putih, wajah terlihat 80%, alis terlihat, tidak berbayang. Pastikan anda tidak mendeteksi tempat meletakan foto sebagai Background.
Pasfoto bisa saja difoto dengan diletakkan di atas meja atau objek berwarnai lainnya.
BUKTI KELAHIRAN
Wajib ada untuk setiap peserta. Nama yang tertulis harus sama dengan KTP, PASPOR dan terdapat di Kartu Keluarga (KK).
Dapat digantikan dengan ijazah. Nama yang tertulis harus sama dengan KTP, PASPOR dan terdapat di Kartu Keluarga (KK).
---
Dokumen lain yang sifatnya kondisional
BUKTI NIKAH/CERAI
Jika status perkawinan di KTP tertulis "Kawin" maka wajib ada Bukti Nikah (misal buku nikah/akta nikah).
Jika status perkawinan di KTP tertulis "Cerai" maka wajib ada bukti cerai yang menyatakan cerai mati atau cerai hidup.
Jika status perkawinan di KTP tertulis "Belum Kawin" maka tidak perlu.
GUARANTEE LETTER
Merupakan surat yang berisi jaminan terkait perjalanan peserta antara lain tujuan perjalanan, tanggal berangkat, tanggal pulang, penanggung biaya, dan jaminan akan kembali ke Indonesia.
Guarantee Letter bisa berasal dari institusi pendidikan seperti sekolah/universitas, tempat peserta bekerja atau dari keluarga seperti suami atau orang tua.
Surat harus mencantumkan nama peserta yang sama dengan KTP, dalam bahasa Inggris, berisi tujuan, tanggal trip, siapa penanggung biaya, dan jaminan kembali ke Indonesia.
SURAT SPONSOR
Berbeda dengan Guarantee Letter. Merupakan surat yang menyatakan bahwa peserta disponsori oleh pihak ketiga khususnya sebagai penanggung biaya. Laporkan data pemberi sponsor.
Bisa berasal dari perusahaan tempat peserta bekerja atau sekolah/universitas. Jika surat sponsor dari sekolah/universitas,maka wajib ada KARTU PELAJAR/MAHASISWA
Surat harus mencantumkan nama peserta yang sama dengan KTP, dalam bahasa Inggris, berisi tujuan, tanggal trip, identitas penanggung biaya, dan jaminan kembali ke Indonesia.
SLIP GAJI
Jika peserta menyertakan SURAT SPONSOR / GUARANTEE LETTER dari perusahaan tempat peserta bekerja, peserta WAJIB menyertakan SLIP GAJI 3 BULAN terakhir sebelum tanggal berangkat.
Berupa pembayaran GAJI dari tempat kerja ke peserta. Pastikan NAMA PERUSAHAAN PEMBERI GAJI sama dengan Guarantee Letter dan/atau Surat Sponsor.
NIB/SIUP
Jika peserta merupakan pemilik usaha, wajib tertera nama pemilik usaha, nama usaha, alamat usaha, dan nomor NIB. Nama pemilik usaha harus sama dengan KTP, paspor dan dokumen lain.
KONTRAK FREELANCE
Jika peserta merupakan freelancer, maka wajib mencantumkan surat yang menunjukan bukti kontrak freelance. Harus tertera nama peserta yang sama dengan KTP dan dilengkapi bukti transaksi.
BUKTI TRANSAKSI
Jika peserta merupakan pekerja freelance, selain wajib menyertakan bukti KONTRAK FREELANCE, wajib menyertakan BUKTI TRANSAKSI. Bisa berupa invoice project atau dokumen terkait.
SURAT PENSIUN
Merupakan surat yang menyatakan sudah pensiun. Jika peserta menyertakan surat pensiun, wajib ada Guarantee Letter dari Keluarga.
maka wajib menyertakan surat pensiun yang berisi nama peserta, dan menyatakan sudah pensiun.
REKENING KORAN SPONSOR
Hanya wajib jika peserta disponsori dengan menyertakan SURAT SPONSOR.
Pastikan nama di rekening koran sponsor sama dengan pemberi sponsor yang tertulis di surat sponsor sebagai pemberi sponsor.
Wajib sudah tertera cap & logo bank, nama & nomor rekening, saldo minimal Rp 40 juta, wajib terupdate hingga. 7 hari sebelum tanggal
SURAT REFERENSI BANK SPONSOR
Hanya wajib jika peserta disponsori dengan menyertakan SURAT SPONSOR dan rekening koran dari pemberi sponsor.
Surat Bank Reference/Referensi Bank, merupakan surat yang menyatakan orang tersebut selaku pemberi sponsor merupakan nasabah bank terkait.
---
TEMPLATE OUTPUT JAWABAN DALAM FORMAT JSON:
{
"analysis":
{
"nama_dokumen_1": {"status": "VALID / INVALID / Tidak Perlu",
"description": "penjelasan detail",
"nama_dokumen_2": {"status": "VALID / INVALID / Tidak Perlu",
"description": "penjelasan detail",
"nama_dokumen_1": {"status": "VALID / INVALID / Tidak Perlu",
"description": "penjelasan detail",
},
"summary": "...",
"invalid_item": ["nama_dokumen_1", "nama_dokumen_2"],
"notice_msg": "...",
"form_filling": {"Surname":"...",
"First Name":"...",
"Date of Birth":"...",
"Place of Birth":"...",
"Nationality":"...",
"Sex":"...",
"Mariage Status":"...",
"Passport Number":"...",
"Passport Expiry Date":"...",
"National Identity Number":"...",
"Travel Document Type":"...",
"Travel Document Number":"...",
"Date Of Issue":"...",
"Valid Until":"...",
"Issued Country":"...",
"Applicant's Home Address":"...",
"Applicant's Telephone Number":"...",
"Applicant's Email Address":"...",
"Current Occupation":"...",
"Employer/Educational Address":"...",
"Journey Purpose":"...",
"Destination":"...",
"Duration":"...",
"Number of Entries":"...", # single or multiple
"already has fingerprint":"...",
"inviting person from each destination":"...",
"inviting person email address":"...",
"Traveling and living cost covered by":"..."
} # Hanya isi yang ada di dokumen saja. Jika tidak ada, tidak usah diisi atau dimunculkan. Anda juga bisa menambahkan data penting lain yang mungkin belum ditulis di atas.
}
---
TEMPLATE PESAN PEMBERITAHUAN (notice_msg):
Berikut kami informasikan kekurangan dokumen yang *WAJIB* dibawa saat biometric visa schengen nanti ya :
1. Pas Foto (Wajib berukuran 3,5 x 4,5 cm dan diserahkan di lokasi biometrik)
2. ...
3. ...
4. ...
5. ...
---
## cantumkan dokumen lain yang masih Invalid beserta perbaikan yang diperlukan.
---
TEMPLATE SUMMARY:
List Dokumen yang sudah valid: .... \n
List Dokumen yang invalid : ... \n
Analisis detail keseluruhan: ... \n # sebutkan detail analisa masing-masing dokumen, apa yang menyebabkan dokumen-dokumen tersebut invalid
Rangkuman data peserta: ... # jelaskan rangkuman data peserta yang ada di dokumen seperti nama peserta, apakah disponsori, siapa yang mensponsori, tujuan, tanggal berangkat dan pulang dan data penting lainnya.
'''
# Perform document analysis
prompt_with_date = f'Tanggal Berangkat={tanggal_berangkat}. Tanggal pulang={tanggal_pulang}. Tanggal Biometrik={tanggal_biometrik}\n\n{prompt}'
response = client.models.generate_content(
model="gemini-2.0-flash-lite",
contents=[prompt_with_date] + images,
config=GenerateContentConfig(
temperature=0.1,
response_mime_type="application/json"
)
)
pre_token_usage = response.usage_metadata.total_token_count
token_usage = pre_token_usage*5/1000
raw_output = response.text
# β
Inisialisasi variabel default
analysis = {}
summary = ""
invalid_list = []
notice_msg = ""
form_filling = {}
try:
parsed_output = json.loads(response.text)
analysis = parsed_output.get("analysis", {})
analysis_str = json.dumps(analysis, indent=2, ensure_ascii=False)
summary = parsed_output.get("summary", "")
invalid_list = parsed_output.get("invalid_item", [])
invalid_list_str = json.dumps(invalid_list, indent=2, ensure_ascii=False)
notice_msg = parsed_output.get("notice_msg", "")
notice_msg_ending = '''
Note :
βͺοΈ Semua dokumen di atas mohon difotokan terlebih dahulu agar dapat diperiksa kembali yaa kak ππ»
βͺοΈ Selama visa belum keluar, rekening harus tetap stabil dengan saldo minimal 40juta rupiah/ orang. Tidak berlaku rekening deposito. Rekening koran wajib tertera nama, nomor rekening, nama dan logo/ stamp bank.
Demikian yang kami sampaikan. Terima kasih atas kerja samanya π€
Wishtravelers WT
PT WISATA IMPIAN UNIVERSAL
'''
notice_msg = '''π» *(WISH TRAVELERS) UPDATE DOKUMEN PENGAJUAN VISA* π»
Penting, mohon di baca sampai habis ya kak ππ»
Ini adalah nomor sistem, tidak dapat membalas pesan. Apabila ada pertanyaan, silahkan hubungi mimin WT wa.me/6282123038484
Halo Kak selamat malam π
''' + notice_msg + notice_msg_ending
form_filling = parsed_output.get("form_filling", "")
form_filling_str = json.dumps(form_filling, indent=2, ensure_ascii=False)
except Exception as e:
print(f"Error parsing JSON: {e}")
return raw_output, analysis_str, summary, invalid_list_str, notice_msg, form_filling_str, token_usage
def process_and_zip_all_images(images, zip_name="All_PDF_Docs.zip"):
# Inisialisasi Gemini client
client = genai.Client(api_key='AIzaSyBpviFHkaEF-GAjMMl28dIS1poikhBqq_w')
# Prompt untuk klasifikasi nama file
prompt_3 = '''Anda adalah asisten yang membantu menamai file gambar dokumen.
Tugas Anda adalah mengidentifikasi jenis dokumen pada gambar ini dan memberikan nama file yang sesuai.
Jawaban Anda *harus* berupa *salah satu* nama file dari daftar berikut:
['paspor', 'fotokopipaspor', 'pasfoto', 'kartukeluarga', 'buktinikah', 'bukticerai', 'ktp', 'buktikelahiran', 'suratsponsor', 'guaranteeletter', 'suratkerja', 'NIB' 'SIUP', 'suratjaminanstaff', 'suratsekolah', 'kontrakkerja', 'suratpensiun', 'rekeningkoran', 'slipgaji', 'suratreferensibank']
Jawaban Anda *hanya* boleh berupa teks yang *persis sama* dengan salah satu item dalam daftar tersebut.
Jangan tambahkan penjelasan, tanda kutip, titik, atau teks tambahan lainnya.
Contoh:
Gambar : [tampak gambar KTP]
Output: KTP
Gambar: [gambar sebenarnya]
Output:
'''
# Step 1: Klasifikasi & Penamaan
renamed_images = []
for image in images:
response = client.models.generate_content(
model="gemini-2.0-flash-lite",
contents=[prompt_3, image],
config=GenerateContentConfig(
temperature=0.1,
top_p=0.1
)
)
filename = response.text.strip().lower()
renamed_images.append({"image": image, "filename": filename})
# Step 2: Kelompokkan berdasarkan nama file (tanpa ekstensi)
grouped = {}
for item in renamed_images:
name = os.path.splitext(item["filename"])[0]
grouped.setdefault(name, []).append(item["image"])
# Step 3: Simpan ke PDF dan masukkan ke ZIP
temp_dir = tempfile.mkdtemp()
zip_path = os.path.join(tempfile.gettempdir(), zip_name)
with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zipf:
for doc_name, images in grouped.items():
images_rgb = [img.convert("RGB") for img in images]
pdf_path = os.path.join(temp_dir, f"{doc_name}.pdf")
if len(images_rgb) == 1:
images_rgb[0].save(pdf_path, save_all=True)
else:
images_rgb[0].save(pdf_path, save_all=True, append_images=images_rgb[1:])
zipf.write(pdf_path, arcname=f"{doc_name}.pdf")
return zip_path
def main_process(files, tanggal_berangkat, tanggal_pulang, tanggal_biometrik, dpi):
all_images = []
image_paths_for_zip = []
for file in files:
file_path = file.name if hasattr(file, 'name') else file
if file_path.lower().endswith('.zip'):
extracted_files = extract_zip_and_collect_files(file_path)
for extracted_file in extracted_files:
if extracted_file.lower().endswith('.pdf'):
images = process_pdfs([extracted_file], dpi)
all_images.extend(images)
elif extracted_file.lower().endswith(('.jpg', '.jpeg', '.png')):
image = Image.open(extracted_file)
all_images.append(image)
elif file_path.lower().endswith('.pdf'):
images = process_pdfs([file_path], dpi)
all_images.extend(images)
elif file_path.lower().endswith(('.jpg', '.jpeg', '.png')):
image = Image.open(file_path)
all_images.append(image)
else:
raise ValueError(f"File {file_path} is not a valid image, PDF, or ZIP.")
# Generate summary from images
preprocessed_images = [preprocess_image(img) for img in all_images]
raw_output, analysis_str, summary, invalid_list_str, notice_msg, form_filling_str, token_usage = gemini_analysis(preprocessed_images, tanggal_berangkat, tanggal_pulang, tanggal_biometrik)
rdf = random.randint(5, 10)
time.sleep(rdf)
# Create DOCX for summary output
doc = Document()
doc.add_heading("Visa Document Check Summary", level=1)
doc.add_paragraph(f"Tanggal Berangkat: {tanggal_berangkat}")
doc.add_paragraph(f"Tanggal Pulang: {tanggal_pulang}")
for line in analysis_str.split("\n"):
doc.add_paragraph(line)
doc.add_paragraph(f"Summary: {summary}\n\n")
doc.add_paragraph(f"Invalid List: {invalid_list_str}\n\n")
doc.add_paragraph(f"Notice Message: {notice_msg}\n\n")
doc.add_paragraph(f"Form Filling: {form_filling_str}\n\n")
first_file = files[0]
first_filename = os.path.basename(first_file.name if hasattr(first_file, 'name') else first_file)
base_name = os.path.splitext(first_filename)[0]
docx_filename = f"summary_{base_name}.docx"
temp_docx_path = os.path.join(tempfile.gettempdir(), docx_filename)
doc.save(temp_docx_path)
# Filtering the file
# zip_file_path = process_and_zip_all_images(all_images, zip_name=f'All_PDF_Docs_{base_name}.zip')
return temp_docx_path, form_filling_str, invalid_list_str, analysis_str, summary, notice_msg, token_usage
# Gradio UI update: add ".zip" to accepted file types
with gr.Blocks() as demo:
gr.Markdown("# π§ Noura the Document Checker βοΈ ")
gr.Markdown("Last Updated: June 10 2025")
file_input = gr.File(
label="Upload PDFs, Images or ZIP files (Multiple Supported)",
file_types=[".pdf", ".jpg", ".jpeg", ".png", ".zip"],
file_count="multiple"
)
with gr.Row():
tanggal_berangkat = gr.Textbox(
label="Tanggal Keberangkatan",
placeholder="Masukan Tanggal Keberangkatan",
type="text"
)
tanggal_pulang = gr.Textbox(
label="Tanggal Kepulangan",
placeholder="Masukan Tanggal Kepulangan",
type="text"
)
tanggal_biometrik = gr.Textbox(
label="Tanggal Biometrik",
placeholder="Masukan Tanggal Biometrik",
type="text"
)
dpi_slider = gr.Slider(
minimum=100,
maximum=400,
step=25,
label="Adjust DPI (100 - 400, Ξ=25, default=350)",
value=350
)
run_btn = gr.Button("π Run Analysis")
with gr.Row():
download_output_docx = gr.File(label="π₯ Download Summary as DOCX", visible=True)
# download_valid_zip = gr.File(label="π₯ Download all PDF document in zip", visible=True)
gr.Markdown("## π FORM FILLING RESULT")
form_filling_output = gr.Textbox(label="π FORM FILLING RESULT", lines=20)
gr.Markdown("## π INVALID DOCUMENT LIST")
invalid_list_output = gr.Textbox(label="π INVALID DOCUMENT LIST", lines=5)
gr.Markdown("## π SUMMARY")
summary_output = gr.Textbox(label="π SUMMARY OUTPUT", lines=5)
gr.Markdown("## π NOTIFICATION MESSAGE")
notice_msg = gr.Textbox(label="π NOTIFICATION MSG", lines=10)
gr.Markdown("## π PER DOCUMENT ANALYSIS")
raw_output = gr.Textbox(label="π PER DOCUMENT ANALYSIS", lines=20)
gr.Markdown("Token cost in IDR")
token_usage = gr.Textbox(label="Token cost in IDR", lines=5)
run_btn.click(
fn=main_process,
inputs=[file_input, tanggal_berangkat, tanggal_pulang, tanggal_biometrik, dpi_slider],
outputs=[download_output_docx, form_filling_output, invalid_list_output, raw_output, summary_output, notice_msg, token_usage]
)
demo.launch(debug=True) |