AIEmailAutomationUtility 0.0.32__py3-none-any.whl → 0.0.34__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_DocumentUploader.py +0 -1
- AIEmailAutomationUtility/Email_Draft.py +1 -0
- AIEmailAutomationUtility/Email_Read.py +24 -11
- AIEmailAutomationUtility/Process_Category.py +177 -18
- {AIEmailAutomationUtility-0.0.32.dist-info → AIEmailAutomationUtility-0.0.34.dist-info}/METADATA +3 -3
- AIEmailAutomationUtility-0.0.34.dist-info/RECORD +15 -0
- {AIEmailAutomationUtility-0.0.32.dist-info → AIEmailAutomationUtility-0.0.34.dist-info}/WHEEL +1 -1
- AIEmailAutomationUtility-0.0.32.dist-info/RECORD +0 -15
- {AIEmailAutomationUtility-0.0.32.dist-info → AIEmailAutomationUtility-0.0.34.dist-info}/LICENCE.txt +0 -0
- {AIEmailAutomationUtility-0.0.32.dist-info → AIEmailAutomationUtility-0.0.34.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,7 @@ from datetime import datetime
|
|
7
7
|
import threading
|
8
8
|
import traceback
|
9
9
|
import json
|
10
|
-
import os
|
10
|
+
import os, shutil
|
11
11
|
import csv
|
12
12
|
|
13
13
|
import io
|
@@ -112,7 +112,7 @@ class Email_Read:
|
|
112
112
|
login_status = "Success"
|
113
113
|
mail.select('inbox')
|
114
114
|
|
115
|
-
file_JsonArray, categories = self.read_JSON_File(templateName)
|
115
|
+
file_JsonArray, categories = self.read_JSON_File(templateName, user_id)
|
116
116
|
|
117
117
|
except Exception as e:
|
118
118
|
login_status = "Failed"
|
@@ -251,7 +251,7 @@ class Email_Read:
|
|
251
251
|
login_status = "Success"
|
252
252
|
mail.select('inbox')
|
253
253
|
|
254
|
-
file_JsonArray, categories = self.read_JSON_File(templateName)
|
254
|
+
file_JsonArray, categories = self.read_JSON_File(templateName, user_id)
|
255
255
|
|
256
256
|
except Exception as e:
|
257
257
|
logger.log(f"Login failed: {e}")
|
@@ -277,7 +277,7 @@ class Email_Read:
|
|
277
277
|
attachments = []
|
278
278
|
status, data = mail.fetch(email_id, '(RFC822 UID)')
|
279
279
|
|
280
|
-
if status == 'OK':
|
280
|
+
if status == 'OK' and data[0]!= None:
|
281
281
|
raw_email = data[0][1]
|
282
282
|
msg = email.message_from_bytes(raw_email)
|
283
283
|
|
@@ -484,7 +484,7 @@ class Email_Read:
|
|
484
484
|
templateName = "ai_email_automation.json"
|
485
485
|
fileName = ""
|
486
486
|
|
487
|
-
file_JsonArray, categories = self.read_JSON_File(templateName)
|
487
|
+
file_JsonArray, categories = self.read_JSON_File(templateName, user_id)
|
488
488
|
# Call the `extract_all_email_info` method to extract details from the eml content
|
489
489
|
extracted_info,msg = self.extract_all_email_info(eml_content)
|
490
490
|
|
@@ -552,24 +552,37 @@ class Email_Read:
|
|
552
552
|
|
553
553
|
return "success"
|
554
554
|
|
555
|
-
def read_JSON_File(self, json_fileName):
|
555
|
+
def read_JSON_File(self, json_fileName, user_id):
|
556
556
|
category_list = []
|
557
557
|
categories = ""
|
558
558
|
try:
|
559
|
-
|
560
|
-
|
561
|
-
|
559
|
+
logger.log(f"\nEmail_Read() read_JSON_File user_id ::: {user_id}")
|
560
|
+
user_file = json_fileName
|
561
|
+
if user_id:
|
562
|
+
user_dir = os.path.join('user_data', user_id)
|
563
|
+
logger.log(f"\nEmail_Read() read_JSON_File user_dir ::: {user_dir}")
|
564
|
+
if not os.path.exists(user_dir):
|
565
|
+
os.makedirs(user_dir, exist_ok=True)
|
566
|
+
user_file = os.path.join(user_dir, json_fileName)
|
567
|
+
if not os.path.exists(user_file) and os.path.exists(json_fileName):
|
568
|
+
shutil.copy(json_fileName, user_file)
|
569
|
+
|
570
|
+
logger.log(f"\nEmail_Read() read_JSON_File user_file ::: {user_file}")
|
571
|
+
|
572
|
+
if os.path.exists(user_file):
|
573
|
+
with open(user_file, "r") as fileObj:
|
574
|
+
file_JsonArray = json.load(fileObj)
|
562
575
|
|
563
576
|
for eachJson in file_JsonArray :
|
564
577
|
for key, value in eachJson.items():
|
565
|
-
if key == "Category"
|
578
|
+
if key == "Category":
|
566
579
|
category_list.append(value)
|
567
580
|
# categories = ", ".join(category_list)
|
568
581
|
|
569
582
|
return file_JsonArray, category_list
|
570
583
|
|
571
584
|
else:
|
572
|
-
message = f"{
|
585
|
+
message = f"{user_file} file not found."
|
573
586
|
raise Exception(message)
|
574
587
|
except Exception as e:
|
575
588
|
msg = f"'{json_fileName}' file is empty. Please provide JSON parameters in the filename."
|
@@ -14,6 +14,10 @@ import openai
|
|
14
14
|
import json
|
15
15
|
import csv
|
16
16
|
import os
|
17
|
+
from email import message_from_string
|
18
|
+
import re
|
19
|
+
import weaviate
|
20
|
+
from weaviate.gql.get import HybridFusion
|
17
21
|
|
18
22
|
class Process_Category:
|
19
23
|
|
@@ -129,7 +133,22 @@ class Process_Category:
|
|
129
133
|
|
130
134
|
parameters["DOCUMENT_TYPE"] = document_type
|
131
135
|
logger.log(f"Updated Parameters ::: {parameters}")
|
132
|
-
|
136
|
+
|
137
|
+
email_parts = []
|
138
|
+
if sender_email_addr:
|
139
|
+
email_parts.append(f"From: {sender_email_addr}")
|
140
|
+
if to_email_addr:
|
141
|
+
email_parts.append(f"To: {to_email_addr}")
|
142
|
+
if cc_email_addr:
|
143
|
+
email_parts.append(f"CC: {cc_email_addr}")
|
144
|
+
if subject:
|
145
|
+
email_parts.append(f"Subject: {subject}")
|
146
|
+
|
147
|
+
email_parts.append(email_body)
|
148
|
+
email_body_with_details = "\n".join(email_parts)
|
149
|
+
|
150
|
+
logger.log(f"email_body ::: {email_body}")
|
151
|
+
new_fileName = self.create_file_from_emailBody(email_body_with_details, sender_email_addr, parameters)
|
133
152
|
new_file_path = os.path.join(order_folder, new_fileName)
|
134
153
|
|
135
154
|
with open(new_file_path, "rb") as file:
|
@@ -151,8 +170,28 @@ class Process_Category:
|
|
151
170
|
elif category == "Quotation":
|
152
171
|
action_taken = f"Mail drafted for products rate"
|
153
172
|
responseMethod, parameters = self.get_JsonArray_values(category, file_JsonArray)
|
154
|
-
logger.log(f"
|
173
|
+
logger.log(f"Parameters are ::: {parameters}")
|
174
|
+
|
175
|
+
|
176
|
+
enterpriseName = parameters["Enterprise_Name"]
|
177
|
+
schema_name = parameters["Schema_Name"].capitalize().replace("-","_")
|
178
|
+
entity_type = parameters["Entity_Type"]
|
179
|
+
server_url = ""
|
155
180
|
|
181
|
+
schemaName_Updated = enterpriseName + "_" + schema_name + "_" + entity_type
|
182
|
+
logger.log(f'\nschemaName_Updated ::: \t{schemaName_Updated}')
|
183
|
+
|
184
|
+
environment_weaviate_server_url = os.getenv('weaviate_server_url')
|
185
|
+
logger.log(f"environment_weaviate_server_url ::: [{environment_weaviate_server_url}]")
|
186
|
+
|
187
|
+
if environment_weaviate_server_url != None and environment_weaviate_server_url != '':
|
188
|
+
server_url = environment_weaviate_server_url
|
189
|
+
logger.log(f"\nProcess_cat class Quotation server_url:::\t{server_url} \t{type(server_url)}","0")
|
190
|
+
else:
|
191
|
+
if 'server_url' in parameters.keys():
|
192
|
+
server_url = parameters['server_url']
|
193
|
+
logger.log(f"\nProcess_cat class Quotation server_url:::\t{server_url} \t{type(server_url)}","0")
|
194
|
+
|
156
195
|
# Step 4: Identify customer from email using AI
|
157
196
|
customer_data = self.identify_customer(email_body, subject, Model_Name, openai_api_key, geminiAI_APIKey, localAIURL, parameters["Customer_Assistant_Id"])
|
158
197
|
logger.log(f"Identified customer is ::: {customer_data}")
|
@@ -162,18 +201,19 @@ class Process_Category:
|
|
162
201
|
# Extract customer code once
|
163
202
|
customer_code = customer_data.get("customer_code", "")
|
164
203
|
|
165
|
-
|
166
|
-
# Step 5: Identify product from email using AI
|
167
|
-
|
204
|
+
# Step 5: Identify product from email using AI
|
168
205
|
#If there is attachment then append the content in the body.
|
169
206
|
extracted_content = dataValues.get('extracted_content')
|
170
|
-
|
207
|
+
logger.log(f"extracted_content is ::: {extracted_content}")
|
208
|
+
if extracted_content != "NA" and extracted_content != None:
|
171
209
|
attachment_email_body =email_body + " \n\n" + extracted_content
|
172
210
|
products = self.identify_products(attachment_email_body, subject, Model_Name, openai_api_key, geminiAI_APIKey, localAIURL, parameters["Product_Assistant_Id"])
|
173
211
|
else:
|
174
212
|
products = self.identify_products(email_body, subject, Model_Name, openai_api_key, geminiAI_APIKey, localAIURL, parameters["Product_Assistant_Id"])
|
175
213
|
|
176
214
|
logger.log(f'Identified Products are ::: {products}')
|
215
|
+
products=self.products_item_code_lookup(products, openai_api_key, schemaName_Updated, server_url)
|
216
|
+
logger.log(f'Identified Products after Lookup are ::: {products}')
|
177
217
|
|
178
218
|
product_determination=products
|
179
219
|
|
@@ -182,6 +222,8 @@ class Process_Category:
|
|
182
222
|
item_no = product.get("item_no", "").strip()
|
183
223
|
make = product.get("make", "").strip()
|
184
224
|
rate = None
|
225
|
+
discount = "NA"
|
226
|
+
price_pickup_source = "NA"
|
185
227
|
found_rate = False
|
186
228
|
|
187
229
|
logger.log(f"item no is ::: {item_no}")
|
@@ -217,8 +259,8 @@ class Process_Category:
|
|
217
259
|
else:
|
218
260
|
logger.log(f"Process_Category - Quotation [0] No base price found for item '{item_no}' .")
|
219
261
|
product["rate"] = "NA"
|
220
|
-
product["
|
221
|
-
product["
|
262
|
+
product["price_pickup_source"]="NA"
|
263
|
+
product["discount"]="NA"
|
222
264
|
continue
|
223
265
|
|
224
266
|
# Condition 1: Exact match in special_rate_customer_wise
|
@@ -254,7 +296,7 @@ class Process_Category:
|
|
254
296
|
|
255
297
|
if discount_result:
|
256
298
|
discount_percent = discount_result[0]
|
257
|
-
|
299
|
+
discount= discount_percent
|
258
300
|
rate = raw_price * (1 - int(discount_percent) / 100)
|
259
301
|
rate = round(rate, 2)
|
260
302
|
found_rate = True
|
@@ -279,7 +321,7 @@ class Process_Category:
|
|
279
321
|
|
280
322
|
if past_sales_result:
|
281
323
|
most_common_make, past_discount = past_sales_result
|
282
|
-
|
324
|
+
discount=past_discount
|
283
325
|
if isinstance(raw_price, (int, float)):
|
284
326
|
rate = raw_price * (1 - int(past_discount) / 100)
|
285
327
|
rate = round(rate, 2)
|
@@ -303,7 +345,7 @@ class Process_Category:
|
|
303
345
|
|
304
346
|
if general_discount_result:
|
305
347
|
general_discount_percent = general_discount_result[0]
|
306
|
-
|
348
|
+
discount=general_discount_percent
|
307
349
|
rate = raw_price * (1 - int(general_discount_percent) / 100)
|
308
350
|
rate = round(rate, 2)
|
309
351
|
found_rate = True
|
@@ -315,11 +357,11 @@ class Process_Category:
|
|
315
357
|
rate = raw_price
|
316
358
|
logger.log(f"Process_Category - Quotation [5] No discounts applied. Using base price for item '{item_no}': {rate}")
|
317
359
|
price_pickup_source="PRICE_LIST"
|
318
|
-
|
360
|
+
discount = "NA"
|
319
361
|
|
320
362
|
product["rate"] = rate
|
321
|
-
product["
|
322
|
-
product["
|
363
|
+
product["price_pickup_source"]=price_pickup_source
|
364
|
+
product["discount"]=discount
|
323
365
|
|
324
366
|
db_connection.close()
|
325
367
|
|
@@ -526,7 +568,7 @@ class Process_Category:
|
|
526
568
|
logger.log("Inside identify_products")
|
527
569
|
|
528
570
|
if model_type == "OpenAI":
|
529
|
-
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,
|
571
|
+
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, quantity, price_unit, inventory_unit strictly in JSON array format(Always return the result as a JSON **array**, even if there's only one item). 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}. """
|
530
572
|
emailreplyassistant = EmailReplyAssistant()
|
531
573
|
ai_result = emailreplyassistant.identify_customer_product_reply_assitant(openai_api_key, assistant_id, email_body, subject, prompt)
|
532
574
|
|
@@ -555,13 +597,31 @@ class Process_Category:
|
|
555
597
|
return product_data
|
556
598
|
|
557
599
|
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):
|
558
|
-
logger.log("Inside generate_quotation_draft")
|
559
600
|
|
560
601
|
customer = customer_data
|
561
602
|
|
562
603
|
product_table = "Products:\n"
|
563
604
|
for product in products:
|
564
|
-
|
605
|
+
rate = product.get("rate", "NA")
|
606
|
+
quantity = product.get("quantity", "NA")
|
607
|
+
try:
|
608
|
+
total = float(rate) * float(quantity)
|
609
|
+
except:
|
610
|
+
total = rate if rate != "NA" and rate not in ("", None) else "-"
|
611
|
+
product_table += (
|
612
|
+
f'- Requested Description: {product.get("requested_description", "-")}, '
|
613
|
+
f'Item Code: {product.get("item_no", "-")}, '
|
614
|
+
f'Item Description: {product.get("description", "-")}, '
|
615
|
+
f'Make: {product.get("make", "-")}, '
|
616
|
+
f'Inventory Unit: {product.get("inventory_unit", "-")}, '
|
617
|
+
f'Price: {product.get("price", "-")}, '
|
618
|
+
f'Discount: {product.get("discount", "-")}, '
|
619
|
+
f'Rate: {rate}, '
|
620
|
+
f'Quantity: {quantity}, '
|
621
|
+
f'Total: {total}, '
|
622
|
+
f'Price Pickup Source: {product.get("price_pickup_source", "-")}, '
|
623
|
+
f'Availability: ""\n'
|
624
|
+
)
|
565
625
|
|
566
626
|
if model_type == "OpenAI":
|
567
627
|
prompt = f"""
|
@@ -571,7 +631,13 @@ class Process_Category:
|
|
571
631
|
Customer Code: {customer.get('customer_code', '')}
|
572
632
|
|
573
633
|
{product_table}
|
574
|
-
|
634
|
+
Ensure the table has the following columns in this exact order:
|
635
|
+
Sr. No., Requested Description, Item Code, Item Description, Make, Inventory Unit, Price, Discount, Rate, Quantity, Total, Price Pickup Source, Availability
|
636
|
+
|
637
|
+
- If any value is missing, use a dash ("-") instead.
|
638
|
+
- "Total" is calculated as Rate × Quantity.
|
639
|
+
- "Availability" should be a blank column.
|
640
|
+
- Only the numeric values in the table rows are right-aligned(Ensure the alignment applies only to the data cells (i.e., <td>), not the header cells (<th>).)
|
575
641
|
Original Email Subject: {subject}
|
576
642
|
|
577
643
|
Return only the following JSON String format:
|
@@ -788,6 +854,17 @@ class Process_Category:
|
|
788
854
|
with the name user_id.csv.
|
789
855
|
"""
|
790
856
|
|
857
|
+
logger.log(f"The response am getting in csv is : {response}")
|
858
|
+
match = re.search(
|
859
|
+
r'Content-Transfer-Encoding:\s*base64\s+([\s\S]+?)\n--',
|
860
|
+
response,
|
861
|
+
re.IGNORECASE
|
862
|
+
)
|
863
|
+
if match:
|
864
|
+
response = self.extract_html_from_mime(response)
|
865
|
+
|
866
|
+
logger.log(f"The response after am getting in csv is : {response}")
|
867
|
+
|
791
868
|
# Ensure the Mail_log folder exists
|
792
869
|
log_folder = "Mail_log"
|
793
870
|
os.makedirs(log_folder, exist_ok=True)
|
@@ -911,4 +988,86 @@ class Process_Category:
|
|
911
988
|
if user_id:
|
912
989
|
return user_id.value
|
913
990
|
return None
|
991
|
+
|
992
|
+
def extract_html_from_mime(self, raw_data):
|
993
|
+
msg = message_from_string(raw_data)
|
994
|
+
|
995
|
+
if msg.is_multipart():
|
996
|
+
for part in msg.walk():
|
997
|
+
content_type = part.get_content_type()
|
998
|
+
content_encoding = part.get("Content-Transfer-Encoding", "").lower()
|
999
|
+
|
1000
|
+
# Look for text/html part with base64 encoding
|
1001
|
+
if content_type == "text/html" and content_encoding == "base64":
|
1002
|
+
payload = part.get_payload(decode=True)
|
1003
|
+
return payload.decode(part.get_content_charset() or 'utf-8')
|
1004
|
+
return "No HTML content found."
|
914
1005
|
|
1006
|
+
def products_item_code_lookup(self, products, openai_api_key, schemaName_Updated, server_url):
|
1007
|
+
try:
|
1008
|
+
logger.log(f'\nproduct_Json : {products}')
|
1009
|
+
logger.log(f'\nopenai_api_key : {openai_api_key}')
|
1010
|
+
logger.log(f'\nschemaName_Updated : {schemaName_Updated}')
|
1011
|
+
logger.log(f'\nserver_url : {server_url}')
|
1012
|
+
alphaValue = 0.54
|
1013
|
+
|
1014
|
+
client = weaviate.Client(server_url,additional_headers={"X-OpenAI-Api-Key": openai_api_key})
|
1015
|
+
logger.log(f'Connection is establish : {client.is_ready()}')
|
1016
|
+
|
1017
|
+
schemaClasslist = [i['class'] for i in client.schema.get()["classes"]]
|
1018
|
+
logger.log(f'schemaClasslist : {schemaClasslist}')
|
1019
|
+
|
1020
|
+
for product in products:
|
1021
|
+
item_no = product.get("item_no", "NA")
|
1022
|
+
item_name = product.get("requested_description", "NA")
|
1023
|
+
if item_no == "NA":
|
1024
|
+
inputQuery = item_name.upper().replace("N/A","").replace("."," ").replace(","," ").replace("-"," ").replace("_"," ")
|
1025
|
+
logger.log(f'inputQuery : {inputQuery}')
|
1026
|
+
|
1027
|
+
if schemaName_Updated in schemaClasslist:
|
1028
|
+
logger.log(f'Inside schemaClasslist')
|
1029
|
+
response = (
|
1030
|
+
client.query
|
1031
|
+
.get(schemaName_Updated, ["description", "answer","phy_attrib_2","phy_attrib_3","phy_attrib_4"])
|
1032
|
+
.with_hybrid(
|
1033
|
+
alpha = alphaValue,
|
1034
|
+
query = inputQuery.strip() ,
|
1035
|
+
fusion_type = HybridFusion.RELATIVE_SCORE
|
1036
|
+
)
|
1037
|
+
.with_additional('score')
|
1038
|
+
.with_limit(10)
|
1039
|
+
.do()
|
1040
|
+
)
|
1041
|
+
logger.log(f"Input ::: {item_name}")
|
1042
|
+
if response != {}:
|
1043
|
+
response_List = response['data']['Get'][schemaName_Updated]
|
1044
|
+
product['description'] = response_List[0]['description']
|
1045
|
+
product['item_no'] = response_List[0]['answer']
|
1046
|
+
# product['cas_no'] = response_List[0]['phy_attrib_1']
|
1047
|
+
product['make'] = response_List[0]['phy_attrib_2']
|
1048
|
+
product["price"] = response_List[0]['phy_attrib_3']
|
1049
|
+
product["inventory_unit"] = response_List[0]['phy_attrib_4']
|
1050
|
+
|
1051
|
+
for index in range(len(response_List)):
|
1052
|
+
description = response_List[index]['description']
|
1053
|
+
description = description.upper().replace("N/A","").replace("."," ").replace(","," ").replace("-"," ").replace("_"," ")
|
1054
|
+
|
1055
|
+
descr_replaced = description.replace(" ", "")
|
1056
|
+
inputQuery_replaced = inputQuery.replace(" ", "")
|
1057
|
+
|
1058
|
+
if descr_replaced == inputQuery_replaced:
|
1059
|
+
logger.log(f"\n Input::: '{inputQuery_replaced}' MATCHEDD with description ::: '{descr_replaced}' \n")
|
1060
|
+
product['description'] = response_List[index]['description']
|
1061
|
+
product['item_no'] = response_List[index]['answer']
|
1062
|
+
# product['cas_no'] = response_List[index]['phy_attrib_1']
|
1063
|
+
product['make'] = response_List[index]['phy_attrib_2']
|
1064
|
+
product["price"] = response_List[index]['phy_attrib_3']
|
1065
|
+
product["inventory_unit"] = response_List[index]['phy_attrib_4']
|
1066
|
+
break
|
1067
|
+
else:
|
1068
|
+
logger.log(f"\n Input '{inputQuery_replaced}' not matched with returned response description '{descr_replaced}'\n ")
|
1069
|
+
|
1070
|
+
return products
|
1071
|
+
|
1072
|
+
except Exception as error:
|
1073
|
+
raise str(error)
|
{AIEmailAutomationUtility-0.0.32.dist-info → AIEmailAutomationUtility-0.0.34.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.34
|
4
|
+
Summary: Added a vector lookup for fallback products those return as NA.
|
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
|
+
Added a vector lookup for fallback products those return as NA.
|
@@ -0,0 +1,15 @@
|
|
1
|
+
AIEmailAutomationUtility/EmailReplyAssistant.py,sha256=R_wJna3-ITsVxQEccryhM93T_Nf_Oxo8DXnS-sDN8VE,6679
|
2
|
+
AIEmailAutomationUtility/Email_Classification.py,sha256=Ar0g4Ff8HOT7xICktd3nP_C_vCyeY-xCpUjVCVRWAyc,9417
|
3
|
+
AIEmailAutomationUtility/Email_DocumentUploader.py,sha256=BWNRt2X-E2HCogBaKDfl7cZZNSkZUeIsVs8iXjFjH88,3218
|
4
|
+
AIEmailAutomationUtility/Email_Draft.py,sha256=JYZijUh_zan2asyMYQwIBwIpGNJ5SSQGma5AL1meaXk,7808
|
5
|
+
AIEmailAutomationUtility/Email_Read.py,sha256=_JwHTJZmxjuMPTbn90D9YStW7NSJd3t4R_cwUZ1tn20,31470
|
6
|
+
AIEmailAutomationUtility/Email_Upload_Document.py,sha256=3bdkxfDlwoeRp-46KPw2Gs1dqBhEIoA1yE5GCudpdV8,1320
|
7
|
+
AIEmailAutomationUtility/Process_Category.py,sha256=IMqvDVvuMNeLtQ2heFIyp1UKkz2AN1hAT02lXo8Pywk,53664
|
8
|
+
AIEmailAutomationUtility/Save_Draft.py,sha256=yzLgFN14I_lXE6qL0I3tKNduvcnWdbsY9i2mKdTtio4,5348
|
9
|
+
AIEmailAutomationUtility/Save_Transaction.py,sha256=Gg1w6hhzHmEFjsuzYvkq-3-EsWReetjLHsYSv5YIGgM,3816
|
10
|
+
AIEmailAutomationUtility/__init__.py,sha256=Jad3IdPRsVMeLqEEh-FbCrc1lE2tzJO2DTG5Hgmxh5g,391
|
11
|
+
AIEmailAutomationUtility-0.0.34.dist-info/LICENCE.txt,sha256=2qX9IkEUBx0VJp1Vh9O2dsRwE-IpYId0lXDyn7OVsJ8,1073
|
12
|
+
AIEmailAutomationUtility-0.0.34.dist-info/METADATA,sha256=eCpEKv1Cvin8-cceIQZ6OvbOsZ36o9EeijDAYgrM7Pw,627
|
13
|
+
AIEmailAutomationUtility-0.0.34.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
14
|
+
AIEmailAutomationUtility-0.0.34.dist-info/top_level.txt,sha256=3jTWrTUblVkaP7mpwY2UBSnrlfot5Ykpfsehyke-Uzw,25
|
15
|
+
AIEmailAutomationUtility-0.0.34.dist-info/RECORD,,
|
@@ -1,15 +0,0 @@
|
|
1
|
-
AIEmailAutomationUtility/EmailReplyAssistant.py,sha256=R_wJna3-ITsVxQEccryhM93T_Nf_Oxo8DXnS-sDN8VE,6679
|
2
|
-
AIEmailAutomationUtility/Email_Classification.py,sha256=Ar0g4Ff8HOT7xICktd3nP_C_vCyeY-xCpUjVCVRWAyc,9417
|
3
|
-
AIEmailAutomationUtility/Email_DocumentUploader.py,sha256=YJu4tuTHr0K-5vuds9gZfj-Hwsgm4MuAOP39Lmu_t98,3219
|
4
|
-
AIEmailAutomationUtility/Email_Draft.py,sha256=DcyBeDaE8CReKHnHxLiz-o2tDxuUgwy91c4k0qhQbVw,7749
|
5
|
-
AIEmailAutomationUtility/Email_Read.py,sha256=zE2dK4h0XfKWuSuMJs3E2U-yMPHzRtBfNSdP74h_pDI,30743
|
6
|
-
AIEmailAutomationUtility/Email_Upload_Document.py,sha256=3bdkxfDlwoeRp-46KPw2Gs1dqBhEIoA1yE5GCudpdV8,1320
|
7
|
-
AIEmailAutomationUtility/Process_Category.py,sha256=xXiXYf_dmscKO6scFOMRCWLgKhsV8RsCVK1AXPnE1DI,44695
|
8
|
-
AIEmailAutomationUtility/Save_Draft.py,sha256=yzLgFN14I_lXE6qL0I3tKNduvcnWdbsY9i2mKdTtio4,5348
|
9
|
-
AIEmailAutomationUtility/Save_Transaction.py,sha256=Gg1w6hhzHmEFjsuzYvkq-3-EsWReetjLHsYSv5YIGgM,3816
|
10
|
-
AIEmailAutomationUtility/__init__.py,sha256=Jad3IdPRsVMeLqEEh-FbCrc1lE2tzJO2DTG5Hgmxh5g,391
|
11
|
-
AIEmailAutomationUtility-0.0.32.dist-info/LICENCE.txt,sha256=2qX9IkEUBx0VJp1Vh9O2dsRwE-IpYId0lXDyn7OVsJ8,1073
|
12
|
-
AIEmailAutomationUtility-0.0.32.dist-info/METADATA,sha256=m0b6nXm2W1DSYwxU9Mbt8oPd7ujQ90BDc8I9ohdK3ck,611
|
13
|
-
AIEmailAutomationUtility-0.0.32.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
14
|
-
AIEmailAutomationUtility-0.0.32.dist-info/top_level.txt,sha256=3jTWrTUblVkaP7mpwY2UBSnrlfot5Ykpfsehyke-Uzw,25
|
15
|
-
AIEmailAutomationUtility-0.0.32.dist-info/RECORD,,
|
{AIEmailAutomationUtility-0.0.32.dist-info → AIEmailAutomationUtility-0.0.34.dist-info}/LICENCE.txt
RENAMED
File without changes
|
File without changes
|