AIEmailAutomationUtility 0.0.26__py3-none-any.whl → 0.0.28__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/EmailReplyAssistant.py +9 -2
- AIEmailAutomationUtility/Email_Read.py +2 -1
- AIEmailAutomationUtility/Process_Category.py +128 -83
- {AIEmailAutomationUtility-0.0.26.dist-info → AIEmailAutomationUtility-0.0.28.dist-info}/METADATA +3 -3
- {AIEmailAutomationUtility-0.0.26.dist-info → AIEmailAutomationUtility-0.0.28.dist-info}/RECORD +8 -8
- {AIEmailAutomationUtility-0.0.26.dist-info → AIEmailAutomationUtility-0.0.28.dist-info}/LICENCE.txt +0 -0
- {AIEmailAutomationUtility-0.0.26.dist-info → AIEmailAutomationUtility-0.0.28.dist-info}/WHEEL +0 -0
- {AIEmailAutomationUtility-0.0.26.dist-info → AIEmailAutomationUtility-0.0.28.dist-info}/top_level.txt +0 -0
@@ -95,6 +95,12 @@ class EmailReplyAssistant:
|
|
95
95
|
|
96
96
|
def identify_customer_product_reply_assitant(self, openAI_key, assistant_ID, email_content, subject, prompt):
|
97
97
|
try:
|
98
|
+
logger.log(f"the Assistant id is ::: {assistant_ID}")
|
99
|
+
logger.log(f"the Prompt is ::: {prompt}")
|
100
|
+
logger.log(f"the Api key is ::: {openAI_key}")
|
101
|
+
logger.log(f"the email content is ::: {email_content}")
|
102
|
+
logger.log(f"the subject is ::: {subject}")
|
103
|
+
|
98
104
|
openAI_response = ""
|
99
105
|
client = OpenAI(api_key=openAI_key)
|
100
106
|
thread = client.beta.threads.create()
|
@@ -102,7 +108,8 @@ class EmailReplyAssistant:
|
|
102
108
|
client.beta.threads.messages.create(
|
103
109
|
thread_id=thread.id,
|
104
110
|
role="user",
|
105
|
-
content=f"subject:{subject}\nemail body:{email_content}",
|
111
|
+
# content=f"subject:{subject}\nemail body:{email_content}",
|
112
|
+
content=prompt,
|
106
113
|
)
|
107
114
|
|
108
115
|
event_handler = EmailReplyAssistant().EventHandler()
|
@@ -110,7 +117,7 @@ class EmailReplyAssistant:
|
|
110
117
|
with client.beta.threads.runs.stream(
|
111
118
|
thread_id=thread.id,
|
112
119
|
assistant_id=assistant_ID,
|
113
|
-
instructions=prompt,
|
120
|
+
# instructions=prompt,
|
114
121
|
event_handler=event_handler,
|
115
122
|
) as stream:
|
116
123
|
stream.until_done()
|
@@ -552,7 +552,8 @@ class Email_Read:
|
|
552
552
|
logger.log(f"Exception in writeJsonFile: {msg} \n {trace} \n DataType ::: {type(msg)}")
|
553
553
|
raise Exception(msg)
|
554
554
|
|
555
|
-
def log_email_login(self, user_id, email, model_name, login_status
|
555
|
+
def log_email_login(self, user_id, email, model_name, login_status):
|
556
|
+
base_dir="EMail_log"
|
556
557
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
557
558
|
log_dir = os.path.join(base_dir, user_id)
|
558
559
|
os.makedirs(log_dir, exist_ok=True)
|
@@ -42,16 +42,14 @@ class Process_Category:
|
|
42
42
|
is_html = dataValues.get('is_html')
|
43
43
|
import_file = dataValues.get('import_file')
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
logger.log(f"the json datavalues of email_id are ------------------------ {email_id}")
|
48
|
-
logger.log(f"the category is ------------------------ {category}")
|
45
|
+
customer_determination = None
|
46
|
+
product_determination = None
|
49
47
|
|
50
48
|
if category == "Product Enquiry":
|
51
49
|
if Model_Name == "OpenAI":
|
52
50
|
action_taken = "Reply email drafted using Open_AI Model"
|
53
51
|
responseMethod, parameters = self.get_JsonArray_values(category, file_JsonArray)
|
54
|
-
logger.log(f"the repsonse method{responseMethod}")
|
52
|
+
logger.log(f"the repsonse method is ::: {responseMethod}")
|
55
53
|
if responseMethod == "Reply_Email_Ai_Assistant":
|
56
54
|
emailreplyassistant = EmailReplyAssistant()
|
57
55
|
openai_Response = emailreplyassistant.Reply_Email_Ai_Assistant(openai_api_key, parameters["Assistant_Id"], openai_Process_Input, subject)
|
@@ -107,47 +105,51 @@ class Process_Category:
|
|
107
105
|
logger.log(f"fileName 107::: {fileName}")
|
108
106
|
logger.log(f"document_type 108::: {document_type}")
|
109
107
|
|
110
|
-
if
|
111
|
-
|
112
|
-
today_date = datetime.today().strftime('%Y-%m-%d')
|
113
|
-
order_folder = os.path.join(document_type, today_date)
|
114
|
-
|
115
|
-
email_upload_document = Email_DocumentUploader()
|
116
|
-
if len(fileName) != 0:
|
117
|
-
file_path = os.path.join(order_folder, fileName) # Correct file path
|
118
|
-
|
119
|
-
with open(file_path, "rb") as file:
|
120
|
-
parameters["DOCUMENT_TYPE"] = document_type
|
121
|
-
|
122
|
-
logger.log(f"Updated Parameters ::: {parameters}")
|
123
|
-
response_status, restAPI_Result = email_upload_document.email_document_upload(file, parameters)
|
124
|
-
logger.log(f"email_upload_document_response ::: {restAPI_Result}")
|
125
|
-
else:
|
126
|
-
document_type = "Order Email"
|
108
|
+
if document_type != '':
|
109
|
+
if responseMethod == "Upload_Document":
|
127
110
|
# Get today's date folder path
|
128
111
|
today_date = datetime.today().strftime('%Y-%m-%d')
|
129
112
|
order_folder = os.path.join(document_type, today_date)
|
130
113
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
114
|
+
email_upload_document = Email_DocumentUploader()
|
115
|
+
if len(fileName) != 0:
|
116
|
+
file_path = os.path.join(order_folder, fileName) # Correct file path
|
117
|
+
|
118
|
+
with open(file_path, "rb") as file:
|
119
|
+
parameters["DOCUMENT_TYPE"] = document_type
|
120
|
+
|
121
|
+
logger.log(f"Updated Parameters ::: {parameters}")
|
122
|
+
response_status, restAPI_Result = email_upload_document.email_document_upload(file, parameters)
|
123
|
+
logger.log(f"email_upload_document_response ::: {restAPI_Result}")
|
124
|
+
else:
|
125
|
+
document_type = "Order Email"
|
126
|
+
# Get today's date folder path
|
127
|
+
today_date = datetime.today().strftime('%Y-%m-%d')
|
128
|
+
order_folder = os.path.join(document_type, today_date)
|
129
|
+
|
130
|
+
parameters["DOCUMENT_TYPE"] = document_type
|
131
|
+
logger.log(f"Updated Parameters ::: {parameters}")
|
132
|
+
new_fileName = self.create_file_from_emailBody(email_body, sender_email_addr, parameters)
|
133
|
+
new_file_path = os.path.join(order_folder, new_fileName)
|
134
|
+
|
135
|
+
with open(new_file_path, "rb") as file:
|
136
|
+
response_status, restAPI_Result = email_upload_document.email_document_upload(file, parameters)
|
137
|
+
logger.log(f"email_upload_document_response ::: {restAPI_Result}")
|
138
|
+
|
139
|
+
if response_status == "200":
|
140
|
+
logger.log(f"Attachment uploaded successfully against Document ID: '{restAPI_Result}'.")
|
141
|
+
csv_data_status="Success",
|
142
|
+
csv_data_response=f"Attachment uploaded successfully against Document ID: '{restAPI_Result}'"
|
143
|
+
else:
|
144
|
+
logger.log(restAPI_Result)
|
145
|
+
csv_data_status="Fail",
|
146
|
+
csv_data_response=f"Attachment uploaded Failed against Document ID: '{restAPI_Result}'"
|
144
147
|
else:
|
145
|
-
|
146
|
-
|
147
|
-
csv_data_response=f"Attachment uploaded Failed against Document ID: '{restAPI_Result}'"
|
148
|
+
message = f"Invalid response method received '{responseMethod}' for category : '{category}'"
|
149
|
+
raise ValueError(message)
|
148
150
|
else:
|
149
|
-
|
150
|
-
|
151
|
+
csv_data_status="Fail",
|
152
|
+
csv_data_response=f"Respective document type has not matched for uploading."
|
151
153
|
|
152
154
|
elif category == "Quotation":
|
153
155
|
action_taken = f"Mail drafted for products rate"
|
@@ -156,32 +158,39 @@ class Process_Category:
|
|
156
158
|
|
157
159
|
# Step 4: Identify customer from email using AI
|
158
160
|
customer_data = self.identify_customer(email_body, subject, Model_Name, openai_api_key, geminiAI_APIKey, localAIURL, parameters["Customer_Assistant_Id"])
|
159
|
-
logger.log(f"Identified customer
|
160
|
-
|
161
|
+
logger.log(f"Identified customer is ::: {customer_data}")
|
162
|
+
|
163
|
+
customer_determination=customer_data
|
164
|
+
|
161
165
|
# Extract customer code once
|
162
166
|
customer_code = customer_data.get("customer_code", "")
|
163
167
|
|
164
168
|
# Step 5: Identify product from email using AI
|
165
169
|
products = self.identify_products(email_body, subject, Model_Name, openai_api_key, geminiAI_APIKey, localAIURL, parameters["Product_Assistant_Id"])
|
166
|
-
logger.log(f'
|
170
|
+
logger.log(f'Identified Products are ::: {products}')
|
171
|
+
|
172
|
+
product_determination=products
|
167
173
|
|
168
174
|
db_connection = sqlite3.connect('/home/base/git/ai-email-automation/AI_Email/database/fetchprice.db')
|
169
175
|
for product in products:
|
170
|
-
cursor = db_connection.cursor()
|
171
|
-
|
172
176
|
item_no = product.get("item_no", "").strip()
|
173
177
|
make = product.get("make", "").strip()
|
174
178
|
rate = None
|
175
179
|
found_rate = False
|
176
180
|
|
181
|
+
logger.log(f"item no is ::: {item_no}")
|
182
|
+
logger.log(f"make is ::: {make}")
|
183
|
+
|
177
184
|
# Step 1: Get base price from PRICE_LIST
|
178
185
|
query_price = '''
|
179
186
|
SELECT PRICE
|
180
187
|
FROM PRICE_LIST
|
181
188
|
WHERE ITEM_NO = ?;
|
182
189
|
'''
|
190
|
+
cursor = db_connection.cursor()
|
183
191
|
cursor.execute(query_price, (item_no,))
|
184
192
|
price_result = cursor.fetchone()
|
193
|
+
cursor.close()
|
185
194
|
|
186
195
|
if price_result:
|
187
196
|
price_raw = price_result[0]
|
@@ -194,17 +203,16 @@ class Process_Category:
|
|
194
203
|
|
195
204
|
try:
|
196
205
|
raw_price = float(price_cleaned)
|
197
|
-
logger.log(f"[0] Base price for item '{item_no}' is {raw_price}")
|
206
|
+
logger.log(f"Process_Category - Quotation [0] Base price for item '{item_no}' is {raw_price}")
|
198
207
|
except (TypeError, ValueError):
|
199
|
-
logger.log(f"[0] Invalid raw price for item '{item_no}': {price_result[0]}")
|
208
|
+
logger.log(f"Process_Category - Quotation [0] Invalid raw price for item '{item_no}': {price_result[0]}")
|
200
209
|
product["rate"] = None
|
201
210
|
continue
|
202
211
|
else:
|
203
|
-
logger.log(f"[0] No base price found for item '{item_no}'.
|
204
|
-
product["rate"] =
|
212
|
+
logger.log(f"Process_Category - Quotation [0] No base price found for item '{item_no}' .")
|
213
|
+
product["rate"] = "NA"
|
205
214
|
continue
|
206
215
|
|
207
|
-
|
208
216
|
# Condition 1: Exact match in special_rate_customer_wise
|
209
217
|
query1 = '''
|
210
218
|
SELECT RATE
|
@@ -212,13 +220,16 @@ class Process_Category:
|
|
212
220
|
WHERE ITEM_CODE = ?
|
213
221
|
AND CUSTOMER_CODE = ?;
|
214
222
|
'''
|
223
|
+
cursor = db_connection.cursor()
|
215
224
|
cursor.execute(query1, (item_no, customer_code))
|
216
225
|
result = cursor.fetchone()
|
226
|
+
cursor.close()
|
217
227
|
|
218
228
|
if result:
|
219
229
|
rate = result[0]
|
220
230
|
found_rate = True
|
221
|
-
logger.log(f"[1] Special Rate for item '{item_no}' and customer '{customer_code}' is {rate}")
|
231
|
+
logger.log(f"Process_Category - Quotation [1] Special Rate for item '{item_no}' and customer '{customer_code}' is {rate}")
|
232
|
+
price_pickup_source="SPECIAL_RATE_CUSTOMER_WISE"
|
222
233
|
|
223
234
|
# Condition 2: Customer + Manufacturer discount
|
224
235
|
if not found_rate:
|
@@ -227,15 +238,18 @@ class Process_Category:
|
|
227
238
|
FROM CUSTOMER_WISE_DISCOUNT
|
228
239
|
WHERE CUSTOMER_CODE = ? AND MAKE = ?;
|
229
240
|
'''
|
241
|
+
cursor = db_connection.cursor()
|
230
242
|
cursor.execute(query2, (customer_code, make))
|
231
243
|
discount_result = cursor.fetchone()
|
244
|
+
cursor.close()
|
232
245
|
|
233
246
|
if discount_result:
|
234
247
|
discount_percent = discount_result[0]
|
235
248
|
rate = raw_price * (1 - int(discount_percent) / 100)
|
236
249
|
rate = round(rate, 2)
|
237
250
|
found_rate = True
|
238
|
-
logger.log(f"[2] Discounted rate for '{make}' ({discount_percent}%) on price {raw_price}: {rate}")
|
251
|
+
logger.log(f"Process_Category - Quotation [2] Discounted rate for '{make}' ({discount_percent}%) on price {raw_price}: {rate}")
|
252
|
+
price_pickup_source="CUSTOMER_WISE_DISCOUNT"
|
239
253
|
|
240
254
|
# Condition 3: Past Sales most used make
|
241
255
|
if not found_rate:
|
@@ -248,8 +262,10 @@ class Process_Category:
|
|
248
262
|
ORDER BY COUNT(*) DESC
|
249
263
|
LIMIT 1;
|
250
264
|
'''
|
265
|
+
cursor = db_connection.cursor()
|
251
266
|
cursor.execute(query3, (customer_code, item_no))
|
252
267
|
past_sales_result = cursor.fetchone()
|
268
|
+
cursor.close()
|
253
269
|
|
254
270
|
if past_sales_result:
|
255
271
|
most_common_make, past_discount = past_sales_result
|
@@ -257,12 +273,11 @@ class Process_Category:
|
|
257
273
|
rate = raw_price * (1 - int(past_discount) / 100)
|
258
274
|
rate = round(rate, 2)
|
259
275
|
found_rate = True
|
260
|
-
logger.log(f"[3] Fallback: Most used make '{most_common_make}' for customer '{customer_code}' got {past_discount}% discount. Rate: {rate}")
|
276
|
+
logger.log(f"Process_Category - Quotation [3] Fallback: Most used make '{most_common_make}' for customer '{customer_code}' got {past_discount}% discount. Rate: {rate}")
|
277
|
+
price_pickup_source="PAST_SALES"
|
261
278
|
else:
|
262
|
-
logger.log(f"[3] Fallback: Invalid price for item '{item_no}'")
|
263
|
-
|
264
|
-
logger.log(f"[3] No past sales data for item '{item_no}' and customer '{customer_code}'")
|
265
|
-
|
279
|
+
logger.log(f"Process_Category - Quotation [3] Fallback: Invalid price for item '{item_no}'")
|
280
|
+
|
266
281
|
# Condition 4: Manufacturer General Discount
|
267
282
|
if not found_rate:
|
268
283
|
query4 = '''
|
@@ -270,20 +285,27 @@ class Process_Category:
|
|
270
285
|
FROM MANUFACTURE_WISE_GENERAL_DISCOUNT
|
271
286
|
WHERE MAKE = ?;
|
272
287
|
'''
|
288
|
+
cursor = db_connection.cursor()
|
273
289
|
cursor.execute(query4, (make,))
|
274
290
|
general_discount_result = cursor.fetchone()
|
291
|
+
cursor.close()
|
275
292
|
|
276
293
|
if general_discount_result:
|
277
294
|
general_discount_percent = general_discount_result[0]
|
278
295
|
rate = raw_price * (1 - int(general_discount_percent) / 100)
|
279
296
|
rate = round(rate, 2)
|
280
297
|
found_rate = True
|
281
|
-
logger.log(f"[4] General Discount for '{make}' ({general_discount_percent}%) on price {raw_price}: {rate}")
|
282
|
-
|
283
|
-
|
298
|
+
logger.log(f"Process_Category - Quotation [4] General Discount for '{make}' ({general_discount_percent}%) on price {raw_price}: {rate}")
|
299
|
+
price_pickup_source="MANUFACTURE_WISE_GENERAL_DISCOUNT"
|
300
|
+
|
301
|
+
#Condition 5: Fallback to raw_price if no discount applied
|
302
|
+
if not found_rate:
|
303
|
+
rate = raw_price
|
304
|
+
logger.log(f"Process_Category - Quotation [5] No discounts applied. Using base price for item '{item_no}': {rate}")
|
305
|
+
price_pickup_source="PRICE_LIST"
|
284
306
|
|
285
307
|
product["rate"] = rate
|
286
|
-
|
308
|
+
product["Price Pickup Source"]=price_pickup_source
|
287
309
|
|
288
310
|
db_connection.close()
|
289
311
|
|
@@ -311,8 +333,6 @@ class Process_Category:
|
|
311
333
|
|
312
334
|
csv_data_status = status
|
313
335
|
csv_data_response = response
|
314
|
-
# csv_data_status = "status"
|
315
|
-
# csv_data_response = "response"
|
316
336
|
logger.log(f"Quotation email sent to {sender_email_addr}")
|
317
337
|
|
318
338
|
elif category == "Others" and import_file == True:
|
@@ -325,7 +345,7 @@ class Process_Category:
|
|
325
345
|
csv_data_response = f""
|
326
346
|
|
327
347
|
logger.log(f"Marking email as UNREAD. ")
|
328
|
-
|
348
|
+
# print(f"email_id: {email_id}, type: {type(email_id)}")
|
329
349
|
mail.store(email_id, '-FLAGS', '\\Seen')
|
330
350
|
mail.create(LABEL)
|
331
351
|
mail.copy(email_id, LABEL)
|
@@ -335,7 +355,7 @@ class Process_Category:
|
|
335
355
|
|
336
356
|
current_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
337
357
|
filename = f'{uid}{current_timestamp}'
|
338
|
-
logger.log(f"
|
358
|
+
logger.log(f"The file name for csv and eml is ::: {filename}")
|
339
359
|
self.store_email_details_to_csv(
|
340
360
|
email_id=f'{uid}{current_timestamp}',
|
341
361
|
to_email=parseaddr(to_email_addr)[1],
|
@@ -349,7 +369,9 @@ class Process_Category:
|
|
349
369
|
user_id=user_id,
|
350
370
|
status=csv_data_status,
|
351
371
|
response=csv_data_response,
|
352
|
-
current_timestamp=current_timestamp
|
372
|
+
current_timestamp=current_timestamp,
|
373
|
+
customer_determination=customer_determination,
|
374
|
+
product_determination=product_determination,
|
353
375
|
)
|
354
376
|
self.store_email_as_eml(
|
355
377
|
uid=f'{uid}{current_timestamp}',
|
@@ -380,7 +402,7 @@ class Process_Category:
|
|
380
402
|
|
381
403
|
filename = ""
|
382
404
|
mime_type = ""
|
383
|
-
document_type = "
|
405
|
+
document_type = ""
|
384
406
|
|
385
407
|
for part in msg.walk():
|
386
408
|
if part.get_content_maintype() == 'multipart':
|
@@ -460,10 +482,10 @@ class Process_Category:
|
|
460
482
|
logger.log("Inside identify_customer")
|
461
483
|
|
462
484
|
if model_type == "OpenAI":
|
463
|
-
prompt = f"""Identify the customer code, customer name
|
485
|
+
prompt = f"""/* Identify the most likely customer code, customer name from the following email using the file attached in assistant. Use various key information's such as sender name, organisation, address, email id to determine the customer. If customer not available in the data return the name and NA as code. Return the data in json format. Always return 1 row. Do not include any instruction as the output will be directly in a program. */ /n {email_body}"""
|
464
486
|
emailreplyassistant = EmailReplyAssistant()
|
465
487
|
ai_result = emailreplyassistant.identify_customer_product_reply_assitant(openai_api_key, assistant_id, email_body, subject, prompt)
|
466
|
-
|
488
|
+
|
467
489
|
elif model_type == "GeminiAI":
|
468
490
|
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."""
|
469
491
|
ai_result = self.identify_customer_product_GeminiAI(gemini_api_key, email_body, prompt)
|
@@ -490,11 +512,7 @@ class Process_Category:
|
|
490
512
|
logger.log("Inside identify_products")
|
491
513
|
|
492
514
|
if model_type == "OpenAI":
|
493
|
-
prompt = f"""
|
494
|
-
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}.
|
495
|
-
If there is one product or multiple should return in list.
|
496
|
-
Do not include any instruction as the output will be directly in a program.
|
497
|
-
"""
|
515
|
+
prompt = f"""/* Extract complete item pricing information from the following mixed-format email content. The email may contain a combination of:- descriptive product listings- tabular structured price info- semi-structured lines with HSN, quantity, material, etc. Give me price in INR and information of all items in following format requested_description, item_no, make, description, price, price unit, inventory unit strictly in JSON format. If the item is not available in the assistant files return requested description from email data and rest of the columns as NA. Do not include any instruction as the output will be directly in a program. */ /n {email_body}. """
|
498
516
|
emailreplyassistant = EmailReplyAssistant()
|
499
517
|
ai_result = emailreplyassistant.identify_customer_product_reply_assitant(openai_api_key, assistant_id, email_body, subject, prompt)
|
500
518
|
|
@@ -539,7 +557,7 @@ class Process_Category:
|
|
539
557
|
Customer Code: {customer.get('customer_code', '')}
|
540
558
|
|
541
559
|
{product_table}
|
542
|
-
product_table must contain
|
560
|
+
product_table must contain price column, if it is none(set it as -).
|
543
561
|
Original Email Subject: {subject}
|
544
562
|
|
545
563
|
Return only the following JSON String format:
|
@@ -750,7 +768,7 @@ class Process_Category:
|
|
750
768
|
logger.log(f"Error with Gemini AI detection/generation: {str(e)}")
|
751
769
|
return {"success": "Failed", "message": f"Error with Gemini AI detection/generation: {str(e)}"}
|
752
770
|
|
753
|
-
def store_email_details_to_csv(self, email_id, to_email, from_email, cc_email, subject, body, email_type, action_performed, filename, user_id,status,response,current_timestamp):
|
771
|
+
def store_email_details_to_csv(self, email_id, to_email, from_email, cc_email, subject, body, email_type, action_performed, filename, user_id,status,response,current_timestamp,customer_determination,product_determination):
|
754
772
|
"""
|
755
773
|
Stores the extracted email details to a CSV file inside 'Mail_log/mail_log_user_id' folder
|
756
774
|
with the name user_id.csv.
|
@@ -765,28 +783,55 @@ class Process_Category:
|
|
765
783
|
os.makedirs(user_folder, exist_ok=True)
|
766
784
|
|
767
785
|
filename = filename.lstrip()
|
768
|
-
logger.log(f"filename ::: [{filename}]")
|
769
786
|
full_csv_path = os.path.join(user_folder, f"{filename}.csv")
|
770
|
-
logger.log(f"full_csv_path ::: {full_csv_path}")
|
771
787
|
|
772
|
-
|
773
|
-
|
788
|
+
if email_type=="Quotation":
|
789
|
+
csv_data = [{
|
774
790
|
'to': to_email,
|
775
791
|
'from': from_email,
|
776
792
|
'cc': cc_email,
|
777
793
|
'subject': subject,
|
778
794
|
'body': body.replace('\n', ' ').replace('\r', ''),
|
779
795
|
'Category': email_type,
|
780
|
-
'Action
|
796
|
+
'Action Performed': action_performed,
|
781
797
|
'unique_id': email_id,
|
782
798
|
'timestamp': current_timestamp,
|
783
799
|
'status of mail draft': status,
|
784
|
-
'Response
|
800
|
+
'Response Generated':response,
|
801
|
+
'Customer Determination':customer_determination,
|
802
|
+
'Product Determination':product_determination,
|
785
803
|
}]
|
804
|
+
else:
|
805
|
+
csv_data = [{
|
806
|
+
'to': to_email,
|
807
|
+
'from': from_email,
|
808
|
+
'cc': cc_email,
|
809
|
+
'subject': subject,
|
810
|
+
'body': body.replace('\n', ' ').replace('\r', ''),
|
811
|
+
'Category': email_type,
|
812
|
+
'Action Performed': action_performed,
|
813
|
+
'unique_id': email_id,
|
814
|
+
'timestamp': current_timestamp,
|
815
|
+
'status of mail draft': status,
|
816
|
+
'Response Generated':response
|
817
|
+
}]
|
786
818
|
|
787
819
|
# Write to CSV file (user_id.csv)
|
788
820
|
with open(full_csv_path, 'a', newline='', encoding='utf-8') as csvfile:
|
789
|
-
|
821
|
+
if email_type == "Quotation":
|
822
|
+
fieldnames = [
|
823
|
+
'to', 'from', 'cc', 'timestamp', 'subject', 'body',
|
824
|
+
'Category', 'Action Performed', 'unique_id',
|
825
|
+
'status of mail draft', 'Response Generated',
|
826
|
+
'Customer Determination', 'Product Determination'
|
827
|
+
]
|
828
|
+
else:
|
829
|
+
fieldnames = [
|
830
|
+
'to', 'from', 'cc', 'timestamp', 'subject', 'body',
|
831
|
+
'Category', 'Action Performed', 'unique_id',
|
832
|
+
'status of mail draft', 'Response Generated'
|
833
|
+
]
|
834
|
+
|
790
835
|
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
791
836
|
|
792
837
|
# If the file is empty, write the header
|
{AIEmailAutomationUtility-0.0.26.dist-info → AIEmailAutomationUtility-0.0.28.dist-info}/METADATA
RENAMED
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: AIEmailAutomationUtility
|
3
|
-
Version: 0.0.
|
4
|
-
Summary:
|
3
|
+
Version: 0.0.28
|
4
|
+
Summary: Set Bydefault document type as blank to avoid garbage data while uploading
|
5
5
|
Author: Proteus Technology PVT. LTD.
|
6
6
|
Author-email: <apps@baseinformation.com>
|
7
7
|
Keywords: python,first package
|
@@ -13,4 +13,4 @@ Classifier: Operating System :: MacOS :: MacOS X
|
|
13
13
|
Classifier: Operating System :: Microsoft :: Windows
|
14
14
|
License-File: LICENCE.txt
|
15
15
|
|
16
|
-
|
16
|
+
Set Bydefault document type as blank to avoid garbage data while uploading
|
{AIEmailAutomationUtility-0.0.26.dist-info → AIEmailAutomationUtility-0.0.28.dist-info}/RECORD
RENAMED
@@ -1,15 +1,15 @@
|
|
1
|
-
AIEmailAutomationUtility/EmailReplyAssistant.py,sha256=
|
1
|
+
AIEmailAutomationUtility/EmailReplyAssistant.py,sha256=R_wJna3-ITsVxQEccryhM93T_Nf_Oxo8DXnS-sDN8VE,6679
|
2
2
|
AIEmailAutomationUtility/Email_Classification.py,sha256=Ar0g4Ff8HOT7xICktd3nP_C_vCyeY-xCpUjVCVRWAyc,9417
|
3
3
|
AIEmailAutomationUtility/Email_DocumentUploader.py,sha256=YJu4tuTHr0K-5vuds9gZfj-Hwsgm4MuAOP39Lmu_t98,3219
|
4
4
|
AIEmailAutomationUtility/Email_Draft.py,sha256=DcyBeDaE8CReKHnHxLiz-o2tDxuUgwy91c4k0qhQbVw,7749
|
5
|
-
AIEmailAutomationUtility/Email_Read.py,sha256=
|
5
|
+
AIEmailAutomationUtility/Email_Read.py,sha256=pRqc9295r_qqdfWIFJFG2XH9J-VlvO1E0yP3iv_cRV4,27802
|
6
6
|
AIEmailAutomationUtility/Email_Upload_Document.py,sha256=3bdkxfDlwoeRp-46KPw2Gs1dqBhEIoA1yE5GCudpdV8,1320
|
7
|
-
AIEmailAutomationUtility/Process_Category.py,sha256=
|
7
|
+
AIEmailAutomationUtility/Process_Category.py,sha256=f17YF8rfSTFScxBfAhuJJ8ev6TbxYDcPQljIpZWa5PY,44100
|
8
8
|
AIEmailAutomationUtility/Save_Draft.py,sha256=yzLgFN14I_lXE6qL0I3tKNduvcnWdbsY9i2mKdTtio4,5348
|
9
9
|
AIEmailAutomationUtility/Save_Transaction.py,sha256=Gg1w6hhzHmEFjsuzYvkq-3-EsWReetjLHsYSv5YIGgM,3816
|
10
10
|
AIEmailAutomationUtility/__init__.py,sha256=Jad3IdPRsVMeLqEEh-FbCrc1lE2tzJO2DTG5Hgmxh5g,391
|
11
|
-
AIEmailAutomationUtility-0.0.
|
12
|
-
AIEmailAutomationUtility-0.0.
|
13
|
-
AIEmailAutomationUtility-0.0.
|
14
|
-
AIEmailAutomationUtility-0.0.
|
15
|
-
AIEmailAutomationUtility-0.0.
|
11
|
+
AIEmailAutomationUtility-0.0.28.dist-info/LICENCE.txt,sha256=2qX9IkEUBx0VJp1Vh9O2dsRwE-IpYId0lXDyn7OVsJ8,1073
|
12
|
+
AIEmailAutomationUtility-0.0.28.dist-info/METADATA,sha256=u5RJjpiERsP60tsBgtLops76gMlO2yuRq9naJ-_5Qmo,649
|
13
|
+
AIEmailAutomationUtility-0.0.28.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
14
|
+
AIEmailAutomationUtility-0.0.28.dist-info/top_level.txt,sha256=3jTWrTUblVkaP7mpwY2UBSnrlfot5Ykpfsehyke-Uzw,25
|
15
|
+
AIEmailAutomationUtility-0.0.28.dist-info/RECORD,,
|
{AIEmailAutomationUtility-0.0.26.dist-info → AIEmailAutomationUtility-0.0.28.dist-info}/LICENCE.txt
RENAMED
File without changes
|
{AIEmailAutomationUtility-0.0.26.dist-info → AIEmailAutomationUtility-0.0.28.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|