Rsnarsna commited on
Commit
9d9d8df
·
verified ·
1 Parent(s): ba92c64

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +346 -59
app.py CHANGED
@@ -1,67 +1,354 @@
1
  from fastapi import FastAPI, Request
2
  from fastapi.responses import HTMLResponse
3
- from transformers import pipeline
 
 
 
 
 
4
 
5
- # Initialize the FastAPI app
6
  app = FastAPI()
7
 
8
- # Initialize the text generation pipeline
9
- pipe = pipeline("text2text-generation", model="google/flan-t5-small")
 
 
 
 
 
 
 
 
 
 
10
 
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  @app.get("/", response_class=HTMLResponse)
13
- def home():
14
- """
15
- Renders a simple HTML page with a text input field and a submit button.
16
- """
17
- return """
18
- <!DOCTYPE html>
19
- <html lang="en">
20
- <head>
21
- <meta charset="UTF-8">
22
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
23
- <title>Text Generation</title>
24
- </head>
25
- <body>
26
- <h1>Text Generation with FastAPI and Hugging Face Transformers</h1>
27
- <form action="/generate" method="get">
28
- <label for="text">Enter Text:</label><br><br>
29
- <input type="text" id="text" name="text" required><br><br>
30
- <button type="submit">Generate</button>
31
- </form>
32
- <div id="result"></div>
33
- </body>
34
- </html>
35
- """
36
-
37
-
38
- @app.get("/generate", response_class=HTMLResponse)
39
- def generate(text: str):
40
- """
41
- Handles the text generation and returns the generated output in HTML format.
42
- """
43
- # Use the pipeline to generate text from the given input text
44
- output = pipe(text)
45
-
46
- # Prepare the result as an HTML response
47
- generated_text = output[0]['generated_text']
48
- return f"""
49
- <!DOCTYPE html>
50
- <html lang="en">
51
- <head>
52
- <meta charset="UTF-8">
53
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
54
- <title>Generated Output</title>
55
- </head>
56
- <body>
57
- <h1>Generated Text</h1>
58
- <p><strong>Input:</strong> {text}</p>
59
- <p><strong>Output:</strong> {generated_text}</p>
60
- <br>
61
- <a href="/">Go Back</a>
62
- </body>
63
- </html>
64
- """
65
-
66
-
67
- # Run the app with: uvicorn your_filename:app --reload
 
1
  from fastapi import FastAPI, Request
2
  from fastapi.responses import HTMLResponse
3
+ import threading
4
+ from email.header import decode_header
5
+ import mysql.connector
6
+ from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
7
+ import email, imaplib, json, time
8
+ import torch
9
 
 
10
  app = FastAPI()
11
 
12
+ # Global variable to control the main loop
13
+ running = True
14
+ IMAP_SERVER = 'imap.gmail.com'
15
+ EMAIL_ADDRESS = '[email protected]'
16
+ PASSWORD = 'gclc wsnx kywt uvqy '
17
+ DB_CONFIG = {
18
+ 'host': '0.tcp.in.ngrok.io',
19
+ 'port': 18051,
20
+ 'user': 'root',
21
+ 'password': '',
22
+ 'database': 'shipment_details'
23
+ }
24
 
25
 
26
+ try:
27
+ # Check if GPU is available and set the device accordingly
28
+ # device = "cuda" if torch.cuda.is_available() else "cpu"
29
+ # print(f"Using device: {device}")
30
+ # Load the tokenizer
31
+ tokenizer = AutoTokenizer.from_pretrained("microsoft/Phi-3-mini-128k-instruct", trust_remote_code=True, cache_dir='./phi3_mini')
32
+
33
+ # Load the model
34
+ model = AutoModelForCausalLM.from_pretrained(
35
+ "microsoft/Phi-3-mini-128k-instruct",
36
+ load_in_8bit=True,
37
+ device_map="auto", # Automatically map layers to available device (GPU/CPU)
38
+ trust_remote_code=True,
39
+ cache_dir='./phi3_mini'
40
+ )
41
+
42
+ except Exception as e:
43
+ print(f"Error initializing LLM: {e}")
44
+
45
+
46
+ output_format = {
47
+ "origin": "",
48
+ "destination": "",
49
+ "Expected_shipment_datetime": "",
50
+ "Types of service": "",
51
+ "Warehouse": "",
52
+ "Description": "",
53
+ "Quantities": "",
54
+ "Carrier_details": ""
55
+ }
56
+
57
+ prompt = f"""
58
+ System prompt: You will be provided with an email containing shipment details. Your task is to extract specific information based on the given instructions.
59
+
60
+ Instructions:
61
+ 1. The input email may contain irrelevant information. Focus only on extracting details about future shipments.
62
+ 2. The output should be in JSON format. If a type of information is not found, it should be marked as null.
63
+ 3. Extract the following information:
64
+ - origin: The origin location of the consignment.
65
+ - destination: The destination location of the consignment.
66
+ - expected_shipment_datetime: The expected date and time of delivery to the warehouse (format: yyyy-mm-dd hh:mm:ss).
67
+ - types_of_service: The type of service (AIR, LCL, FCL). AIR can be mentioned as flight, aeroplane, or any mode of air transport. LCL is a Less-Container Load, and FCL is a Full-Container Load.
68
+ - warehouse: The name of the warehouse.
69
+ - description: A brief description of the email (ASN) within 100 words and the responce is not truncated and covers the essential points.
70
+ - quantities: The number of items in the shipment.
71
+ - carrier_details: The details of the carrier.
72
+ 4. the output extracted information contains must be in this format:
73
+ {{
74
+ "origin": "",
75
+ "destination": "",
76
+ "expected_shipment_datetime": "",
77
+ "types_of_service": "",
78
+ "warehouse": "",
79
+ "description": "",
80
+ "quantities": "",
81
+ "carrier_details": ""
82
+ }}
83
+ Examples:
84
+
85
+ 1. Email: We are pleased to inform you of an upcoming shipment originating from Hamburg and destined for New York. The shipment is expected to arrive on August 15, 2024. This consignment includes various electronics, with an estimated quantity of 200 units. The service type for this shipment is AIR, provided by our reliable carrier, Sky Logistics.
86
+ Extracted Information:
87
+ origin: Hamburg,
88
+ destination: New York,
89
+ expected_shipment_datetime: 2024-08-15 00:00:000,
90
+ types_of_service: AIR,
91
+ warehouse: Sky Logistics,
92
+ description: We are pleased to inform you of an upcoming shipment originating from Hamburg and destined for New York. The shipment is expected to arrive on August 15, 2024.,
93
+ quantities: 200 units,
94
+ carrier_details: Sky Logistics
95
+
96
+ 2. Email: Please be advised of a shipment from our supplier in Shanghai heading to Los Angeles. The expected date of arrival is July 30, 2024. The shipment consists of mixed goods, mainly textiles, with a total of 500 pieces. This delivery will be handled through LCL service by Ocean Freight Co.
97
+ Extracted Information:
98
+ origin: Shanghai,
99
+ destination: Los Angeles,
100
+ expected_shipment_datetime: 2024-07-30 00:00:0000,
101
+ types_of_service: LCL,
102
+ warehouse: Ocean Freight Co.,
103
+ description: Please be advised of a shipment from our supplier in Shanghai heading to Los Angeles. The expected date of arrival is July 30, 2024.,
104
+ quantities: 500 pieces,
105
+ carrier_details: Ocean Freight Co.
106
+
107
+ 3. Email: A new shipment is on its way from Mumbai to London, scheduled to reach by August 22, 2024. This batch contains furniture items, totaling 150 pieces. It is managed by Global Carriers.
108
+ Extracted Information:
109
+ origin: Mumbai,
110
+ destination: London,
111
+ expected_shipment_datetime: 2024-08-22 00:00:00000,
112
+ types_of_service: null,
113
+ warehouse: Global Carriers,
114
+ description: A new shipment is on its way from Mumbai to London, scheduled to reach by August 22, 2024.,
115
+ quantities: 150 pieces,
116
+ carrier_details: Global Carriers
117
+
118
+ 4. Email: We are notifying you about a shipment dispatched from Tokyo, heading towards Sydney, with an estimated arrival date of September 10, 2024. The cargo includes automotive parts, summing up to 350 units. This shipment will be transported via AIR service, operated by Jet Logistics.
119
+ Extracted Information:
120
+ origin: Tokyo,
121
+ destination: Sydney,
122
+ expected_shipment_datetime: 2024-09-10 00:00:0000,
123
+ types_of_service: AIR,
124
+ warehouse: Jet Logistics,
125
+ description: We are notifying you about a shipment dispatched from Tokyo, heading towards Sydney, with an estimated arrival date of September 10, 2024.,
126
+ quantities: 350 units,
127
+ carrier_details: Jet Logistics
128
+
129
+ 5. Email: Kindly note the details of a forthcoming shipment from Berlin to Toronto. The shipment encompasses various household goods, with a total quantity of 400 items. We have arranged for this to be shipped using LCL service, provided by Sea Wave Transport.
130
+ Extracted Information:
131
+ origin: Berlin,
132
+ destination: Toronto,
133
+ expected_shipment_datetime: null,
134
+ types_of_service: LCL,
135
+ warehouse: Sea Wave Transport,
136
+ description: Kindly note the details of a forthcoming shipment from Berlin to Toronto. The expected arrival is on August 5, 2024.,
137
+ quantities: 400 items,
138
+ carrier_details: Sea Wave Transport
139
+
140
+ Output: {output_format}
141
+ """
142
+ tput_format}
143
+
144
+ def insert_data(extracted_details):
145
+ print(extracted_details)
146
+ try:
147
+ print('started !!')
148
+ # Initialize MySQL database connection
149
+ mydb = mysql.connector.connect(**DB_CONFIG)
150
+ cursor = mydb.cursor()
151
+ # print('db connecyed ! ''')
152
+ # Check if any of the required fields are empty
153
+ required_fields = [
154
+ 'origin', 'destination', 'expected_shipment_datetime',
155
+ 'types_of_service', 'warehouse', 'description',
156
+ 'quantities', 'carrier_details'
157
+ ]
158
+ if all(extracted_details.get(field) in ["", None] for field in required_fields):
159
+ print("Skipping insertion: All specified extracted values are empty.")
160
+ return
161
+ sql = """
162
+ INSERT INTO shipment_details (origin, destination, expected_shipment_datetime, types_of_service, warehouse, description, quantities, carrier_details, sender, receiver, cc, bcc, subject)
163
+ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
164
+ """
165
+ # print('ready to update ! ///')
166
+ val = (
167
+ extracted_details.get('origin'),
168
+ extracted_details.get('destination'),
169
+ extracted_details.get('expected_shipment_datetime'),
170
+ extracted_details.get('types_of_service'),
171
+ extracted_details.get('warehouse'),
172
+ extracted_details.get('description'),
173
+ extracted_details.get('quantities'),
174
+ extracted_details.get('carrier_details'),
175
+ extracted_details.get('sender'),
176
+ extracted_details.get('receiver'),
177
+ extracted_details.get('cc'),
178
+ extracted_details.get('bcc'),
179
+ extracted_details.get('subject')
180
+ )
181
+
182
+ cursor.execute(sql, val)
183
+ print('data inserted successfully ! ...')
184
+ mydb.commit()
185
+
186
+ except mysql.connector.Error as e:
187
+ print(f"Database error: {e}")
188
+ except Exception as e:
189
+ print(f"Error inserting data: {e}")
190
+
191
+ def get_details(mail):
192
+ pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
193
+ prompt_ = f"\n[system]:{prompt}\n[User]: {mail}\n[Assistant]:"
194
+ output = pipe(prompt_, max_new_tokens=200)
195
+ # print(output[0])
196
+ # print(output[0]['generated_text'])
197
+
198
+ txt = output[0]['generated_text']
199
+ st = txt.find('[Assistant]:')
200
+ ed = txt.find('}')
201
+
202
+ data = txt[st+len('[Assistant]:'):].strip()
203
+
204
+ data = data[data.find('{'):data.find('}')+1].strip()
205
+
206
+ # print(data)
207
+ # jon = json.loads(data)
208
+ return data
209
+
210
+
211
+
212
+
213
+ def read_email():
214
+ try:
215
+ mail = imaplib.IMAP4_SSL(IMAP_SERVER)
216
+ mail.login(EMAIL_ADDRESS, PASSWORD)
217
+ mail.select('inbox')
218
+
219
+ # Search for unread emails
220
+ status, messages = mail.search(None, 'UNSEEN')
221
+ message_ids = messages[0].split()
222
+ print(f"Total unread emails: {len(message_ids)}")
223
+
224
+ # Process each unread email
225
+ for message_id in message_ids:
226
+ try:
227
+ # Fetch the email
228
+ status, data = mail.fetch(message_id, '(RFC822)')
229
+ raw_email = data[0][1]
230
+ email_message = email.message_from_bytes(raw_email)
231
+
232
+ # Extract email metadata
233
+ sender = email_message['From']
234
+ receiver = email_message['To']
235
+ cc = email_message['Cc']
236
+ bcc = email_message['Bcc']
237
+ subject = email_message['Subject']
238
+ date = email_message['Date']
239
+
240
+ # print('sender : >>',type(sender), sender)
241
+ # Extract the email body
242
+ email_body = ""
243
+ if email_message.is_multipart():
244
+ for part in email_message.walk():
245
+ if part.get_content_type() == 'text/plain':
246
+ email_body = part.get_payload(decode=True).decode('utf-8')
247
+ break
248
+ else:
249
+ email_body = email_message.get_payload(decode=True).decode('utf-8')
250
+ # print(email_body)
251
+ extracted_details_str = get_details(email_body)
252
+ # print('extracted mail info',type(extracted_details_str))
253
+ extracted_details = json.loads(extracted_details_str)
254
+ # print(extracted_details)
255
+ # print('loaded json data type',type(extracted_details))
256
+ # Combine metadata and extracted details
257
+ meta_data = {
258
+ 'sender': sender,
259
+ 'receiver': receiver,
260
+ 'cc': cc,
261
+ 'bcc': bcc,
262
+ 'subject': subject
263
+ }
264
+ print('meta_data',type(meta_data))
265
+ extracted_details.update(meta_data)
266
+
267
+ print('full data about email ! ...::',extracted_details)
268
+ insert_data(extracted_details)
269
+ print('email analysed succesfully !\n')
270
+ except Exception as e:
271
+ print(f"Error processing email ID {message_id}: {e}")
272
+
273
+ # Close the connection
274
+ mail.close()
275
+ mail.logout()
276
+
277
+ except Exception as e:
278
+ print(f"Error reading emails: {e}")
279
+
280
+
281
+ # Background loop for continuous email extraction
282
+ def email_processing_loop():
283
+ global running
284
+ while running:
285
+ try:
286
+ read_email()
287
+ print("Emails processed")
288
+ except Exception as e:
289
+ print(f"Error in email processing: {e}")
290
+ time.sleep(60) # Check emails every minute
291
+
292
+ # HTML content embedded directly in app.py using Jinja2-style templating
293
+ html_content = """
294
+ <!DOCTYPE html>
295
+ <html lang="en">
296
+ <head>
297
+ <meta charset="UTF-8">
298
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
299
+ <title>Email Processing</title>
300
+ <style>
301
+ body { font-family: Arial, sans-serif; margin: 50px; }
302
+ h1 { color: #333; }
303
+ button {
304
+ padding: 10px 20px;
305
+ margin: 10px;
306
+ background-color: #4CAF50;
307
+ color: white;
308
+ border: none;
309
+ cursor: pointer;
310
+ }
311
+ button.stop { background-color: #f44336; }
312
+ </style>
313
+ </head>
314
+ <body>
315
+ <h1>Email Processing Status: {{ status }}</h1>
316
+
317
+ <!-- Display status -->
318
+ <button onclick="window.location.href='/start'">Start Processing</button>
319
+ <button class="stop" onclick="window.location.href='/stop'">Stop Processing</button>
320
+ </body>
321
+ </html>
322
+ """
323
+
324
+ # Endpoint to display the home page with the email processor's status
325
  @app.get("/", response_class=HTMLResponse)
326
+ async def home():
327
+ global running
328
+ status = "Running" if running else "Stopped"
329
+ return HTMLResponse(content=html_content.replace("{{ status }}", status), status_code=200)
330
+
331
+ # Endpoint to start the email processing loop
332
+ @app.get("/start", response_class=HTMLResponse)
333
+ async def start_processing():
334
+ global running
335
+ if not running:
336
+ running = True
337
+ threading.Thread(target=email_processing_loop, daemon=True).start()
338
+ status = "Running"
339
+ return HTMLResponse(content=html_content.replace("{{ status }}", status), status_code=200)
340
+
341
+ # Endpoint to stop the email processing loop
342
+ @app.get("/stop", response_class=HTMLResponse)
343
+ async def stop_processing():
344
+ global running
345
+ running = False
346
+ status = "Stopped"
347
+ return HTMLResponse(content=html_content.replace("{{ status }}", status), status_code=200)
348
+
349
+ # Start the email processing loop when the app runs
350
+ if __name__ == "__main__":
351
+ # running = True
352
+ # threading.Thread(target=email_processing_loop, daemon=True).start()
353
+ import uvicorn
354
+ uvicorn.run()