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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -160
app.py CHANGED
@@ -8,7 +8,6 @@ import email, imaplib, json, time
8
  import torch, logging
9
  import uvicorn
10
  from pydantic import BaseModel
11
- import pandas as pd
12
 
13
  app = FastAPI()
14
 
@@ -17,14 +16,18 @@ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(
17
  logger = logging.getLogger(__name__)
18
 
19
  # Email and database configuration
 
 
 
20
  DB_CONFIG = {
21
  'host': '0.tcp.in.ngrok.io',
22
- 'port': 19266,
23
  'user': 'root',
24
- 'password': '',
25
  'database': 'shipment_details'
26
- }
27
 
 
28
  output_format = {
29
  "origin": "",
30
  "destination": "",
@@ -34,25 +37,26 @@ output_format = {
34
  "Description": "",
35
  "Quantities": "",
36
  "Carrier_details": ""
37
- }
38
 
39
- prompt = f"""
 
40
  System prompt: You will be provided with an email containing shipment details. Your task is to extract specific information based on the given instructions.
41
 
42
  Instructions:
43
- 1. The input email may contain irrelevant information. Focus only on extracting details about future shipments.
44
- 2. The output should be in JSON format. If a type of information is not found, it should be marked as null.
45
- 3. Extract the following information:
46
- - origin: The origin location of the consignment.
47
- - destination: The destination location of the consignment.
48
- - expected_shipment_datetime: The expected date and time of delivery to the warehouse (format: yyyy-mm-dd hh:mm:ss).
49
- - 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.
50
- - warehouse: The name of the warehouse.
51
- - description: A brief description of the email (ASN).
52
- - quantities: The number of items in the shipment.
53
- - carrier_details: The details of the carrier.
54
- 4. the output extracted information contains must be in this format:
55
- {{
56
  "origin": "",
57
  "destination": "",
58
  "expected_shipment_datetime": "",
@@ -61,68 +65,9 @@ Instructions:
61
  "description": "",
62
  "quantities": "",
63
  "carrier_details": ""
64
- }}
65
- Examples:
66
-
67
- 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.
68
- Extracted Information:
69
- origin: Hamburg,
70
- destination: New York,
71
- expected_shipment_datetime: 2024-08-15 00:00:000,
72
- types_of_service: AIR,
73
- warehouse: Sky Logistics,
74
- 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.,
75
- quantities: 200 units,
76
- carrier_details: Sky Logistics
77
-
78
- 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.
79
- Extracted Information:
80
- origin: Shanghai,
81
- destination: Los Angeles,
82
- expected_shipment_datetime: 2024-07-30 00:00:0000,
83
- types_of_service: LCL,
84
- warehouse: Ocean Freight Co.,
85
- 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.,
86
- quantities: 500 pieces,
87
- carrier_details: Ocean Freight Co.
88
-
89
- 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.
90
- Extracted Information:
91
- origin: Mumbai,
92
- destination: London,
93
- expected_shipment_datetime: 2024-08-22 00:00:00000,
94
- types_of_service: null,
95
- warehouse: Global Carriers,
96
- description: A new shipment is on its way from Mumbai to London, scheduled to reach by August 22, 2024.,
97
- quantities: 150 pieces,
98
- carrier_details: Global Carriers
99
-
100
- 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.
101
- Extracted Information:
102
- origin: Tokyo,
103
- destination: Sydney,
104
- expected_shipment_datetime: 2024-09-10 00:00:0000,
105
- types_of_service: AIR,
106
- warehouse: Jet Logistics,
107
- description: We are notifying you about a shipment dispatched from Tokyo, heading towards Sydney, with an estimated arrival date of September 10, 2024.,
108
- quantities: 350 units,
109
- carrier_details: Jet Logistics
110
-
111
- 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.
112
- Extracted Information:
113
- origin: Berlin,
114
- destination: Toronto,
115
- expected_shipment_datetime: null,
116
- types_of_service: LCL,
117
- warehouse: Sea Wave Transport,
118
- description: Kindly note the details of a forthcoming shipment from Berlin to Toronto. The expected arrival is on August 5, 2024.,
119
- quantities: 400 items,
120
- carrier_details: Sea Wave Transport
121
-
122
- Output: {output_format}
123
  """
124
 
125
-
126
  # Function to insert extracted shipment details into MySQL database
127
  def insert_data(extracted_details):
128
  try:
@@ -172,50 +117,86 @@ def insert_data(extracted_details):
172
  except Exception as ex:
173
  logger.error(f"Error inserting data: {ex}")
174
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  # Function to read and process unread emails
176
  def read_email():
177
  logging.info('ready to read email ! ...')
178
  try:
179
- tokenizer = AutoTokenizer.from_pretrained("microsoft/Phi-3-mini-128k-instruct", trust_remote_code=True, cache_dir='./phi3_mini')
180
-
181
- # Load the model
182
- model = AutoModelForCausalLM.from_pretrained(
183
- "microsoft/Phi-3-mini-128k-instruct",
184
- load_in_8bit=True,
185
- device_map="auto", # Automatically map layers to available device (GPU/CPU)
186
- trust_remote_code=True,
187
- cache_dir='./phi3_mini'
188
- )
189
-
190
- df = pd.read_csv('emails.csv')
191
-
192
- for i in df['Body']:
193
- pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
194
- prompt_ = f"\n[system]:{prompt}\n[User]: {i}\n[Assistant]:"
195
- output = pipe(prompt_, max_new_tokens=200, )
196
- print('*'*10,i,'\n')
197
- a = output[0]['generated_text']
198
- t = a[a.find('[Assistant]:')+len('[Assistant]:') :]
199
- jon = t[:t.find('\n}\n')+len('\n}\n')]
200
- jon = json.loads(jon)
201
- # print(type(jon),'\n',jon)
202
- meta_data = {
203
- 'sender': 'sender',
204
- 'receiver': 'receiver',
205
- 'cc': 'cc',
206
- 'bcc': 'bcc',
207
- 'subject': 'subject'
208
- }
209
- jon.update(meta_data)
210
- print(jon)
211
- insert_data(jon)
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
  except Exception as e:
214
  logger.error(f"Error reading emails: {e}")
215
 
216
- # Global variables
217
  running = False
218
- loop_thread = None
219
 
220
  # HTML content for the web interface
221
  html_content = """
@@ -237,37 +218,28 @@ html_content = """
237
  cursor: pointer;
238
  }
239
  button.stop { background-color: #f44336; }
240
- #status { font-weight: bold; }
241
  </style>
242
- <script>
243
- async function startLoop() {
244
- const response = await fetch('/start', { method: 'POST' });
245
- const result = await response.text();
246
- document.getElementById("status").innerHTML = result;
247
- }
248
-
249
- async function stopLoop() {
250
- const response = await fetch('/stop', { method: 'POST' });
251
- const result = await response.text();
252
- document.getElementById("status").innerHTML = result;
253
- }
254
- </script>
255
  </head>
256
  <body>
257
- <h1>Email Processing Status: <span id="status">{{ status }}</span></h1>
258
- <button onclick="startLoop()">Start</button>
259
- <button class="stop" onclick="stopLoop()">Stop</button>
260
  </body>
261
  </html>
262
  """
263
 
 
 
 
 
 
 
264
  # Function to process emails in a loop
265
  def email_processing_loop():
266
  global running
267
- logging.info("Starting email processing loop...")
268
- read_email()
269
- print("$" * 100) # Simulate email processing
270
- time.sleep(10) # Check for new emails every 10 seconds
 
271
 
272
  # Endpoint to display the current email processor status
273
  @app.get("/", response_class=HTMLResponse)
@@ -275,33 +247,40 @@ async def home():
275
  global running
276
  status = "Running" if running else "Stopped"
277
  return HTMLResponse(content=html_content.replace("{{ status }}", status), status_code=200)
278
-
279
- # Endpoint to start the email processing loop
280
- @app.post("/start")
281
- async def start_email_loop():
282
  global running, loop_thread
283
- if not running:
284
- running = True
285
- loop_thread = threading.Thread(target=email_processing_loop, daemon=True)
286
- loop_thread.start()
287
- logging.info("Email processing loop started.")
288
- return "Running"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  else:
290
- return "Already running"
 
 
 
291
 
292
- # Endpoint to stop the email processing loop
293
- @app.post("/stop")
294
- async def stop_email_loop():
295
- global running
296
- if running:
297
- running = False
298
- logging.info("Email processing loop stopped.")
299
- return "Stopped"
300
- else:
301
- return "Already stopped"
302
 
303
  if __name__ == "__main__":
304
- logging.basicConfig(level=logging.INFO)
305
- logging.info("Starting FastAPI server...")
306
- import uvicorn
307
- uvicorn.run(app, host="0.0.0.0", port=8000)
 
 
 
 
8
  import torch, logging
9
  import uvicorn
10
  from pydantic import BaseModel
 
11
 
12
  app = FastAPI()
13
 
 
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
  "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
  "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:
 
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
  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
  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()