frendyrachman commited on
Commit
cf0a188
·
verified ·
1 Parent(s): d9b382b

Update app.py

Browse files

Update feature
1. File filtering
2. FIltered output zip
3. Docx analysis
4. Valid list text

Files changed (1) hide show
  1. app.py +97 -51
app.py CHANGED
@@ -9,6 +9,22 @@ import tempfile
9
  os.system("apt-get install poppler-utils")
10
  import datetime
11
  from docx import Document
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
 
14
  def extract_zip_and_collect_files(zip_file_path):
@@ -38,24 +54,24 @@ def process_pdfs(pdf_files):
38
  if not os.path.isfile(pdf_file):
39
  raise ValueError(f"File {pdf_file} does not exist.")
40
 
41
- images = convert_from_path(pdf_file, dpi=200) # Convert PDF pages to images
42
  all_images.extend(images)
43
 
44
  return all_images
45
 
46
 
47
  # Function to analyze the extracted image using Google GenAI
48
- def gemini_analysis(images, tanggal_berangkat, tanggal_pulang):
49
  """
50
  Analyze the extracted image using Google GenAI.
51
  """
52
  # Initialize the GenAI client (make sure the API key is set properly)
53
  today = date.today()
54
- client = genai.Client(api_key=os.getenv("GOOGLE_API_KEY"))
55
  # Define your prompt
56
- prompt = f'''Anda bertugas memvalidasi kesesuaian dan konsistensi data dari dokumen individual berdasarkan syarat Visa di bawah. Cukup fokus pada syarat yang diberikan tanpa mengambil referensi lain.
57
- Gunakan tanggal hari ini ({today}) sebagai tanggal pemeriksaan visa (bukan pengajuan). Gunakan {tanggal_berangkat} sebagai tanggal berangkat, dan {tanggal_pulang} sebagai tanggal kepulangan.
58
- Pastikan data seperti nama, tanggal, tujuan dan lainnya sama/konsisten antar dokumen. Di akhir, berikan kesimpulan dari pemeriksaan dokumen. Jika ada yang kurang lengkap atau tidak valid, berikan pesan pemberitahuan untuk pemilik data tersebut terkait data yang kurang atau tidak sesuai.
59
  ---
60
  DAFTAR SYARAT DOKUMEN YANG WAJIB DIPERIKSA:
61
  1. Paspor
@@ -102,73 +118,102 @@ def gemini_analysis(images, tanggal_berangkat, tanggal_pulang):
102
  Jika suami lengkap → istri cukup lampirkan rekening koran suami
103
 
104
  ---
105
- FORMAT JAWABAN UNTUK SETIAP DOKUMEN YANG DIUPLOAD:
106
  - Jenis Dokumen : (jenis dokumen)
107
  - Status : (Valid / Perlu cek ulang / Tidak diperlukan / Tidak ada)
108
  - Catatan : (Catatan singkat terkait isi dokumen)
109
  ---
110
- FORMAT KESIMPULAN:
111
  - List dokumen yang sudah valid: ...
112
- - List dokumen yang perlu pemeriksaan ulang: ...
113
- - List dokumen yang tidak ada/belum lengkap: ...
114
  ---
115
- TEMPLATE PESAN PEMBERITAHUAN:
116
- Halo pak/bu (nama peserta), berikut ini rangkuman hasil pemeriksaan dokumen pengajuan visa anda: ...
117
  '''
118
 
119
  # Perform document analysis
120
  response_1 = client.models.generate_content(
121
- model="gemini-1.5-flash",
122
- contents=[prompt] + images # Pass prompt and image files
123
- )
 
 
 
 
124
  analysis = response_1.text
125
  # Perform valid list generation
126
- prompt_2 = "Buatkan daftar dokumen yang valid saja dalam bentuk list dalam 1 kata di antara contoh berikut: 'PASPOR', 'PAS_FOTO', 'KARTU_KELUARGA', 'BUKTI_NIKAH', 'KTP', 'SURAT_KELAHIRAN', 'SURAT_SPONSOR', 'SURAT_KERJA', 'NIB', 'SIUP', 'SURAT_JAMINAN_STAF', 'SURAT_SEKOLAH', 'SURAT_PENDIDIKAN', 'KONTRAK_KERJA', 'SURAT_PENSIUN', 'REKENING_KORAN', 'SLIP_GAJI'"
127
  response_2 = client.models.generate_content(
128
- model="gemini-1.5-flash",
129
- contents=[response_1.text, prompt_2] # Pass prompt and image files
 
 
 
 
130
  )
131
- valid_docs_list_raw = response_2.text.strip()
132
  if '\n' in valid_docs_list_raw:
133
  docs_list = [line.strip("-• ").strip() for line in valid_docs_list_raw.splitlines() if line.strip()]
134
  elif ',' in valid_docs_list_raw:
135
  docs_list = [item.strip() for item in valid_docs_list_raw.split(",") if item.strip()]
 
 
136
  else:
137
  # fallback: jadikan 1 elemen list
138
  docs_list = [valid_docs_list_raw]
139
  return analysis, docs_list
140
 
141
- # function to ask gemini to rename the image based on detected
142
- def image_file_naming(images):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  renamed_images = []
144
- client = genai.Client(api_key=os.getenv("GOOGLE_API_KEY"))
145
-
146
- for i, image in enumerate(images):
147
- prompt_3 = "Analisa dokumen berikut dan beri nama dalam 1 nama dokumen pasti antara: 'PASPOR', 'PAS_FOTO', 'KARTU_KELUARGA', 'BUKTI_NIKAH', 'KTP', 'SURAT_KELAHIRAN', 'SURAT_SPONSOR', 'SURAT_KERJA', 'NIB', 'SIUP', 'SURAT_JAMINAN_STAF', 'SURAT_SEKOLAH', 'SURAT_PENDIDIKAN', 'KONTRAK_KERJA', 'SURAT_PENSIUN', 'REKENING_KORAN', 'SLIP_GAJI'"
148
- response_3 = client.models.generate_content(
149
- model="gemini-1.5-flash",
150
- contents=[prompt_3, image] # Pass prompt and image files
 
151
  )
152
- new_image_filename = response_3.text.strip().upper() + ".jpg"
153
- renamed_images.append({"image": image, "filename": new_image_filename})
154
-
155
- return renamed_images
156
 
157
- def save_images_to_zip(images_info, zip_name="filtered_images.zip"):
158
- from PIL import Image
159
- temp_dir = tempfile.mkdtemp()
160
- zip_path = os.path.join(tempfile.gettempdir(), zip_name)
 
161
 
162
- # Step 1: Kelompokkan gambar berdasarkan nama dokumen
163
  grouped = {}
164
- for item in images_info:
165
- name = os.path.splitext(item["filename"])[0] # tanpa .jpg
166
  grouped.setdefault(name, []).append(item["image"])
167
 
168
- # Step 2: Simpan tiap grup sebagai PDF
 
 
 
169
  with zipfile.ZipFile(zip_path, 'w') as zipf:
170
  for doc_name, images in grouped.items():
171
- # pastikan semua dalam RGB
172
  images_rgb = [img.convert("RGB") for img in images]
173
  pdf_path = os.path.join(temp_dir, f"{doc_name}.pdf")
174
 
@@ -182,9 +227,7 @@ def save_images_to_zip(images_info, zip_name="filtered_images.zip"):
182
  return zip_path
183
 
184
 
185
-
186
-
187
- def main_process(files, tanggal_berangkat, tanggal_pulang):
188
  all_images = []
189
  image_paths_for_zip = []
190
 
@@ -210,7 +253,9 @@ def main_process(files, tanggal_berangkat, tanggal_pulang):
210
  raise ValueError(f"File {file_path} is not a valid image, PDF, or ZIP.")
211
 
212
  # Generate summary from images
213
- summary, valid_list = gemini_analysis(all_images, tanggal_berangkat, tanggal_pulang)
 
 
214
 
215
  # Create DOCX for summary output
216
  doc = Document()
@@ -225,11 +270,7 @@ def main_process(files, tanggal_berangkat, tanggal_pulang):
225
  doc.save(temp_docx_path)
226
 
227
  # Filtering the file
228
- renamed_images_info = image_file_naming(all_images)
229
- # Filter hanya yang valid
230
- images_to_zip = [img_info for img_info in renamed_images_info if os.path.splitext(img_info["filename"])[0] in valid_list]
231
- zip_file_path = save_images_to_zip(images_to_zip)
232
-
233
  return temp_docx_path, valid_list, zip_file_path
234
 
235
 
@@ -254,6 +295,11 @@ with gr.Blocks() as demo:
254
  placeholder="Masukan Tanggal Kepulangan",
255
  type="text"
256
  )
 
 
 
 
 
257
 
258
  run_btn = gr.Button("🏃 Run Analysis")
259
  output = gr.Textbox(label="📝 Valid Document List", lines=5)
@@ -264,7 +310,7 @@ with gr.Blocks() as demo:
264
 
265
  run_btn.click(
266
  fn=main_process,
267
- inputs=[file_input, tanggal_berangkat, tanggal_pulang],
268
  outputs=[download_output_docx, output, download_valid_zip]
269
  )
270
 
 
9
  os.system("apt-get install poppler-utils")
10
  import datetime
11
  from docx import Document
12
+ import time
13
+ import random
14
+ from google.genai.types import (
15
+ FunctionDeclaration,
16
+ GenerateContentConfig,
17
+ GoogleSearch,
18
+ HarmBlockThreshold,
19
+ HarmCategory,
20
+ MediaResolution,
21
+ Part,
22
+ Retrieval,
23
+ SafetySetting,
24
+ Tool,
25
+ ToolCodeExecution,
26
+ VertexAISearch,
27
+ )
28
 
29
 
30
  def extract_zip_and_collect_files(zip_file_path):
 
54
  if not os.path.isfile(pdf_file):
55
  raise ValueError(f"File {pdf_file} does not exist.")
56
 
57
+ images = convert_from_path(pdf_file, dpi=250) # Convert PDF pages to images
58
  all_images.extend(images)
59
 
60
  return all_images
61
 
62
 
63
  # Function to analyze the extracted image using Google GenAI
64
+ def gemini_analysis(images, tanggal_berangkat, tanggal_pulang, api_key):
65
  """
66
  Analyze the extracted image using Google GenAI.
67
  """
68
  # Initialize the GenAI client (make sure the API key is set properly)
69
  today = date.today()
70
+ client = genai.Client(api_key=api_key)
71
  # Define your prompt
72
+ prompt = f'''Anda bertugas memvalidasi kelengkapan, kesesuaian dan konsistensi data dari dokumen individual berdasarkan syarat Visa di bawah. Cukup fokus pada syarat yang diberikan tanpa mengambil referensi lain.
73
+ Gunakan {tanggal_berangkat} sebagai tanggal berangkat, dan {tanggal_pulang} sebagai tanggal kepulangan.
74
+ Pastikan data seperti nama, tanggal, tujuan dan lainnya konsisten antar dokumen. Semua jawaban dalam format text. Jangan tambahkan formating seperti * atau #
75
  ---
76
  DAFTAR SYARAT DOKUMEN YANG WAJIB DIPERIKSA:
77
  1. Paspor
 
118
  Jika suami lengkap → istri cukup lampirkan rekening koran suami
119
 
120
  ---
121
+ FORMAT ANALISA PER DOKUMEN:
122
  - Jenis Dokumen : (jenis dokumen)
123
  - Status : (Valid / Perlu cek ulang / Tidak diperlukan / Tidak ada)
124
  - Catatan : (Catatan singkat terkait isi dokumen)
125
  ---
126
+ FORMAT RANGKUMAN :
127
  - List dokumen yang sudah valid: ...
128
+ - List dokumen yang tidak valid perlu pemeriksaan ulang: ...
 
129
  ---
 
 
130
  '''
131
 
132
  # Perform document analysis
133
  response_1 = client.models.generate_content(
134
+ model="gemini-2.0-flash",
135
+ contents=[prompt] + images,
136
+ config=GenerateContentConfig(
137
+ temperature=0.2,
138
+ top_p=0.2
139
+ )
140
+ )
141
  analysis = response_1.text
142
  # Perform valid list generation
143
+ prompt_2 = "Dari analisa diatas, Rangkum menjadi list/daftar dokumen yang valid saja. Misal: 'paspor', 'pasfoto', 'kartukeluarga', 'buktinikah', 'KTP', 'suratkelahiran', 'suratsponsor', 'suratkerja', 'NIB', 'SIUP', 'suratjaminanstaff', 'suratsekolah', 'kontrakkerja', 'suratpensiun', 'rekeningkoran', 'slipgaji', 'other'. Jangan tambahkan kata-kata atau kalimat lain."
144
  response_2 = client.models.generate_content(
145
+ model="gemini-2.0-flash",
146
+ contents=[analysis, prompt_2], # Pass prompt and image files
147
+ config=GenerateContentConfig(
148
+ temperature=0.2,
149
+ top_p=0.2
150
+ )
151
  )
152
+ valid_docs_list_raw = response_2.text.strip().lower()
153
  if '\n' in valid_docs_list_raw:
154
  docs_list = [line.strip("-• ").strip() for line in valid_docs_list_raw.splitlines() if line.strip()]
155
  elif ',' in valid_docs_list_raw:
156
  docs_list = [item.strip() for item in valid_docs_list_raw.split(",") if item.strip()]
157
+ elif '* ' in valid_docs_list_raw:
158
+ docs_list = [item.strip() for item in valid_docs_list_raw.split("*") if item.strip()]
159
  else:
160
  # fallback: jadikan 1 elemen list
161
  docs_list = [valid_docs_list_raw]
162
  return analysis, docs_list
163
 
164
+
165
+ def process_and_zip_valid_images(images, docs_list, api_key, zip_name="Valid_Docs.zip"):
166
+
167
+ # Inisialisasi Gemini client
168
+ client = genai.Client(api_key=api_key)
169
+
170
+ # Prompt untuk klasifikasi nama file
171
+ prompt = '''Anda adalah asisten yang membantu menamai file gambar dokumen.
172
+ Tugas Anda adalah mengidentifikasi jenis dokumen pada gambar ini dan memberikan nama file yang sesuai.
173
+ Jawaban Anda *harus* berupa *salah satu* nama file dari daftar berikut:
174
+ ['paspor', 'pasfoto', 'kartukeluarga', 'buktinikah', 'KTP', 'suratkelahiran', 'suratsponsor', 'suratkerja', 'NIB', 'SIUP', 'suratjaminanstaff', 'suratsekolah', 'kontrakkerja', 'suratpensiun', 'rekeningkoran', 'slipgaji', 'other']
175
+ Jawaban Anda *hanya* boleh berupa teks yang *persis sama* dengan salah satu item dalam daftar tersebut.
176
+ Jangan tambahkan penjelasan, tanda kutip, titik, atau teks tambahan lainnya.
177
+ Contoh:
178
+ Gambar : [tampak gambar KTP]
179
+ Output: KTP
180
+
181
+ Gambar: [gambar sebenarnya]
182
+ Output:
183
+ '''
184
+
185
+ # Step 1: Klasifikasi & Penamaan
186
  renamed_images = []
187
+ for image in images:
188
+ response = client.models.generate_content(
189
+ model="gemini-2.0-flash",
190
+ contents=[prompt, image],
191
+ config=GenerateContentConfig(
192
+ temperature=0.2,
193
+ top_p=0.2
194
+ )
195
  )
196
+ filename = response.text.strip().lower()
197
+ renamed_images.append({"image": image, "filename": filename})
 
 
198
 
199
+ # Step 2: Filter sesuai valid_list
200
+ filtered_images = [
201
+ item for item in renamed_images
202
+ if os.path.splitext(item["filename"])[0] in [v.lower() for v in docs_list]
203
+ ]
204
 
205
+ # Step 3: Kelompokkan berdasarkan nama file (tanpa .jpg)
206
  grouped = {}
207
+ for item in filtered_images:
208
+ name = os.path.splitext(item["filename"])[0]
209
  grouped.setdefault(name, []).append(item["image"])
210
 
211
+ # Step 4: Simpan ke PDF dan masukkan ke ZIP
212
+ temp_dir = tempfile.mkdtemp()
213
+ zip_path = os.path.join(tempfile.gettempdir(), zip_name)
214
+
215
  with zipfile.ZipFile(zip_path, 'w') as zipf:
216
  for doc_name, images in grouped.items():
 
217
  images_rgb = [img.convert("RGB") for img in images]
218
  pdf_path = os.path.join(temp_dir, f"{doc_name}.pdf")
219
 
 
227
  return zip_path
228
 
229
 
230
+ def main_process(files, tanggal_berangkat, tanggal_pulang, api_key):
 
 
231
  all_images = []
232
  image_paths_for_zip = []
233
 
 
253
  raise ValueError(f"File {file_path} is not a valid image, PDF, or ZIP.")
254
 
255
  # Generate summary from images
256
+ summary, valid_list = gemini_analysis(all_images, tanggal_berangkat, tanggal_pulang, api_key)
257
+ rdf = random.randint(5, 10)
258
+ time.sleep(rdf)
259
 
260
  # Create DOCX for summary output
261
  doc = Document()
 
270
  doc.save(temp_docx_path)
271
 
272
  # Filtering the file
273
+ zip_file_path = process_and_zip_valid_images(all_images, valid_list, api_key)
 
 
 
 
274
  return temp_docx_path, valid_list, zip_file_path
275
 
276
 
 
295
  placeholder="Masukan Tanggal Kepulangan",
296
  type="text"
297
  )
298
+ api_key = gr.Textbox(
299
+ label="Gemini API Key",
300
+ placeholder="Masukan Kode API",
301
+ type="text"
302
+ )
303
 
304
  run_btn = gr.Button("🏃 Run Analysis")
305
  output = gr.Textbox(label="📝 Valid Document List", lines=5)
 
310
 
311
  run_btn.click(
312
  fn=main_process,
313
+ inputs=[file_input, tanggal_berangkat, tanggal_pulang, api_key],
314
  outputs=[download_output_docx, output, download_valid_zip]
315
  )
316