Rsnarsna commited on
Commit
9fcc753
·
verified ·
1 Parent(s): 58bbec4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -135
app.py CHANGED
@@ -8,6 +8,8 @@ import email, imaplib, json, time
8
  import torch, logging
9
  import uvicorn
10
  from pydantic import BaseModel
 
 
11
 
12
  app = FastAPI()
13
 
@@ -16,18 +18,14 @@ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(
16
  logger = logging.getLogger(__name__)
17
 
18
  # Email and database configuration
19
- IMAP_SERVER = 'imap.gmail.com'
20
- EMAIL_ADDRESS = '[email protected]'
21
- PASSWORD = 'gclc wsnx kywt uvqy ' # Store this securely in production
22
  DB_CONFIG = {
23
  'host': '0.tcp.in.ngrok.io',
24
- 'port': 11329,
25
  'user': 'root',
26
- 'password': '', # Add the correct password
27
  'database': 'shipment_details'
28
- }
29
 
30
- # JSON format for extracted shipment details
31
  output_format = {
32
  "origin": "",
33
  "destination": "",
@@ -37,26 +35,25 @@ output_format = {
37
  "Description": "",
38
  "Quantities": "",
39
  "Carrier_details": ""
40
- }
41
 
42
- # Prompt for LLM to process shipment-related emails
43
- prompt = """
44
  System prompt: You will be provided with an email containing shipment details. Your task is to extract specific information based on the given instructions.
45
 
46
  Instructions:
47
- 1. Focus only on extracting details about future shipments, ignore irrelevant information.
48
- 2. Output should be in JSON format. Missing information should be marked as null.
49
- 3. Extract the following:
50
- - origin
51
- - destination
52
- - expected_shipment_datetime (format: yyyy-mm-dd hh:mm:ss)
53
- - types_of_service (AIR, LCL, FCL)
54
- - warehouse
55
- - description (max 100 words)
56
- - quantities
57
- - carrier_details
58
- 4. The output should be formatted as follows:
59
- {
60
  "origin": "",
61
  "destination": "",
62
  "expected_shipment_datetime": "",
@@ -65,9 +62,68 @@ Instructions:
65
  "description": "",
66
  "quantities": "",
67
  "carrier_details": ""
68
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  """
70
 
 
71
  # Function to insert extracted shipment details into MySQL database
72
  def insert_data(extracted_details):
73
  try:
@@ -116,87 +172,51 @@ def insert_data(extracted_details):
116
  logger.error(f"Database error: {db_err}")
117
  except Exception as ex:
118
  logger.error(f"Error inserting data: {ex}")
 
 
119
 
120
- # Function to extract shipment details using an LLM
121
- def get_details(mail):
122
- try:
123
- # Initialize LLM model and tokenizer
124
- # Uncomment below if using Hugging Face models, or load your specific model accordingly
125
- # pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
126
- # output = pipe(f"{prompt}\n{mail}", max_new_tokens=200)
127
-
128
- # Using Llama model for completion
129
- llm = Llama(model_path="./ggml-model-q8_0.gguf", n_ctx=2048, n_batch=512)
130
- response = llm.create_chat_completion(
131
- messages=[
132
- {"role": "system", "content": prompt},
133
- {"role": "user", "content": mail}
134
- ],
135
- max_tokens=200
136
- )
137
- return response['choices'][0]['message']['content']
138
-
139
- except Exception as ex:
140
- logger.error(f"Error generating details from LLM: {ex}")
141
- return None
142
-
143
- # Function to read and process unread emails
144
  def read_email():
145
- logging.info('ready to read email ! ...')
146
  try:
147
- logging.info('get imap server!')
148
- mail = imaplib.IMAP4_SSL(IMAP_SERVER)
149
- mail.login(EMAIL_ADDRESS, PASSWORD)
150
- mail.select('inbox')
151
- logging.info('select mail inbox')
152
- status, messages = mail.search(None, 'UNSEEN')
153
- message_ids = messages[0].split()
154
- logging.info(f"Total unread emails: {len(message_ids)}")
155
- print(f"Total unread emails: {len(message_ids)}")
156
-
157
- for message_id in message_ids:
158
  try:
159
- status, data = mail.fetch(message_id, '(RFC822)')
160
- raw_email = data[0][1]
161
- email_message = email.message_from_bytes(raw_email)
162
-
163
- # Extract metadata
164
- sender = email_message['From']
165
- receiver = email_message['To']
166
- cc = email_message.get('Cc', '')
167
- bcc = email_message.get('Bcc', '')
168
- subject = email_message['Subject']
 
 
169
 
170
- # Extract email body
171
- if email_message.is_multipart():
172
- for part in email_message.walk():
173
- if part.get_content_type() == 'text/plain':
174
- email_body = part.get_payload(decode=True).decode('utf-8')
175
- break
176
- else:
177
- email_body = email_message.get_payload(decode=True).decode('utf-8')
178
-
179
- # Extract and store details
180
- extracted_details_str = get_details(email_body)
181
- extracted_details = json.loads(extracted_details_str)
182
  meta_data = {
183
- 'sender': sender, 'receiver': receiver, 'cc': cc, 'bcc': bcc, 'subject': subject
 
 
 
 
184
  }
 
185
  extracted_details.update(meta_data)
 
 
186
  insert_data(extracted_details)
187
 
188
  except Exception as e:
189
- logger.error(f"Error processing email {message_id}: {e}")
190
-
191
- mail.close()
192
- mail.logout()
193
-
194
  except Exception as e:
195
- logger.error(f"Error reading emails: {e}")
196
 
197
- # Email processing loop
 
198
  running = False
199
- loop_thread = None
200
 
201
  # HTML content for the web interface
202
  html_content = """
@@ -218,28 +238,38 @@ html_content = """
218
  cursor: pointer;
219
  }
220
  button.stop { background-color: #f44336; }
 
221
  </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  </head>
223
  <body>
224
- <h1>Email Processing Status: {{ status }}</h1>
 
 
225
  </body>
226
  </html>
227
  """
228
 
229
- class ActionModel(BaseModel):
230
- action: str # 'start' or 'stop'
231
-
232
- class ModelData(BaseModel):
233
- data: str # Additional email-related information
234
-
235
  # Function to process emails in a loop
236
  def email_processing_loop():
237
  global running
238
- logger.info("Starting email processing loop...")
239
- while running:
240
- # read_email() # Assuming this is your email processing function
241
- print("$"*100)
242
- time.sleep(10) # Check for new emails every 10 seconds
243
 
244
  # Endpoint to display the current email processor status
245
  @app.get("/", response_class=HTMLResponse)
@@ -247,40 +277,34 @@ async def home():
247
  global running
248
  status = "Running" if running else "Stopped"
249
  return HTMLResponse(content=html_content.replace("{{ status }}", status), status_code=200)
250
- async def control_email_loop(action: ActionModel, data: ModelData):
 
 
 
251
  global running, loop_thread
252
- logger.info(action.action)
253
-
254
- if action.action == "start":
255
- if not running:
256
- running = True
257
- email_data = data.data # This is already a string, no need to call .dict()
258
- logger.info(f"Email Data: {email_data}")
259
- loop_thread = threading.Thread(target=email_processing_loop, daemon=True)
260
- loop_thread.start()
261
- logger.info("Email processing loop started.")
262
- else:
263
- logger.info("Email processing loop is already running.")
264
-
265
- elif action.action == "stop":
266
- if running:
267
- running = False
268
- logger.info("Email processing loop stopped.")
269
- else:
270
- logger.info("Email processing loop is not running.")
271
-
272
  else:
273
- raise HTTPException(status_code=400, detail="Invalid action. Use 'start' or 'stop'.")
274
-
275
- status = "Running" if running else "Stopped"
276
- return HTMLResponse(content=html_content.replace("{{ status }}", status), status_code=200)
277
 
 
 
 
 
 
 
 
 
 
 
278
 
279
  if __name__ == "__main__":
280
-
281
- print('starting')
282
- logging.info('starting project!...')
283
- # running = True
284
- # threading.Thread(target=email_processing_loop, daemon=True).start()
285
- logging.info('...')
286
- uvicorn.run()
 
8
  import torch, logging
9
  import uvicorn
10
  from pydantic import BaseModel
11
+ import pandas as pd
12
+ from llama_cpp import Llama
13
 
14
  app = FastAPI()
15
 
 
18
  logger = logging.getLogger(__name__)
19
 
20
  # Email and database configuration
 
 
 
21
  DB_CONFIG = {
22
  'host': '0.tcp.in.ngrok.io',
23
+ 'port': 14458,
24
  'user': 'root',
25
+ 'password': '',
26
  'database': 'shipment_details'
27
+ }
28
 
 
29
  output_format = {
30
  "origin": "",
31
  "destination": "",
 
35
  "Description": "",
36
  "Quantities": "",
37
  "Carrier_details": ""
38
+ }
39
 
40
+ prompt = f"""
 
41
  System prompt: You will be provided with an email containing shipment details. Your task is to extract specific information based on the given instructions.
42
 
43
  Instructions:
44
+ 1. The input email may contain irrelevant information. Focus only on extracting details about future shipments.
45
+ 2. The output should be in JSON format. If a type of information is not found, it should be marked as null.
46
+ 3. Extract the following information:
47
+ - origin: The origin location of the consignment.
48
+ - destination: The destination location of the consignment.
49
+ - expected_shipment_datetime: The expected date and time of delivery to the warehouse (format: yyyy-mm-dd hh:mm:ss).
50
+ - 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.
51
+ - warehouse: The name of the warehouse.
52
+ - description: A brief description of the email (ASN).
53
+ - quantities: The number of items in the shipment.
54
+ - carrier_details: The details of the carrier.
55
+ 4. the output extracted information contains must be in this format:
56
+ {{
57
  "origin": "",
58
  "destination": "",
59
  "expected_shipment_datetime": "",
 
62
  "description": "",
63
  "quantities": "",
64
  "carrier_details": ""
65
+ }}
66
+ Examples:
67
+
68
+ 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.
69
+ Extracted Information:
70
+ origin: Hamburg,
71
+ destination: New York,
72
+ expected_shipment_datetime: 2024-08-15 00:00:000,
73
+ types_of_service: AIR,
74
+ warehouse: Sky Logistics,
75
+ 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.,
76
+ quantities: 200 units,
77
+ carrier_details: Sky Logistics
78
+
79
+ 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.
80
+ Extracted Information:
81
+ origin: Shanghai,
82
+ destination: Los Angeles,
83
+ expected_shipment_datetime: 2024-07-30 00:00:0000,
84
+ types_of_service: LCL,
85
+ warehouse: Ocean Freight Co.,
86
+ 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.,
87
+ quantities: 500 pieces,
88
+ carrier_details: Ocean Freight Co.
89
+
90
+ 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.
91
+ Extracted Information:
92
+ origin: Mumbai,
93
+ destination: London,
94
+ expected_shipment_datetime: 2024-08-22 00:00:00000,
95
+ types_of_service: null,
96
+ warehouse: Global Carriers,
97
+ description: A new shipment is on its way from Mumbai to London, scheduled to reach by August 22, 2024.,
98
+ quantities: 150 pieces,
99
+ carrier_details: Global Carriers
100
+
101
+ 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.
102
+ Extracted Information:
103
+ origin: Tokyo,
104
+ destination: Sydney,
105
+ expected_shipment_datetime: 2024-09-10 00:00:0000,
106
+ types_of_service: AIR,
107
+ warehouse: Jet Logistics,
108
+ description: We are notifying you about a shipment dispatched from Tokyo, heading towards Sydney, with an estimated arrival date of September 10, 2024.,
109
+ quantities: 350 units,
110
+ carrier_details: Jet Logistics
111
+
112
+ 5. Email: Just a reminder about our meeting the day after at 10 AM.
113
+ Extracted Information:
114
+ origin: null,
115
+ destination: null,
116
+ expected_shipment_datetime: 0000-00-00 10:00:0000,
117
+ types_of_service: null,
118
+ warehouse: null,
119
+ description: Just a reminder about our meeting the day after at 10 AM.,
120
+ quantities: null,
121
+ carrier_details: null
122
+
123
+ Output: {output_format}
124
  """
125
 
126
+
127
  # Function to insert extracted shipment details into MySQL database
128
  def insert_data(extracted_details):
129
  try:
 
172
  logger.error(f"Database error: {db_err}")
173
  except Exception as ex:
174
  logger.error(f"Error inserting data: {ex}")
175
+
176
+ llm = Llama(model_path='./ggml-model-f16.gguf', n_ctx=2048, n_batch=2048, n_threads= 204)
177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  def read_email():
 
179
  try:
180
+ df = pd.read_csv('./emails.csv')
181
+ for i in df['Body']:
 
 
 
 
 
 
 
 
 
182
  try:
183
+ prompt_ = f"<s>system:{prompt}<|end|><s>user:{i}<|end|><s>assistant:"
184
+ output = llm(prompt_, max_tokens=1000, temperature=0.1)
185
+ print("*"*50)
186
+ t = output['choices'][0]['text']
187
+ print('input : ',i)
188
+ print('output : ',t)
189
+ t = t[t.find('{\n'):t.find('}\n')+1]
190
+ print('json data : ', t)
191
+ extracted_details = json.loads(t)
192
+ print('extracted json : ',type(extracted_details))
193
+ print(type(extracted_details))
194
+ print('_'*50)
195
 
196
+ # print(extracted_details)
197
+ print(type(extracted_details))
 
 
 
 
 
 
 
 
 
 
198
  meta_data = {
199
+ 'sender': 'sender',
200
+ 'receiver': 'receiver',
201
+ 'cc': 'cc',
202
+ 'bcc': 'bcc',
203
+ 'subject': 'subject'
204
  }
205
+ # print(type(meta_data))
206
  extracted_details.update(meta_data)
207
+
208
+ print('full data about email ! ...::',extracted_details)
209
  insert_data(extracted_details)
210
 
211
  except Exception as e:
212
+ print(f"Error processing email ID {i}: {e}")
 
 
 
 
213
  except Exception as e:
214
+ print(f"Error reading csv emails: {e}")
215
 
216
+
217
+ # Global variables
218
  running = False
219
+ loop_thread = None
220
 
221
  # HTML content for the web interface
222
  html_content = """
 
238
  cursor: pointer;
239
  }
240
  button.stop { background-color: #f44336; }
241
+ #status { font-weight: bold; }
242
  </style>
243
+ <script>
244
+ async function startLoop() {
245
+ const response = await fetch('/start', { method: 'POST' });
246
+ const result = await response.text();
247
+ document.getElementById("status").innerHTML = result;
248
+ }
249
+
250
+ async function stopLoop() {
251
+ const response = await fetch('/stop', { method: 'POST' });
252
+ const result = await response.text();
253
+ document.getElementById("status").innerHTML = result;
254
+ }
255
+ </script>
256
  </head>
257
  <body>
258
+ <h1>Email Processing Status: <span id="status">{{ status }}</span></h1>
259
+ <button onclick="startLoop()">Start</button>
260
+ <button class="stop" onclick="stopLoop()">Stop</button>
261
  </body>
262
  </html>
263
  """
264
 
 
 
 
 
 
 
265
  # Function to process emails in a loop
266
  def email_processing_loop():
267
  global running
268
+ logging.info("Starting email processing loop...")
269
+ data = read_email()
270
+ print("$" * 100) # Simulate email processing
271
+ time.sleep(10) # Check for new emails every 10 seconds
272
+ return data
273
 
274
  # Endpoint to display the current email processor status
275
  @app.get("/", response_class=HTMLResponse)
 
277
  global running
278
  status = "Running" if running else "Stopped"
279
  return HTMLResponse(content=html_content.replace("{{ status }}", status), status_code=200)
280
+
281
+ # Endpoint to start the email processing loop
282
+ @app.post("/start")
283
+ async def start_email_loop():
284
  global running, loop_thread
285
+ if not running:
286
+ running = True
287
+ # loop_thread = threading.Thread(target=email_processing_loop, daemon=True)
288
+ # loop_thread.start()
289
+ logging.info("Email processing loop started.")
290
+ data = email_processing_loop()
291
+ return "Running \n\n"+ data
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  else:
293
+ return "Already running \n\n"+data
 
 
 
294
 
295
+ # Endpoint to stop the email processing loop
296
+ @app.post("/stop")
297
+ async def stop_email_loop():
298
+ global running
299
+ if running:
300
+ running = False
301
+ logging.info("Email processing loop stopped.")
302
+ return "Stopped"
303
+ else:
304
+ return "Already stopped"
305
 
306
  if __name__ == "__main__":
307
+ logging.basicConfig(level=logging.INFO)
308
+ logging.info("Starting FastAPI server...")
309
+ import uvicorn
310
+ uvicorn.run(app, host="0.0.0.0", port=8000)