MikeMai commited on
Commit
49f1653
Β·
verified Β·
1 Parent(s): 347b7f8

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +227 -0
app.py ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pdfminer.high_level import extract_text
2
+ from pdf2image import convert_from_path # Convert PDF pages to images
3
+ import base64
4
+ import io
5
+ import os
6
+ from PIL import Image
7
+
8
+ import json
9
+
10
+ from openai import OpenAI
11
+
12
+ from dotenv import load_dotenv
13
+
14
+ import gradio as gr
15
+
16
+ load_dotenv()
17
+ client = OpenAI()
18
+
19
+ # Function to encode image to Base64
20
+ def encode_image(image_input):
21
+ """
22
+ Encode an image to Base64.
23
+
24
+ Supports both file paths (str) and in-memory PIL images.
25
+ """
26
+ if isinstance(image_input, str): # If input is a file path
27
+ with open(image_input, "rb") as image_file:
28
+ return base64.b64encode(image_file.read()).decode("utf-8")
29
+ elif isinstance(image_input, Image.Image): # If input is a PIL image
30
+ buffered = io.BytesIO()
31
+ image_input.save(buffered, format="JPEG")
32
+ return base64.b64encode(buffered.getvalue()).decode("utf-8")
33
+ else:
34
+ raise ValueError("Unsupported input type. Provide a file path or a PIL image.")
35
+
36
+ # Function to process image files
37
+ def process_image(image_path):
38
+ print(f"πŸ–ΌοΈ Processing image file: {image_path}")
39
+ image_base64 = encode_image(image_path)
40
+ image_url = f"data:image/jpeg;base64,{image_base64}"
41
+
42
+ response = client.chat.completions.create(
43
+ model="gpt-4o",
44
+ messages=[
45
+ {
46
+ "role": "user",
47
+ "content": [
48
+ {"type": "text", "text": "Extract all text from this image."},
49
+ {"type": "image_url", "image_url": {"url": image_url}},
50
+ ],
51
+ }
52
+ ],
53
+ )
54
+
55
+ extracted_text = response.choices[0].message.content.strip()
56
+ # print(f"πŸ“ Extracted text: {extracted_text}")
57
+
58
+ return extracted_text
59
+
60
+ # Function to process text-based PDFs
61
+ def process_text_pdf(pdf_path):
62
+ text_content = extract_text(pdf_path).strip()
63
+ if text_content:
64
+ print(f"πŸ“„ Extracting text from PDF: {pdf_path}")
65
+ return text_content
66
+ return None # No text found, fallback to image processing
67
+
68
+ # Function to process scanned PDFs (image-based)
69
+ def process_image_pdf(pdf_path):
70
+ print(f"πŸ–ΌοΈ No text found! Processing as an image-based (scanned) PDF: {pdf_path}")
71
+ images = convert_from_path(pdf_path)
72
+
73
+ extracted_text = []
74
+ for i, image in enumerate(images):
75
+ image_text = process_image(image)
76
+ extracted_text.append(image_text)
77
+
78
+ return "\n\n".join(extracted_text)
79
+
80
+ # Function to detect file type and extract text accordingly
81
+ def process_file(file_path):
82
+ if not os.path.exists(file_path):
83
+ print(f"❌ Error: File not found: {file_path}")
84
+ return None
85
+
86
+ file_extension = file_path.lower().split(".")[-1]
87
+
88
+ if file_extension in ["jpg", "jpeg", "png"]:
89
+ return process_image(file_path) # Process images
90
+ elif file_extension == "pdf":
91
+ text_data = process_text_pdf(file_path)
92
+ if text_data: # If text extraction succeeds, return it
93
+ return text_data
94
+ return process_image_pdf(file_path) # Otherwise, process as image
95
+ else:
96
+ print(f"❌ Unsupported file type: {file_path}")
97
+ return None
98
+
99
+ def extract_certificate_details(certificate_path):
100
+
101
+ certificate_text = process_file(certificate_path)
102
+
103
+ print(f"πŸ–ΌοΈ Extracting details from certificate: {certificate_path}")
104
+
105
+ if not certificate_text:
106
+ print(f"❌ Error: Certificate text could not be extracted from {certificate_path}")
107
+ return None
108
+
109
+ # Ask GPT-4o to extract the details
110
+ response = client.chat.completions.create(
111
+ model="gpt-4o",
112
+ response_format={ "type": "json_object" },
113
+ seed=123,
114
+ temperature=0,
115
+ messages=[
116
+ {
117
+ "role": "developer",
118
+ "content": f"""Extract the following details from the certificate text in JSON format, leave blank if not found:
119
+
120
+ {{
121
+ "Certificate Name": "",
122
+ "Certificate ID": "",
123
+ "Ship Name": "",
124
+ "Date of Issue": "",
125
+ "Expiration Date": ""
126
+ }}
127
+
128
+ Certificate Text:
129
+ {certificate_text}
130
+ """
131
+ }
132
+ ],
133
+ )
134
+
135
+ result = response.choices[0].message.content
136
+ result_json = json.loads(result) # Parse the result as JSON
137
+
138
+ certificate_name = result_json.get("Certificate Name", "")
139
+ certificate_id = result_json.get("Certificate ID", "")
140
+ ship_name = result_json.get("Ship Name", "")
141
+ date_of_issue = result_json.get("Date of Issue", "")
142
+ expiration_date = result_json.get("Expiration Date", "")
143
+
144
+ print(f"βœ… Extracted details:\n- Certificate Name: {certificate_name}\n- Certificate ID: {certificate_id}\n- Ship Name: {ship_name}\n- Date of Issue: {date_of_issue}\n- Expiration Date: {expiration_date}")
145
+
146
+ return {
147
+ "Certificate Name": certificate_name,
148
+ "Certificate ID": certificate_id,
149
+ "Ship Name": ship_name,
150
+ "Date of Issue": date_of_issue,
151
+ "Expiration Date": expiration_date,
152
+ "Certificate Text": certificate_text
153
+ }
154
+
155
+ # Function to compare two certificates using AI
156
+ def compare_certificates(new_cert_details, old_cert_details):
157
+
158
+ # Ask GPT-4o to compare the texts
159
+ response = client.chat.completions.create(
160
+ model="gpt-4o",
161
+ messages=[
162
+ {
163
+ "role": "user",
164
+ "content": f"""Compare the two certificates below and provide a structured summary highlighting key differences in the format below:
165
+
166
+ ### Comparison Summary:
167
+ - Identify differences in terms of:
168
+ - Certificate ID
169
+ - Date of Issue
170
+ - Expiration Date
171
+
172
+ - Highlight any changes in other key details, if applicable.
173
+
174
+ ### Take Note:
175
+ - Clearly structure the output for easy reading
176
+ - Do not include any structural changes in the text, only content changes
177
+
178
+ ### Old Certificate:
179
+ {old_cert_details}
180
+
181
+ ### New Certificate:
182
+ {new_cert_details}"""
183
+ }
184
+ ],
185
+ )
186
+
187
+ comparison_result = response.choices[0].message.content.strip()
188
+
189
+ return comparison_result
190
+
191
+ def gradio_process_certificate(certificate, old_cert_details=""):
192
+ # Process the certificate
193
+ cert_details = extract_certificate_details(certificate)
194
+
195
+ if not cert_details:
196
+ return "❌ Failed to extract certificate details."
197
+
198
+ # If old_certificate is provided, compare the certificates
199
+ if old_cert_details:
200
+
201
+ print(f"πŸ” Comparing certificates")
202
+ # Compare the certificates
203
+ comparison_result = compare_certificates(cert_details, old_cert_details)
204
+
205
+ # Return both certificate details and comparison result
206
+ return {
207
+ "new_certificate": cert_details,
208
+ "old_certificate": old_cert_details,
209
+ "comparison": comparison_result
210
+ }
211
+
212
+ # If only one certificate is provided, return just its details
213
+ return cert_details
214
+
215
+ # Launch Gradio UI
216
+ gr.Interface(
217
+ fn=gradio_process_certificate,
218
+ inputs=[
219
+ gr.File(label="Certificate (PDF or Image)"),
220
+ gr.Textbox(label="Old Certificate Details (JSON) - Optional")
221
+ ],
222
+ outputs=gr.JSON(label="Certificate Details"),
223
+ title="πŸ“œ Certificate Details Extractor",
224
+ description="Upload a certificate to extract details, or upload two certificates to compare them.",
225
+ show_progress='full',
226
+ allow_flagging="never"
227
+ ).launch()