AIEmailAutomationUtility 0.0.21__py3-none-any.whl → 0.0.22__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- AIEmailAutomationUtility/Email_Read.py +334 -625
- AIEmailAutomationUtility/Process_Category.py +824 -0
- AIEmailAutomationUtility/__init__.py +1 -0
- {AIEmailAutomationUtility-0.0.21.dist-info → AIEmailAutomationUtility-0.0.22.dist-info}/METADATA +3 -3
- {AIEmailAutomationUtility-0.0.21.dist-info → AIEmailAutomationUtility-0.0.22.dist-info}/RECORD +8 -7
- {AIEmailAutomationUtility-0.0.21.dist-info → AIEmailAutomationUtility-0.0.22.dist-info}/LICENCE.txt +0 -0
- {AIEmailAutomationUtility-0.0.21.dist-info → AIEmailAutomationUtility-0.0.22.dist-info}/WHEEL +0 -0
- {AIEmailAutomationUtility-0.0.21.dist-info → AIEmailAutomationUtility-0.0.22.dist-info}/top_level.txt +0 -0
@@ -1,25 +1,25 @@
|
|
1
1
|
import imaplib
|
2
2
|
import email
|
3
|
-
import os
|
4
|
-
import json
|
5
3
|
import time
|
6
4
|
import loggerutility as logger
|
7
|
-
from flask import request
|
8
|
-
import traceback
|
9
|
-
from fpdf import FPDF
|
10
|
-
from openai import OpenAI
|
11
|
-
import requests
|
12
|
-
import openai
|
13
|
-
import google.generativeai as genai
|
14
5
|
from datetime import datetime
|
15
6
|
|
7
|
+
import threading
|
8
|
+
import traceback
|
9
|
+
import json
|
10
|
+
import os
|
11
|
+
import csv
|
12
|
+
|
16
13
|
from .Save_Transaction import Save_Transaction
|
17
|
-
from .Email_Upload_Document import Email_Upload_Document
|
18
14
|
from .Email_Classification import Email_Classification
|
19
15
|
from .EmailReplyAssistant import EmailReplyAssistant
|
20
|
-
from .
|
21
|
-
|
22
|
-
import
|
16
|
+
from .Process_Category import Process_Category
|
17
|
+
|
18
|
+
import re
|
19
|
+
from email.utils import parseaddr
|
20
|
+
from email.header import decode_header
|
21
|
+
|
22
|
+
shared_status = True
|
23
23
|
|
24
24
|
class Email_Read:
|
25
25
|
def read_email(self, email_config):
|
@@ -50,7 +50,6 @@ class Email_Read:
|
|
50
50
|
if status == 'OK':
|
51
51
|
raw_email = data[0][1]
|
52
52
|
msg = email.message_from_bytes(raw_email)
|
53
|
-
|
54
53
|
sender_email = msg['From']
|
55
54
|
cc_email = msg['CC']
|
56
55
|
subject = msg['Subject']
|
@@ -88,10 +87,8 @@ class Email_Read:
|
|
88
87
|
except Exception as close_error:
|
89
88
|
logger.log(f"Error during mail close/logout: {str(close_error)}")
|
90
89
|
|
91
|
-
def read_email_automation(self, email_config):
|
92
|
-
# try:
|
90
|
+
def read_email_automation(self, email_config,user_id):
|
93
91
|
logger.log(f"inside read_email_automation")
|
94
|
-
# logger.log(f"email_config ::: {email_config}")
|
95
92
|
LABEL = "Unprocessed_Email"
|
96
93
|
file_JsonArray = []
|
97
94
|
templateName = "ai_email_automation.json"
|
@@ -103,177 +100,132 @@ class Email_Read:
|
|
103
100
|
host = email_config.get('host', '')
|
104
101
|
port = email_config.get('port', '')
|
105
102
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
103
|
+
try:
|
104
|
+
mail = imaplib.IMAP4_SSL(host, port)
|
105
|
+
mail.login(reciever_email_addr, receiver_email_pwd)
|
106
|
+
logger.log("login successfully")
|
107
|
+
login_status = "Success"
|
108
|
+
mail.select('inbox')
|
109
|
+
|
110
|
+
file_JsonArray, categories = self.read_JSON_File(templateName)
|
111
|
+
|
112
|
+
except Exception as e:
|
113
|
+
logger.log(f"Login failed: {e}")
|
114
|
+
|
115
|
+
# Log the result
|
116
|
+
self.log_email_login(user_id, reciever_email_addr, Model_Name, login_status)
|
112
117
|
|
113
118
|
while True:
|
114
|
-
|
115
|
-
emails = []
|
116
|
-
|
117
|
-
if status == 'OK':
|
118
|
-
email_ids = email_ids[0].split()
|
119
|
+
shared_status = self.read_status()
|
119
120
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
else:
|
121
|
+
if shared_status:
|
122
|
+
status, email_ids = mail.search(None, 'UNSEEN')
|
123
|
+
emails = []
|
124
124
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
125
|
+
if status == 'OK':
|
126
|
+
email_ids = email_ids[0].split()
|
127
|
+
|
128
|
+
if not email_ids:
|
129
|
+
logger.log("Email not found, going to check new mail")
|
130
|
+
logger.log("Email not found,\ngoing to check new mail \n")
|
131
|
+
else:
|
132
|
+
|
133
|
+
for email_id in email_ids:
|
134
|
+
email_body = ""
|
135
|
+
attachments = []
|
136
|
+
# status, data = mail.fetch(email_id, '(RFC822)')
|
137
|
+
status, data = mail.fetch(email_id, '(RFC822 UID)') # Fetch UID as well
|
138
|
+
emailCategory = "Not Classified"
|
133
139
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
subject = msg['Subject']
|
140
|
+
if status == 'OK':
|
141
|
+
raw_email = data[0][1]
|
142
|
+
msg = email.message_from_bytes(raw_email)
|
138
143
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
email_body = msg.get_payload(decode=True).decode('utf-8', errors='replace')
|
146
|
-
|
147
|
-
openai_Process_Input = email_body
|
148
|
-
logger.log(f"\nEmail Subject::: {subject}")
|
149
|
-
logger.log(f"\nEmail body::: {openai_Process_Input}")
|
144
|
+
subject = msg['Subject']
|
145
|
+
sender_email_addr = msg['From']
|
146
|
+
cc_email_addr = msg['CC']
|
147
|
+
subject = msg['Subject']
|
148
|
+
to_email_addr = msg.get('To', '')
|
149
|
+
|
150
150
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
151
|
+
# Extract UID
|
152
|
+
print(f" the data -----{data[0][0]}")
|
153
|
+
raw_uid = data[0][0].decode() if isinstance(data[0][0], bytes) else data[0][0]
|
154
|
+
print(f"the raw uid is ------- {raw_uid}")
|
155
|
+
uid_match = re.search(r'UID (\d+)', raw_uid)
|
156
|
+
uid = uid_match.group(1) if uid_match else "N/A"
|
157
|
+
|
158
|
+
is_html = False # Initialize is_html
|
159
|
+
|
160
|
+
if msg.is_multipart():
|
161
|
+
for part in msg.walk():
|
162
|
+
content_type = part.get_content_type()
|
163
|
+
if content_type == "text/html" and not is_html:
|
164
|
+
is_html = True # Set flag if HTML part is found
|
165
|
+
|
166
|
+
if content_type == "text/plain":
|
167
|
+
email_body += part.get_payload(decode=True).decode('utf-8', errors='replace')
|
168
|
+
|
169
|
+
else:
|
170
|
+
email_body = msg.get_payload(decode=True).decode('utf-8', errors='replace')
|
171
|
+
content_type = msg.get_content_type()
|
172
|
+
is_html = (content_type == "text/html") # Set is_html based on single-part type
|
171
173
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
174
|
+
openai_Process_Input = email_body
|
175
|
+
|
176
|
+
logger.log(f"\nEmail Subject::: {subject}")
|
177
|
+
logger.log(f"\nEmail body::: {openai_Process_Input}")
|
178
|
+
|
179
|
+
openai_api_key = email_config.get('openai_api_key', '')
|
180
|
+
geminiAI_APIKey = email_config.get('gemini_api_key', '')
|
181
|
+
signature = email_config.get('signature', '')
|
182
|
+
localAIURL = email_config.get('local_ai_url', '')
|
181
183
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
elif emailCategory == "Purchase Order":
|
224
|
-
responseMethod, parameters = self.get_JsonArray_values(emailCategory, file_JsonArray)
|
225
|
-
logger.log(f"responseMethod ::: {responseMethod}")
|
226
|
-
logger.log(f"parameters ::: {parameters}")
|
227
|
-
|
228
|
-
# Download the attachment
|
229
|
-
fileName = self.download_attachment(msg)
|
230
|
-
|
231
|
-
# Get today's date folder path
|
232
|
-
today_date = datetime.today().strftime('%Y-%m-%d')
|
233
|
-
order_folder = os.path.join("ORDERS", today_date)
|
234
|
-
|
235
|
-
if responseMethod == "Upload_Document":
|
236
|
-
if len(fileName) != 0:
|
237
|
-
email_upload_document = Email_DocumentUploader()
|
238
|
-
file_path = os.path.join(order_folder, fileName) # Correct file path
|
239
|
-
|
240
|
-
with open(file_path, "rb") as file:
|
241
|
-
response_status, restAPI_Result = email_upload_document.email_document_upload(file, parameters)
|
242
|
-
logger.log(f"email_upload_document_response ::: {restAPI_Result}")
|
243
|
-
else:
|
244
|
-
new_fileName = self.create_file_from_emailBody(email_body, sender_email_addr, parameters)
|
245
|
-
new_file_path = os.path.join(order_folder, new_fileName)
|
246
|
-
|
247
|
-
with open(new_file_path, "rb") as file:
|
248
|
-
response_status, restAPI_Result = email_upload_document.email_document_upload(file, parameters)
|
249
|
-
logger.log(f"email_upload_document_response ::: {restAPI_Result}")
|
250
|
-
|
251
|
-
if response_status == "200":
|
252
|
-
logger.log(f"Attachment uploaded successfully against Document ID: '{restAPI_Result}'.")
|
253
|
-
else:
|
254
|
-
logger.log(restAPI_Result)
|
255
|
-
|
256
|
-
else :
|
257
|
-
message = f"Invalid response method received '{responseMethod}' for category : '{emailCategory}'"
|
258
|
-
raise ValueError(message)
|
259
|
-
else:
|
260
|
-
message = f"Detected Email category not found : '{emailCategory}'"
|
261
|
-
raise ValueError(message)
|
184
|
+
if len(str(openai_Process_Input)) > 0 :
|
185
|
+
email_cat_data = {
|
186
|
+
"model_type" : Model_Name,
|
187
|
+
"openai_api_key" : openai_api_key,
|
188
|
+
"categories" : categories,
|
189
|
+
"email_body" : email_body,
|
190
|
+
"gemini_api_key" : geminiAI_APIKey,
|
191
|
+
"signature" : signature,
|
192
|
+
"local_ai_url" : localAIURL,
|
193
|
+
}
|
194
|
+
# logger.log(f"\nemail_cat_data ::: {email_cat_data}")
|
195
|
+
email_classification = Email_Classification()
|
196
|
+
emailCategory = email_classification.detect_category(email_cat_data)
|
197
|
+
emailCategory = emailCategory['message']
|
198
|
+
logger.log(f"\nDetected Email category ::: {emailCategory}")
|
199
|
+
|
200
|
+
dataValues = {
|
201
|
+
'Model_Name': Model_Name,
|
202
|
+
'file_JsonArray': file_JsonArray,
|
203
|
+
'openai_api_key': openai_api_key,
|
204
|
+
'openai_Process_Input': openai_Process_Input,
|
205
|
+
'subject': subject,
|
206
|
+
'sender_email_addr': sender_email_addr,
|
207
|
+
'cc_email_addr': cc_email_addr,
|
208
|
+
'email_body': email_body,
|
209
|
+
'email_config': email_config,
|
210
|
+
'msg': msg,
|
211
|
+
'geminiAI_APIKey': geminiAI_APIKey,
|
212
|
+
'localAIURL': localAIURL,
|
213
|
+
'signature': signature,
|
214
|
+
'LABEL': LABEL,
|
215
|
+
'mail': mail,
|
216
|
+
'email_id': email_id,
|
217
|
+
"uid": uid,
|
218
|
+
"to_email_addr": to_email_addr,
|
219
|
+
"user_id": user_id,
|
220
|
+
"is_html": is_html
|
221
|
+
}
|
222
|
+
processcategory = Process_Category()
|
223
|
+
processcategory.process_cat(emailCategory, dataValues)
|
224
|
+
|
262
225
|
time.sleep(10)
|
263
|
-
|
264
|
-
|
265
|
-
# return {"status": "Failed", "message": f"Error reading emails: {str(e)}"}
|
266
|
-
# finally:
|
267
|
-
# try:
|
268
|
-
# mail.close()
|
269
|
-
# mail.logout()
|
270
|
-
# except Exception as close_error:
|
271
|
-
# logger.log(f"Error during mail close/logout: {str(close_error)}")
|
272
|
-
# return {"status": "Failed", "message": f"Error reading emails: {str(close_error)}"}
|
273
|
-
|
274
|
-
def read_email_quotation(self, email_config):
|
226
|
+
|
227
|
+
def read_email_quotation(self, email_config,user_id):
|
275
228
|
# try:
|
276
|
-
logger.log(f"inside read_email_automation")
|
277
229
|
LABEL = "Unprocessed_Email"
|
278
230
|
file_JsonArray = []
|
279
231
|
templateName = "ai_email_automation.json"
|
@@ -285,12 +237,20 @@ class Email_Read:
|
|
285
237
|
host = email_config.get('host', '')
|
286
238
|
port = email_config.get('port', '')
|
287
239
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
240
|
+
try:
|
241
|
+
mail = imaplib.IMAP4_SSL(host, port)
|
242
|
+
mail.login(reciever_email_addr, receiver_email_pwd)
|
243
|
+
logger.log("login successfully")
|
244
|
+
login_status = "Success"
|
245
|
+
mail.select('inbox')
|
246
|
+
|
247
|
+
file_JsonArray, categories = self.read_JSON_File(templateName)
|
248
|
+
|
249
|
+
except Exception as e:
|
250
|
+
logger.log(f"Login failed: {e}")
|
251
|
+
|
252
|
+
# Log the result
|
253
|
+
self.log_email_login(user_id, reciever_email_addr, Model_Name, login_status)
|
294
254
|
|
295
255
|
while True:
|
296
256
|
status, email_ids = mail.search(None, 'UNSEEN')
|
@@ -307,7 +267,7 @@ class Email_Read:
|
|
307
267
|
for email_id in email_ids:
|
308
268
|
email_body = ""
|
309
269
|
attachments = []
|
310
|
-
status, data = mail.fetch(email_id, '(RFC822)')
|
270
|
+
status, data = mail.fetch(email_id, '(RFC822 UID)')
|
311
271
|
|
312
272
|
if status == 'OK':
|
313
273
|
raw_email = data[0][1]
|
@@ -317,14 +277,28 @@ class Email_Read:
|
|
317
277
|
sender_email_addr = msg['From']
|
318
278
|
cc_email_addr = msg['CC']
|
319
279
|
subject = msg['Subject']
|
280
|
+
to_email_addr = msg.get('To', '')
|
281
|
+
|
282
|
+
# Extract UID
|
283
|
+
raw_uid = data[0][0].decode() if isinstance(data[0][0], bytes) else data[0][0]
|
284
|
+
uid_match = re.search(r'UID (\d+)', raw_uid)
|
285
|
+
uid = uid_match.group(1) if uid_match else "N/A"
|
286
|
+
|
287
|
+
is_html = False # Initialize is_html
|
320
288
|
|
321
289
|
if msg.is_multipart():
|
322
290
|
for part in msg.walk():
|
323
291
|
content_type = part.get_content_type()
|
292
|
+
if content_type == "text/html" and not is_html:
|
293
|
+
is_html = True # Set flag if HTML part is found
|
294
|
+
|
324
295
|
if content_type == "text/plain":
|
325
296
|
email_body += part.get_payload(decode=True).decode('utf-8', errors='replace')
|
297
|
+
|
326
298
|
else:
|
327
299
|
email_body = msg.get_payload(decode=True).decode('utf-8', errors='replace')
|
300
|
+
content_type = msg.get_content_type()
|
301
|
+
is_html = (content_type == "text/html") # Set is_html based on single-part type
|
328
302
|
|
329
303
|
openai_Process_Input = email_body
|
330
304
|
logger.log(f"\nEmail Subject::: {subject}")
|
@@ -354,379 +328,33 @@ class Email_Read:
|
|
354
328
|
emailCategory = emailCategory['message']
|
355
329
|
logger.log(f"\nDetected Email category ::: {emailCategory}")
|
356
330
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
product["rate"] = None
|
382
|
-
|
383
|
-
logger.log(f"Identified products: {products}")
|
384
|
-
logger.log(f"Identified products length: {len(products)}")
|
385
|
-
quotation_draft = self.generate_quotation_draft(
|
386
|
-
customer_data,
|
387
|
-
products,
|
388
|
-
Model_Name,
|
389
|
-
openai_api_key,
|
390
|
-
geminiAI_APIKey,
|
391
|
-
localAIURL,
|
392
|
-
parameters["Customer_Assistant_Id"],
|
393
|
-
email_body,
|
394
|
-
subject,
|
395
|
-
signature
|
396
|
-
)
|
397
|
-
logger.log(f"quotation_draft ::: {quotation_draft}")
|
398
|
-
|
399
|
-
# Step 8: Send draft quotation email
|
400
|
-
email_details = {"sender":sender_email_addr, "cc":cc_email_addr, "subject":subject, "body": email_body}
|
401
|
-
email_draft = Email_Draft()
|
402
|
-
status, response = email_draft.quotation_draft_email(email_config, email_details, quotation_draft)
|
403
|
-
logger.log(f"status ::: {status}")
|
404
|
-
|
405
|
-
logger.log(f"Quotation email sent to {sender_email_addr}")
|
406
|
-
|
407
|
-
else:
|
408
|
-
logger.log(f"Marking email as UNREAD. ")
|
409
|
-
mail.store(email_id, '-FLAGS', '\\Seen')
|
410
|
-
|
411
|
-
mail.create(LABEL)
|
412
|
-
mail.copy(email_id, LABEL)
|
413
|
-
mail.store(email_id, '+FLAGS', '\\Deleted') # Mark for deletion
|
414
|
-
mail.expunge()
|
415
|
-
logger.log(f"Mail removed from inbox and added to '{LABEL}' label.")
|
331
|
+
dataValues = {
|
332
|
+
'Model_Name': Model_Name,
|
333
|
+
'file_JsonArray': file_JsonArray,
|
334
|
+
'openai_api_key': openai_api_key,
|
335
|
+
'openai_Process_Input': openai_Process_Input,
|
336
|
+
'subject': subject,
|
337
|
+
'sender_email_addr': sender_email_addr,
|
338
|
+
'cc_email_addr': cc_email_addr,
|
339
|
+
'email_body': email_body,
|
340
|
+
'email_config': email_config,
|
341
|
+
'msg': msg,
|
342
|
+
'geminiAI_APIKey': geminiAI_APIKey,
|
343
|
+
'localAIURL': localAIURL,
|
344
|
+
'signature': signature,
|
345
|
+
'LABEL': LABEL,
|
346
|
+
'mail': mail,
|
347
|
+
'email_id': email_id,
|
348
|
+
"uid": uid,
|
349
|
+
"to_email_addr": to_email_addr,
|
350
|
+
"user_id": user_id,
|
351
|
+
"is_html": is_html
|
352
|
+
}
|
353
|
+
processcategory = Process_Category()
|
354
|
+
processcategory.process_cat(emailCategory, dataValues)
|
416
355
|
|
417
356
|
time.sleep(10)
|
418
357
|
|
419
|
-
def identify_customer(self, email_body, subject, model_type, openai_api_key, gemini_api_key, local_ai_url, assistant_id):
|
420
|
-
logger.log("Inside identify_customer")
|
421
|
-
|
422
|
-
if model_type == "OpenAI":
|
423
|
-
prompt = f"""Identify the customer code, customer name in json format from the following email {email_body} and received from {subject}. Do not include any instruction as the output will be directly in a program."""
|
424
|
-
emailreplyassistant = EmailReplyAssistant()
|
425
|
-
ai_result = emailreplyassistant.identify_customer_product_reply_assitant(openai_api_key, assistant_id, email_body, subject, prompt)
|
426
|
-
|
427
|
-
elif model_type == "GeminiAI":
|
428
|
-
prompt = f"""Identify the customer code, customer name in json format from the following email {email_body} and received from {subject}. Do not include any instruction as the output will be directly in a program."""
|
429
|
-
ai_result = self.identify_customer_product_GeminiAI(gemini_api_key, email_body, prompt)
|
430
|
-
|
431
|
-
elif model_type == "LocalAI":
|
432
|
-
prompt = f"""Identify the customer code and customer name in JSON format from the following email: {email_body}, received from {subject}.
|
433
|
-
If no customer details are found, return:{{"customer_name": "","customer_code": ""}}Only return the JSON object. No explanations, no additional text."""
|
434
|
-
ai_result = self.identify_customer_product_LocalAI(openai_api_key, email_body, local_ai_url, prompt)
|
435
|
-
|
436
|
-
else:
|
437
|
-
ai_result = "{}"
|
438
|
-
|
439
|
-
customer_data = {}
|
440
|
-
if ai_result["status"] == "Success":
|
441
|
-
customer_data = json.loads(ai_result["message"])
|
442
|
-
else:
|
443
|
-
customer_data = {
|
444
|
-
"customer_name": "",
|
445
|
-
"customer_code": ""
|
446
|
-
}
|
447
|
-
return customer_data
|
448
|
-
|
449
|
-
def identify_products(self, email_body, subject, model_type, openai_api_key, gemini_api_key, local_ai_url, assistant_id):
|
450
|
-
logger.log("Inside identify_products")
|
451
|
-
|
452
|
-
if model_type == "OpenAI":
|
453
|
-
prompt = f"""
|
454
|
-
Can you give me price information of all products in following format requested_description, item_no, make, description, price, price unit, inventory unit for following items in strictly in JSON String format {email_body}.
|
455
|
-
If there is one product or multiple should return in list.
|
456
|
-
Do not include any instruction as the output will be directly in a program.
|
457
|
-
"""
|
458
|
-
emailreplyassistant = EmailReplyAssistant()
|
459
|
-
ai_result = emailreplyassistant.identify_customer_product_reply_assitant(openai_api_key, assistant_id, email_body, subject, prompt)
|
460
|
-
|
461
|
-
elif model_type == "GeminiAI":
|
462
|
-
prompt = f"""
|
463
|
-
Can you give me price information of all products in following format requested_description, item_no, make, description, price, price unit, inventory unit for following items in strictly in JSON String format {email_body}.
|
464
|
-
If there is one product or multiple should return in list.
|
465
|
-
Do not include any instruction as the output will be directly in a program.
|
466
|
-
"""
|
467
|
-
ai_result = self.identify_customer_product_GeminiAI(gemini_api_key, email_body, prompt)
|
468
|
-
|
469
|
-
elif model_type == "LocalAI":
|
470
|
-
prompt = f"""Can you give me price information in following format requested_description, item_no, make, description, price, price unit, inventory unit for following items it strictly in json format which loads directly in json {email_body}. If there is one product or multiple should return in list.
|
471
|
-
If no product details are found, return:[] Only return the JSON object. No explanations, no additional text."""
|
472
|
-
ai_result = self.identify_customer_product_LocalAI(openai_api_key, email_body, local_ai_url, prompt)
|
473
|
-
|
474
|
-
else:
|
475
|
-
ai_result = "{}"
|
476
|
-
|
477
|
-
product_data = {}
|
478
|
-
if ai_result["status"] == "Success":
|
479
|
-
logger.log(f"ai_result ::: {ai_result}")
|
480
|
-
product_data = json.loads(ai_result["message"])
|
481
|
-
else:
|
482
|
-
product_data = []
|
483
|
-
return product_data
|
484
|
-
|
485
|
-
def generate_quotation_draft(self, customer_data, products, model_type, openai_api_key, gemini_api_key, local_ai_url, assistant_id, email_body, subject, signature):
|
486
|
-
logger.log("Inside generate_quotation_draft")
|
487
|
-
|
488
|
-
customer = customer_data
|
489
|
-
|
490
|
-
product_table = "Products:\n"
|
491
|
-
for product in products:
|
492
|
-
product_table += f'- {product.get("requested_description")} (Code: {product.get("item_no")}) = ${product.get("rate")}\n'
|
493
|
-
|
494
|
-
if model_type == "OpenAI":
|
495
|
-
prompt = f"""
|
496
|
-
Generate product information in HTML tabular format with line separators for rows and columns in a draft reply based on the following information:
|
497
|
-
|
498
|
-
Customer: {customer.get('customer_name', '')}
|
499
|
-
Customer Code: {customer.get('customer_code', '')}
|
500
|
-
|
501
|
-
{product_table}
|
502
|
-
product_table must contain only price column even if it is none(set it as -).
|
503
|
-
Original Email Subject: {subject}
|
504
|
-
|
505
|
-
Return only the following JSON String format:
|
506
|
-
{{
|
507
|
-
"email_body": {{
|
508
|
-
"body": "Draft email body proper response, It should not be same like mail content and does not having any signature part like Best regards.",
|
509
|
-
"table_html": "Table Details with Sr. No. in HTML",
|
510
|
-
"signature": "{signature}"
|
511
|
-
}}
|
512
|
-
}}
|
513
|
-
|
514
|
-
Do not include signature in body and any instructions, explanations, or additional text—only the JSON object.
|
515
|
-
"""
|
516
|
-
logger.log(f"Quotation draft ::: {prompt}")
|
517
|
-
emailreplyassistant = EmailReplyAssistant()
|
518
|
-
ai_result = emailreplyassistant.create_quotation_draft(openai_api_key, assistant_id, email_body, subject, prompt)
|
519
|
-
|
520
|
-
elif model_type == "GeminiAI":
|
521
|
-
prompt = f"""
|
522
|
-
Create an HTML product information email draft with the following details:
|
523
|
-
|
524
|
-
Customer Name: {customer.get('customer_name', '')}
|
525
|
-
Customer Code: {customer.get('customer_code', '')}
|
526
|
-
|
527
|
-
Product Information:
|
528
|
-
{product_table}
|
529
|
-
Note: Include price column with a value of "-" if price is not available.
|
530
|
-
|
531
|
-
Email Subject Reference: {subject}
|
532
|
-
|
533
|
-
Please format the response as a valid JSON string with these fields:
|
534
|
-
{{
|
535
|
-
"email_body": {{
|
536
|
-
"body": "Professional email content that summarizes the product information without being identical to the input data. Do not include signature here.",
|
537
|
-
"table_": "HTML table with SR. No. column and product details",
|
538
|
-
"signature": "{signature}"
|
539
|
-
}}
|
540
|
-
}}
|
541
|
-
|
542
|
-
Ensure the JSON is properly formatted with escaped newlines (\\n) and no trailing commas. Return only the valid JSON string without additional explanations or instructions.
|
543
|
-
"""
|
544
|
-
logger.log(f"Quotation draft ::: {prompt}")
|
545
|
-
ai_result = self.create_quotation_draft_GeminiAI(gemini_api_key, email_body, prompt)
|
546
|
-
|
547
|
-
elif model_type == "LocalAI":
|
548
|
-
prompt = f"""
|
549
|
-
Generate product information in HTML tabular format with line separators for rows and columns in a draft reply based on the following information:
|
550
|
-
|
551
|
-
Customer: {customer.get('customer_name', '')}
|
552
|
-
Customer Code: {customer.get('customer_code', '')}
|
553
|
-
|
554
|
-
{product_table}
|
555
|
-
- The table must contain the **Price** column, even if it is empty (set it as `-` if None).
|
556
|
-
- The table should include **Sr. No.** as the first column.
|
557
|
-
- Format the table with `<table>`, `<tr>`, `<th>`, and `<td>` tags with some border to table.
|
558
|
-
|
559
|
-
Original Email Subject: {subject}
|
560
|
-
|
561
|
-
Return **strictly** in the following JSON String format:
|
562
|
-
- All keys must be: `body`, `table_`, and `signature` inside the `email_body` JSON.
|
563
|
-
- **Do not include** `\n`, `\`, `\\`, or any unnecessary escape characters.
|
564
|
-
- Do not include instructions, explanations, or additional text—only the JSON object.
|
565
|
-
|
566
|
-
Format:
|
567
|
-
{{
|
568
|
-
"email_body": {{
|
569
|
-
"body": "Draft email body proper response, It should not contain the table or signature.",
|
570
|
-
"table_": "Table Details with Sr. No. in HTML only",
|
571
|
-
"signature": "{signature}"
|
572
|
-
}}
|
573
|
-
}}
|
574
|
-
"""
|
575
|
-
logger.log(f"Quotation draft ::: {prompt}")
|
576
|
-
ai_result = self.create_quotation_draft_LocalAI(openai_api_key, email_body, local_ai_url, prompt)
|
577
|
-
|
578
|
-
else:
|
579
|
-
ai_result = "Error: Unable to generate quotation draft. Please check the configuration."
|
580
|
-
|
581
|
-
logger.log(f"Quotation draft ai_result::: {ai_result}")
|
582
|
-
quotation_draft_data = None
|
583
|
-
if ai_result != None:
|
584
|
-
quotation_draft_data = json.loads(ai_result)["email_body"]
|
585
|
-
return quotation_draft_data
|
586
|
-
|
587
|
-
def identify_customer_product_LocalAI(self, openai_api_key, email_body, local_ai_url, prompt):
|
588
|
-
logger.log("Inside identify_customer_product_LocalAI")
|
589
|
-
try:
|
590
|
-
message = [{
|
591
|
-
"role": "user",
|
592
|
-
"content": f"{prompt}"
|
593
|
-
}]
|
594
|
-
|
595
|
-
logger.log(f"Final Local AI message for detecting category::: {message}")
|
596
|
-
openai.api_key = openai_api_key
|
597
|
-
client = OpenAI(base_url=local_ai_url, api_key="lm-studio")
|
598
|
-
completion = client.chat.completions.create(
|
599
|
-
model="mistral",
|
600
|
-
messages=message,
|
601
|
-
temperature=0,
|
602
|
-
stream=False,
|
603
|
-
max_tokens=4096
|
604
|
-
)
|
605
|
-
|
606
|
-
final_result = str(completion.choices[0].message.content)
|
607
|
-
final_result = final_result.replace("\n```", "").replace("```", "").replace("json","").replace("JSON","").replace("csv","").replace("CSV","").replace("html","")
|
608
|
-
logger.log(f"finalResult:520 {final_result}")
|
609
|
-
return {"status": "Success", "message": final_result}
|
610
|
-
|
611
|
-
except Exception as e:
|
612
|
-
logger.log(f"Error with LocalAI detection/generation: {str(e)}")
|
613
|
-
return {"success": "Failed", "message": f"Error with LocalAI detection/generation: {str(e)}"}
|
614
|
-
|
615
|
-
def create_quotation_draft_LocalAI(self, openai_api_key, email_body, local_ai_url, prompt):
|
616
|
-
logger.log("Inside create_quotation_draft_LocalAI")
|
617
|
-
try:
|
618
|
-
message = [{
|
619
|
-
"role": "user",
|
620
|
-
"content": f"{prompt}"
|
621
|
-
}]
|
622
|
-
|
623
|
-
logger.log(f"Final Local AI message for detecting category::: {message}")
|
624
|
-
openai.api_key = openai_api_key
|
625
|
-
client = OpenAI(base_url=local_ai_url, api_key="lm-studio")
|
626
|
-
completion = client.chat.completions.create(
|
627
|
-
model="mistral",
|
628
|
-
messages=message,
|
629
|
-
temperature=0,
|
630
|
-
stream=False,
|
631
|
-
max_tokens=4096
|
632
|
-
)
|
633
|
-
|
634
|
-
final_result = str(completion.choices[0].message.content)
|
635
|
-
final_result = final_result.replace("\n```", "").replace("```", "").replace("json","").replace("JSON","").replace("csv","").replace("CSV","").replace("html","")
|
636
|
-
logger.log(f"finalResult:520 {final_result}")
|
637
|
-
return final_result
|
638
|
-
|
639
|
-
except Exception as e:
|
640
|
-
logger.log(f"Error with LocalAI detection/generation: {str(e)}")
|
641
|
-
return str(e)
|
642
|
-
|
643
|
-
def identify_customer_product_GeminiAI(self, gemini_api_key, email_body, prompt):
|
644
|
-
logger.log("Inside identify_customer_product_GeminiAI")
|
645
|
-
try:
|
646
|
-
message = [{
|
647
|
-
"role": "user",
|
648
|
-
"content": f"{prompt}"
|
649
|
-
}]
|
650
|
-
|
651
|
-
logger.log(f"Final Gemini AI message for detecting category::: {message}")
|
652
|
-
message_list = str(message)
|
653
|
-
|
654
|
-
genai.configure(api_key=gemini_api_key)
|
655
|
-
# model = genai.GenerativeModel('gemini-1.0-pro')
|
656
|
-
model = genai.GenerativeModel('gemini-1.5-pro-latest')
|
657
|
-
response = model.generate_content(message_list)
|
658
|
-
|
659
|
-
final_result = ""
|
660
|
-
for part in response:
|
661
|
-
final_result = part.text
|
662
|
-
logger.log(f"response::: {final_result}")
|
663
|
-
if final_result:
|
664
|
-
try:
|
665
|
-
final_result = final_result.replace("\\", "").replace('```', '').replace('json', '')
|
666
|
-
if final_result.startswith("{{") and final_result.endswith("}}"):
|
667
|
-
final_result = final_result[1:-1]
|
668
|
-
except json.JSONDecodeError:
|
669
|
-
logger.log(f"Exception : Invalid JSON Response GEMINI 1.5: {final_result} {type(final_result)}")
|
670
|
-
|
671
|
-
logger.log(f"finalResult::: {final_result}")
|
672
|
-
return {"status": "Success", "message": final_result}
|
673
|
-
|
674
|
-
except Exception as e:
|
675
|
-
logger.log(f"Error with Gemini AI detection/generation: {str(e)}")
|
676
|
-
return {"success": "Failed", "message": f"Error with Gemini AI detection/generation: {str(e)}"}
|
677
|
-
|
678
|
-
def create_quotation_draft_GeminiAI(self, gemini_api_key, email_body, prompt):
|
679
|
-
logger.log("Inside identify_customer_product_GeminiAI")
|
680
|
-
try:
|
681
|
-
message = [{
|
682
|
-
"role": "user",
|
683
|
-
"content": f"{prompt}"
|
684
|
-
}]
|
685
|
-
|
686
|
-
logger.log(f"Final Gemini AI message for detecting category::: {message}")
|
687
|
-
message_list = str(message)
|
688
|
-
|
689
|
-
genai.configure(api_key=gemini_api_key)
|
690
|
-
# model = genai.GenerativeModel('gemini-1.0-pro')
|
691
|
-
model = genai.GenerativeModel('gemini-1.5-pro-latest')
|
692
|
-
response = model.generate_content(message_list)
|
693
|
-
|
694
|
-
final_result = ""
|
695
|
-
for part in response:
|
696
|
-
final_result = part.text
|
697
|
-
logger.log(f"response::: {final_result}")
|
698
|
-
if final_result:
|
699
|
-
try:
|
700
|
-
final_result = final_result.replace('```', '').replace('json', '')
|
701
|
-
if final_result.startswith("{{") and final_result.endswith("}}"):
|
702
|
-
final_result = final_result[1:-1]
|
703
|
-
except json.JSONDecodeError:
|
704
|
-
logger.log(f"Exception : Invalid JSON Response GEMINI 1.5: {final_result} {type(final_result)}")
|
705
|
-
|
706
|
-
logger.log(f"finalResult::: {final_result}")
|
707
|
-
return final_result
|
708
|
-
|
709
|
-
except Exception as e:
|
710
|
-
logger.log(f"Error with Gemini AI detection/generation: {str(e)}")
|
711
|
-
return {"success": "Failed", "message": f"Error with Gemini AI detection/generation: {str(e)}"}
|
712
|
-
|
713
|
-
def save_attachment(self, part, download_dir):
|
714
|
-
try:
|
715
|
-
filename = part.get_filename()
|
716
|
-
if filename:
|
717
|
-
# Create the directory if it doesn't exist
|
718
|
-
if not os.path.exists(download_dir):
|
719
|
-
os.makedirs(download_dir)
|
720
|
-
|
721
|
-
file_path = os.path.join(download_dir, filename)
|
722
|
-
with open(file_path, 'wb') as f:
|
723
|
-
f.write(part.get_payload(decode=True))
|
724
|
-
|
725
|
-
logger.log(f"Attachment saved: {file_path}")
|
726
|
-
return file_path
|
727
|
-
except Exception as e:
|
728
|
-
return {"success": "Failed", "message": f"Error saving attachment: {str(e)}"}
|
729
|
-
|
730
358
|
def Read_Email(self, data):
|
731
359
|
try:
|
732
360
|
|
@@ -761,33 +389,144 @@ class Email_Read:
|
|
761
389
|
|
762
390
|
except Exception as e:
|
763
391
|
logger.log(f"Error in Read_Email: {str(e)}")
|
392
|
+
|
393
|
+
def extract_all_email_info(self, eml_content):
|
394
|
+
# Parse the email content
|
395
|
+
msg = email.message_from_string(eml_content)
|
396
|
+
extracted_info = {}
|
397
|
+
|
398
|
+
# Extracting To, From, and CC
|
399
|
+
extracted_info['to'] = msg.get('To')
|
400
|
+
extracted_info['from'] = msg.get('From')
|
401
|
+
extracted_info['cc'] = msg.get('Cc')
|
402
|
+
print(f"To: {extracted_info['to']}, From: {extracted_info['from']}, CC: {extracted_info['cc']}")
|
403
|
+
|
404
|
+
# Extracting subject and decoding it if necessary
|
405
|
+
subject = decode_header(msg.get('Subject', ''))[0][0]
|
406
|
+
if decode_header(msg.get('Subject', ''))[0][1]:
|
407
|
+
subject = subject.decode()
|
408
|
+
extracted_info['subject'] = subject
|
409
|
+
print(f"Subject: {extracted_info['subject']}")
|
410
|
+
|
411
|
+
# Extracting the body content (text or HTML)
|
412
|
+
text_body = None
|
413
|
+
html_body = None
|
414
|
+
if msg.is_multipart():
|
415
|
+
print("Multipart email detected.")
|
416
|
+
for part in msg.walk():
|
417
|
+
content_type = part.get_content_type()
|
418
|
+
content_disposition = str(part.get("Content-Disposition"))
|
419
|
+
print(f"Part content type: {content_type}, Content-Disposition: {content_disposition}")
|
420
|
+
|
421
|
+
if content_type == "text/plain" and "attachment" not in content_disposition:
|
422
|
+
text_body = part.get_payload(decode=True).decode()
|
423
|
+
print("Text body extracted.")
|
424
|
+
elif content_type == "text/html" and "attachment" not in content_disposition:
|
425
|
+
html_body = part.get_payload(decode=True).decode()
|
426
|
+
print("HTML body extracted.")
|
427
|
+
else:
|
428
|
+
if msg.get_content_type() == "text/plain":
|
429
|
+
text_body = msg.get_payload(decode=True).decode()
|
430
|
+
print("Text body extracted (non-multipart) .")
|
431
|
+
elif msg.get_content_type() == "text/html":
|
432
|
+
html_body = msg.get_payload(decode=True).decode()
|
433
|
+
print("HTML body extracted (non-multipart).")
|
434
|
+
|
435
|
+
extracted_info['email_body'] = text_body if text_body else html_body if html_body else None
|
436
|
+
extracted_info['is_html'] = bool(html_body)
|
437
|
+
|
438
|
+
# Extracting the date and converting it to ISO format
|
439
|
+
date_tuple = email.utils.parsedate_tz(msg.get('Date'))
|
440
|
+
print(f"date tuple is {date_tuple}")
|
441
|
+
if date_tuple:
|
442
|
+
local_date = datetime.fromtimestamp(email.utils.mktime_tz(date_tuple))
|
443
|
+
extracted_info['date'] = local_date.isoformat()
|
444
|
+
print(f"Date: {extracted_info['date']}")
|
445
|
+
else:
|
446
|
+
extracted_info['date'] = None
|
447
|
+
print("No date found.")
|
764
448
|
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
# Ensure folders exist
|
771
|
-
os.makedirs(date_folder, exist_ok=True)
|
449
|
+
# Extracting the unique ID (Message-ID)
|
450
|
+
extracted_info['unique_id'] = msg.get('Message-ID')
|
451
|
+
print(f"Unique ID: {extracted_info['unique_id']}")
|
452
|
+
print(f"-------------------------------The extracted info is --------------------------{extracted_info}")
|
772
453
|
|
773
|
-
|
454
|
+
return extracted_info,msg
|
455
|
+
|
456
|
+
def process_eml_files(self, user_id, eml_content,mail,Model_Name,email_config):
|
457
|
+
LABEL = "Unprocessed_Email"
|
458
|
+
file_JsonArray = []
|
459
|
+
templateName = "ai_email_automation.json"
|
460
|
+
fileName = ""
|
461
|
+
|
462
|
+
file_JsonArray, categories = self.read_JSON_File(templateName)
|
463
|
+
# Call the `extract_all_email_info` method to extract details from the eml content
|
464
|
+
extracted_info,msg = self.extract_all_email_info(eml_content)
|
465
|
+
|
466
|
+
# Extract the details from `extracted_info`
|
467
|
+
subject = extracted_info.get('subject', '')
|
468
|
+
sender_email_addr = extracted_info.get('from', '')
|
469
|
+
cc_email_addr = extracted_info.get('cc', '')
|
470
|
+
to_email_addr = extracted_info.get('to', '')
|
471
|
+
date = extracted_info.get('date', '')
|
472
|
+
email_body = extracted_info.get('email_body', '')
|
473
|
+
msg_id = extracted_info.get('unique_id', '')
|
474
|
+
is_html = extracted_info.get('is_html', False)
|
475
|
+
|
476
|
+
uid = re.sub(r'[<>]|\@.*|\+', '', msg_id)
|
477
|
+
logger.log(f"\nEmail Subject::: {subject}")
|
478
|
+
logger.log(f"\nEmail body::: {email_body}")
|
479
|
+
|
480
|
+
openai_Process_Input = email_body
|
481
|
+
|
482
|
+
openai_api_key = email_config.get('openai_api_key', '')
|
483
|
+
geminiAI_APIKey = email_config.get('gemini_api_key', '')
|
484
|
+
signature = email_config.get('signature', '')
|
485
|
+
localAIURL = email_config.get('local_ai_url', '')
|
486
|
+
|
487
|
+
if len(str(openai_Process_Input)) > 0:
|
488
|
+
email_cat_data = {
|
489
|
+
"model_type": Model_Name,
|
490
|
+
"openai_api_key": openai_api_key,
|
491
|
+
"categories": categories,
|
492
|
+
"email_body": email_body,
|
493
|
+
"gemini_api_key": geminiAI_APIKey,
|
494
|
+
"signature": signature,
|
495
|
+
"local_ai_url": localAIURL,
|
496
|
+
}
|
497
|
+
email_classification = Email_Classification()
|
498
|
+
emailCategory = email_classification.detect_category(email_cat_data)
|
499
|
+
emailCategory = emailCategory['message']
|
500
|
+
logger.log(f"\nDetected Email category ::: {emailCategory}")
|
501
|
+
|
502
|
+
dataValues = {
|
503
|
+
'Model_Name': Model_Name,
|
504
|
+
'file_JsonArray': file_JsonArray,
|
505
|
+
'openai_api_key': openai_api_key,
|
506
|
+
'openai_Process_Input': openai_Process_Input,
|
507
|
+
'subject': subject,
|
508
|
+
'sender_email_addr': sender_email_addr,
|
509
|
+
'cc_email_addr': cc_email_addr,
|
510
|
+
'email_body': email_body,
|
511
|
+
'email_config': email_config,
|
512
|
+
'msg': msg,
|
513
|
+
'geminiAI_APIKey': geminiAI_APIKey,
|
514
|
+
'localAIURL': localAIURL,
|
515
|
+
'signature': signature,
|
516
|
+
'LABEL': LABEL,
|
517
|
+
'mail': mail,
|
518
|
+
'email_id': msg_id,
|
519
|
+
"uid": uid,
|
520
|
+
"to_email_addr": to_email_addr,
|
521
|
+
"user_id": user_id,
|
522
|
+
"is_html": is_html,
|
523
|
+
"import_file": True
|
524
|
+
}
|
525
|
+
processcategory = Process_Category()
|
526
|
+
processcategory.process_cat(emailCategory, dataValues)
|
774
527
|
|
775
|
-
|
776
|
-
if part.get_content_maintype() == 'multipart':
|
777
|
-
continue
|
778
|
-
if part.get('Content-Disposition') is None:
|
779
|
-
continue
|
780
|
-
filename = part.get_filename()
|
781
|
-
if filename:
|
782
|
-
filepath = os.path.join(date_folder, filename) # Save inside date-wise folder
|
528
|
+
return "success"
|
783
529
|
|
784
|
-
with open(filepath, 'wb') as f:
|
785
|
-
f.write(part.get_payload(decode=True))
|
786
|
-
logger.log(f"\nAttachment saved: '{filepath}'")
|
787
|
-
else:
|
788
|
-
logger.log("\nNo Attachment found.")
|
789
|
-
return filename
|
790
|
-
|
791
530
|
def read_JSON_File(self, json_fileName):
|
792
531
|
category_list = []
|
793
532
|
categories = ""
|
@@ -812,56 +551,26 @@ class Email_Read:
|
|
812
551
|
trace = traceback.format_exc()
|
813
552
|
logger.log(f"Exception in writeJsonFile: {msg} \n {trace} \n DataType ::: {type(msg)}")
|
814
553
|
raise Exception(msg)
|
815
|
-
|
816
|
-
def get_JsonArray_values(self, category, jsonArray):
|
817
|
-
responseMethod = ""
|
818
|
-
parameters = ""
|
819
|
-
|
820
|
-
for eachJson in jsonArray :
|
821
|
-
for key, value in eachJson.items():
|
822
|
-
if value == category:
|
823
|
-
responseMethod = eachJson["Response_Method"]
|
824
|
-
parameters = eachJson["Parameters"]
|
825
|
-
|
826
|
-
return responseMethod, parameters
|
827
|
-
|
828
|
-
def create_file_from_emailBody(self, text, sender_email_addr, parameters):
|
829
|
-
base_folder = "ORDERS"
|
830
|
-
today_date = datetime.today().strftime('%Y-%m-%d') # Format: YYYY-MM-DD
|
831
|
-
order_folder = os.path.join(base_folder, today_date)
|
832
554
|
|
833
|
-
|
834
|
-
|
555
|
+
def log_email_login(self, user_id, email, model_name, login_status, base_dir="EMail_log"):
|
556
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
557
|
+
log_dir = os.path.join(base_dir, user_id)
|
558
|
+
os.makedirs(log_dir, exist_ok=True)
|
559
|
+
log_file_path = os.path.join(log_dir, f"{user_id}.csv")
|
835
560
|
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
pdf = FPDF()
|
844
|
-
pdf.add_page()
|
845
|
-
pdf.set_font("Arial", size=12)
|
846
|
-
pdf.multi_cell(0, 10, text)
|
847
|
-
pdf.output(filePath)
|
848
|
-
logger.log(f"New PDF file created from email body and stored in '{filePath}'")
|
849
|
-
|
850
|
-
elif parameters["FILE_TYPE"] == "txt":
|
851
|
-
fileName = fileName + ".txt"
|
852
|
-
filePath = os.path.join(order_folder, fileName)
|
853
|
-
|
854
|
-
with open(filePath, "w") as file:
|
855
|
-
file.write(text)
|
856
|
-
logger.log(f"New TXT file created from email body and stored in '{filePath}'")
|
857
|
-
else:
|
858
|
-
message = f"Invalid File Type received."
|
859
|
-
self.send_response(200)
|
860
|
-
self.send_header('Content-type', 'text/html')
|
861
|
-
self.end_headers()
|
862
|
-
self.wfile.write(message.encode('utf-8'))
|
561
|
+
log_exists = os.path.isfile(log_file_path)
|
562
|
+
with open(log_file_path, mode='a', newline='') as file:
|
563
|
+
writer = csv.writer(file)
|
564
|
+
if not log_exists:
|
565
|
+
writer.writerow(["timestamp", "user_id", "email", "Model_Name", "login_status"])
|
566
|
+
writer.writerow([timestamp, user_id, email, model_name, login_status])
|
863
567
|
|
864
|
-
|
568
|
+
def update_status(self):
|
569
|
+
global shared_status
|
570
|
+
shared_status = False
|
865
571
|
|
866
|
-
|
572
|
+
def read_status(self):
|
573
|
+
global shared_status
|
574
|
+
return shared_status
|
867
575
|
|
576
|
+
|