Unlimitedlevel19 commited on
Commit
7dc376b
·
verified ·
1 Parent(s): 01c4e21

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +117 -42
app.py CHANGED
@@ -32,8 +32,71 @@ def process_base64_image(base64_string):
32
  print(f"Error processing base64 image: {e}")
33
  return None
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  # Fungsi untuk parsing teks LSB menjadi struktur data
36
  def parse_lsb_form(text):
 
 
 
37
  # Inisialisasi dictionary untuk menyimpan hasil
38
  result = {}
39
 
@@ -41,38 +104,51 @@ def parse_lsb_form(text):
41
  if "LAPORAN SUMBER BAHAYA" in text:
42
  result["jenis_dokumen"] = "LAPORAN SUMBER BAHAYA"
43
 
44
- # Pattern regex untuk menemukan field-field umum pada form LSB
45
  patterns = {
46
- "nama_pelapor": r"(?:NAMA\s*PELAPOR|PELAPOR)[:\s]*([^\n]+)",
47
- "lokasi": r"(?:LOKASI\s*KEJADIAN|LOKASI)[:\s]*([^\n]+)",
48
- "tanggal": r"(?:TANGGAL\s*/?\s*WAKTU|TANGGAL)[:\s]*([^\n]+)",
49
- "posisi_jabatan": r"(?:POSISI\s*/?\s*JABATAN|JABATAN)[:\s]*([^\n]+)",
50
- "jenis_pengamatan": r"(?:JENIS\s*PENGAMATAN)[:\s]*([^\n]+)",
51
- "uraian_pengamatan": r"(?:URAIAN\s*PENGAMATAN)[:\s]*([^\n]+)",
52
- "bahaya": r"(?:BAHAYA)[:\s]*([^\n]+)",
53
- "tindakan_intervensi": r"(?:TINDAKAN\s*INTERVENSI)[:\s/]*([^\n]+)",
54
- "saran_perbaikan": r"(?:SARAN\s*PERBAIKAN)[:\s]*([^\n]+)"
55
  }
56
 
57
  # Cari semua pola dalam teks
58
  for field_name, pattern in patterns.items():
59
  match = re.search(pattern, text, re.IGNORECASE)
60
  if match:
61
- result[field_name] = match.group(1).strip()
 
 
 
 
62
 
63
- # Untuk jenis pengamatan, cek juga pilihan yang dicentang
64
- if "jenis_pengamatan" not in result:
65
- # Cek untuk Unsafe Condition
66
- if re.search(r"(?:Unsafe\s*Condition|Kondisi\s*Tidak\s*Aman)[:\s]*", text, re.IGNORECASE):
 
 
 
 
67
  result["jenis_pengamatan"] = "Unsafe Condition"
68
- # Cek untuk Unsafe Action
69
- elif re.search(r"(?:Unsafe\s*Action|Tindakan\s*Tidak\s*Aman)[:\s]*", text, re.IGNORECASE):
70
  result["jenis_pengamatan"] = "Unsafe Action"
71
- # Cek untuk Intervensi
72
- elif re.search(r"(?:Intervensi)[:\s]*", text, re.IGNORECASE):
73
  result["jenis_pengamatan"] = "Intervensi"
74
 
75
- # Pengolahan tambahan untuk mengekstrak informasi dari teks
 
 
 
 
 
 
 
76
  lines = text.split('\n')
77
 
78
  # Dictionary untuk menyimpan kunci pencarian dan nama field
@@ -105,31 +181,28 @@ def parse_lsb_form(text):
105
  parts = line.split(":", 1)
106
  if len(parts) > 1:
107
  value = parts[1].strip()
108
- result[field_name] = value
109
- current_field = field_name
110
- found_field = True
111
- break
 
 
112
 
113
  # Jika tidak ada field baru, tambahkan ke field sebelumnya
114
  if not found_field and current_field and line:
115
  if current_field in result:
116
- result[current_field] += " " + line
117
- else:
118
- result[current_field] = line
119
-
120
- # Deteksi nomor LSB jika ada
121
- no_lsb_match = re.search(r"No\.\s*LSB\s*:?\s*([^\n]+)", text, re.IGNORECASE)
122
- if no_lsb_match:
123
- result["no_lsb"] = no_lsb_match.group(1).strip()
124
-
125
- # Format ulang data jika ditemukan format yang tidak standar
126
- if "nama_pelapor" in result and len(result["nama_pelapor"]) > 50:
127
- # Nama pelapor terlalu panjang, mungkin salah deteksi
128
- shorter_name = re.search(r"([A-Za-z\s]{2,30})", result["nama_pelapor"])
129
- if shorter_name:
130
- result["nama_pelapor"] = shorter_name.group(1).strip()
131
 
132
- return result
133
 
134
  # Fungsi untuk API predict yang menerima JSON dengan base64 image
135
  def api_predict(json_input):
@@ -155,7 +228,9 @@ def api_predict(json_input):
155
 
156
  # Lakukan OCR
157
  if TESSERACT_AVAILABLE:
158
- text = pytesseract.image_to_string(image, lang='ind')
 
 
159
  else:
160
  text = "⚠️ OCR tidak dapat diproses karena Tesseract tidak tersedia di Space ini."
161
 
@@ -218,4 +293,4 @@ async def predict_route(request: Request):
218
  if __name__ == "__main__":
219
  # For local development
220
  port = int(os.environ.get("PORT", 7860))
221
- uvicorn.run(app, host="0.0.0.0", port=port)
 
32
  print(f"Error processing base64 image: {e}")
33
  return None
34
 
35
+ # Fungsi untuk pembersihan teks hasil OCR
36
+ def clean_ocr_text(text):
37
+ # Hapus karakter yang tidak perlu
38
+ text = re.sub(r'[\x00-\x1F\x7F-\x9F]', '', text)
39
+ # Hapus spasi berlebih
40
+ text = re.sub(r'\s+', ' ', text).strip()
41
+ # Gabungkan baris yang terpisah
42
+ text = re.sub(r'(\w+)- *\n *(\w+)', r'\1\2', text)
43
+ return text
44
+
45
+ # Fungsi untuk validasi nilai field
46
+ def validate_field(field_name, value):
47
+ if not value:
48
+ return None
49
+
50
+ # Bersihkan nilai dari karakter non-alphanumeric di awal dan akhir
51
+ value = re.sub(r'^[^\w]+|[^\w]+$', '', value).strip()
52
+
53
+ if not value:
54
+ return None
55
+
56
+ # Validasi khusus untuk field tertentu
57
+ if field_name == "nama_pelapor":
58
+ # Nama pelapor harus berisi setidaknya 2 karakter alphabet
59
+ if len(re.findall(r'[a-zA-Z]', value)) < 2:
60
+ return None
61
+ # Hapus karakter seperti |, /, \, dll dari nama
62
+ value = re.sub(r'[|/\\]', '', value).strip()
63
+
64
+ elif field_name == "tanggal":
65
+ # Tanggal harus mengandung angka atau format tanggal
66
+ if not re.search(r'\d{1,4}[-/]\d{1,2}[-/]\d{1,4}|\d{1,2}[-/\s]+\w+[-/\s]+\d{2,4}|\d{2}[-/]\d{2}[-/]\d{2,4}', value):
67
+ # Coba cari angka tanggal dalam string
68
+ date_match = re.search(r'\d{1,2}[-/\s]+\d{1,2}[-/\s]+\d{2,4}', value)
69
+ if date_match:
70
+ value = date_match.group(0)
71
+ else:
72
+ return None
73
+
74
+ elif field_name == "lokasi":
75
+ # Lokasi harus berisi lebih dari 2 karakter
76
+ if len(value) <= 2:
77
+ return None
78
+
79
+ elif field_name in ["bahaya", "uraian_pengamatan", "tindakan_intervensi"]:
80
+ # Teks deskripsi harus cukup panjang dan relevan
81
+ if len(value) < 3 or "No." in value or "Revisi" in value or "FM-" in value:
82
+ return None
83
+
84
+ # Pastikan tidak ada nilai placeholder atau sampah
85
+ placeholders = ["...", "___", "N/A", "-", "--", "diisi oleh", "xxx"]
86
+ for placeholder in placeholders:
87
+ if placeholder in value.lower():
88
+ return None
89
+
90
+ # Hapus tanda | yang sering hadir di awal atau akhir
91
+ value = re.sub(r'^\s*\|\s*|\s*\|\s*$', '', value).strip()
92
+
93
+ return value
94
+
95
  # Fungsi untuk parsing teks LSB menjadi struktur data
96
  def parse_lsb_form(text):
97
+ # Preprocessing teks
98
+ text = clean_ocr_text(text)
99
+
100
  # Inisialisasi dictionary untuk menyimpan hasil
101
  result = {}
102
 
 
104
  if "LAPORAN SUMBER BAHAYA" in text:
105
  result["jenis_dokumen"] = "LAPORAN SUMBER BAHAYA"
106
 
107
+ # Pattern regex yang lebih baik untuk menemukan field-field umum pada form LSB
108
  patterns = {
109
+ "nama_pelapor": r"(?:NAMA\s*PELAPOR|PELAPOR)[^A-Za-z0-9]*\s*([^\n|]{2,40})",
110
+ "lokasi": r"(?:LOKASI\s*KEJADIAN|LOKASI)[^A-Za-z0-9]*\s*([^\n|]{2,50})",
111
+ "tanggal": r"(?:TANGGAL\s*/?\s*WAKTU|TANGGAL)[^A-Za-z0-9]*\s*([^\n|]{2,30})",
112
+ "posisi_jabatan": r"(?:POSISI\s*/?\s*JABATAN|JABATAN)[^A-Za-z0-9]*\s*([^\n|]{2,40})",
113
+ "jenis_pengamatan": r"(?:JENIS\s*PENGAMATAN)[^A-Za-z0-9]*\s*([^\n|]{2,50})",
114
+ "uraian_pengamatan": r"(?:URAIAN\s*PENGAMATAN)[^A-Za-z0-9]*\s*([^\n|]{2,100})",
115
+ "bahaya": r"(?:BAHAYA)[^A-Za-z0-9]*\s*([^\n|]{2,100})",
116
+ "tindakan_intervensi": r"(?:TINDAKAN\s*INTERVENSI)[^A-Za-z0-9/]*\s*([^\n|]{2,100})",
117
+ "saran_perbaikan": r"(?:SARAN\s*PERBAIKAN)[^A-Za-z0-9:]*\s*([^\n|]{2,100})"
118
  }
119
 
120
  # Cari semua pola dalam teks
121
  for field_name, pattern in patterns.items():
122
  match = re.search(pattern, text, re.IGNORECASE)
123
  if match:
124
+ value = match.group(1).strip()
125
+ # Validasi dan bersihkan nilai
126
+ clean_value = validate_field(field_name, value)
127
+ if clean_value:
128
+ result[field_name] = clean_value
129
 
130
+ # Deteksi jenis pengamatan melalui checkbox
131
+ # Cek untuk Unsafe Condition
132
+ if "jenis_pengamatan" not in result or not result["jenis_pengamatan"]:
133
+ unsafe_condition = re.search(r'(?:Unsafe\s*Condition|Kondisi\s*Tidak\s*Aman|Unsafe\s*C)', text, re.IGNORECASE)
134
+ unsafe_action = re.search(r'(?:Unsafe\s*Action|Tindakan\s*Tidak\s*Aman|Unsafe\s*A)', text, re.IGNORECASE)
135
+ intervensi = re.search(r'(?:Intervensi|Intervention)', text, re.IGNORECASE)
136
+
137
+ if unsafe_condition:
138
  result["jenis_pengamatan"] = "Unsafe Condition"
139
+ elif unsafe_action:
 
140
  result["jenis_pengamatan"] = "Unsafe Action"
141
+ elif intervensi:
 
142
  result["jenis_pengamatan"] = "Intervensi"
143
 
144
+ # Deteksi nomor LSB jika ada
145
+ no_lsb_match = re.search(r"No\.\s*LSB\s*:?\s*([a-zA-Z0-9_\-/\.]+)", text, re.IGNORECASE)
146
+ if no_lsb_match:
147
+ no_lsb = no_lsb_match.group(1).strip()
148
+ if "diisi oleh" not in no_lsb.lower():
149
+ result["no_lsb"] = no_lsb
150
+
151
+ # Ekstraksi tambahan dari baris-baris teks
152
  lines = text.split('\n')
153
 
154
  # Dictionary untuk menyimpan kunci pencarian dan nama field
 
181
  parts = line.split(":", 1)
182
  if len(parts) > 1:
183
  value = parts[1].strip()
184
+ clean_value = validate_field(field_name, value)
185
+ if clean_value and (field_name not in result or not result[field_name]):
186
+ result[field_name] = clean_value
187
+ current_field = field_name
188
+ found_field = True
189
+ break
190
 
191
  # Jika tidak ada field baru, tambahkan ke field sebelumnya
192
  if not found_field and current_field and line:
193
  if current_field in result:
194
+ # Cek apakah baris ini relevan untuk field saat ini
195
+ if len(line) > 2 and "diisi oleh" not in line.lower():
196
+ result[current_field] += " " + line
197
+
198
+ # Validasi dan pembersihan akhir hasil ekstraksi
199
+ final_result = {}
200
+ for field, value in result.items():
201
+ clean_value = validate_field(field, value)
202
+ if clean_value:
203
+ final_result[field] = clean_value
 
 
 
 
 
204
 
205
+ return final_result
206
 
207
  # Fungsi untuk API predict yang menerima JSON dengan base64 image
208
  def api_predict(json_input):
 
228
 
229
  # Lakukan OCR
230
  if TESSERACT_AVAILABLE:
231
+ # Konfigurasi tambahan untuk OCR
232
+ config = '--psm 4 --oem 3' # Assume page has multiple columns of text
233
+ text = pytesseract.image_to_string(image, lang='ind', config=config)
234
  else:
235
  text = "⚠️ OCR tidak dapat diproses karena Tesseract tidak tersedia di Space ini."
236
 
 
293
  if __name__ == "__main__":
294
  # For local development
295
  port = int(os.environ.get("PORT", 7860))
296
+ uvicorn.run(app, host="0.0.0.0", port=port)