Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -15,6 +15,34 @@ SALESFORCE_USERNAME = "venkatramana@sandbox.com"
|
|
| 15 |
SALESFORCE_PASSWORD = "Venkat12345@"
|
| 16 |
SALESFORCE_SECURITY_TOKEN = "GhcJJmjBEefdnukJoz4CAQlR"
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
# π§ Initialize PaddleOCR
|
| 19 |
ocr = PaddleOCR(use_angle_cls=True, lang='en')
|
| 20 |
|
|
@@ -26,64 +54,28 @@ def extract_text(image):
|
|
| 26 |
extracted_text.append(line[1][0])
|
| 27 |
return "\n".join(extracted_text)
|
| 28 |
|
| 29 |
-
# Function to
|
| 30 |
-
def
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
df = pd.DataFrame(records)
|
| 52 |
-
df.rename(columns={
|
| 53 |
-
'Product_Name__c': 'Product Name',
|
| 54 |
-
'Modal_Name__c': 'Model Name',
|
| 55 |
-
'Current_Stocks__c': 'Current Stocks'
|
| 56 |
-
}, inplace=True)
|
| 57 |
-
df.drop(columns=['attributes'], inplace=True, errors='ignore')
|
| 58 |
-
|
| 59 |
-
return df, generate_bar_graph(df)
|
| 60 |
-
|
| 61 |
-
except Exception as e:
|
| 62 |
-
return None, None
|
| 63 |
-
|
| 64 |
-
# Function to generate a bar graph from Salesforce data
|
| 65 |
-
def generate_bar_graph(df):
|
| 66 |
-
try:
|
| 67 |
-
fig, ax = plt.subplots(figsize=(12, 8))
|
| 68 |
-
df.plot(kind='bar', x="Product Name", y="Current Stocks", ax=ax, legend=False)
|
| 69 |
-
ax.set_title("Stock Distribution by Product Name")
|
| 70 |
-
ax.set_xlabel("Product Name")
|
| 71 |
-
ax.set_ylabel("Current Stocks")
|
| 72 |
-
plt.xticks(rotation=45, ha="right", fontsize=10)
|
| 73 |
-
plt.tight_layout()
|
| 74 |
-
buffer = BytesIO()
|
| 75 |
-
plt.savefig(buffer, format="png")
|
| 76 |
-
buffer.seek(0)
|
| 77 |
-
return Image.open(buffer)
|
| 78 |
-
except Exception as e:
|
| 79 |
-
return None
|
| 80 |
-
|
| 81 |
-
# Function to generate Salesforce data table and graph
|
| 82 |
-
def generate_salesforce_data():
|
| 83 |
-
df, graph = fetch_salesforce_data()
|
| 84 |
-
if df is not None:
|
| 85 |
-
return df.to_html(index=False), graph
|
| 86 |
-
return "<p>No Data Available</p>", None
|
| 87 |
|
| 88 |
# Function to export extracted data to Salesforce
|
| 89 |
def export_to_salesforce(mode, entry_type, quantity, extracted_text):
|
|
@@ -95,47 +87,46 @@ def export_to_salesforce(mode, entry_type, quantity, extracted_text):
|
|
| 95 |
)
|
| 96 |
|
| 97 |
# Determine Object & Field Mapping
|
| 98 |
-
object_name = None
|
| 99 |
-
product_field_name = "Product_Name__c"
|
| 100 |
-
model_field_name = "Modal_Name__c"
|
| 101 |
-
field_name = None
|
| 102 |
|
| 103 |
if mode == "Entry":
|
| 104 |
-
if entry_type == "Sales"
|
| 105 |
-
|
| 106 |
-
field_name = "Quantity__c"
|
| 107 |
-
elif entry_type == "Non-Sales":
|
| 108 |
-
object_name = "UNBILLING_DATA__c"
|
| 109 |
-
field_name = "TotalQuantity__c"
|
| 110 |
elif mode == "Exit":
|
| 111 |
-
if entry_type == "Sales"
|
| 112 |
-
|
| 113 |
-
field_name = "Quantity_Sold__c"
|
| 114 |
-
elif entry_type == "Non-Sales":
|
| 115 |
-
object_name = "Un_Billable__c"
|
| 116 |
-
field_name = "Sold_Out__c"
|
| 117 |
|
| 118 |
if not object_name or not field_name:
|
| 119 |
-
return "Invalid mode or entry type."
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
|
| 121 |
-
# Extract Product Name
|
| 122 |
-
product_name = extracted_text.split("\n")[0] if extracted_text else None
|
| 123 |
if not product_name:
|
| 124 |
-
return "β
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
|
| 126 |
# Check if record exists
|
| 127 |
-
query = f"SELECT Id
|
| 128 |
response = sf.query(query)
|
| 129 |
|
| 130 |
if response["records"]:
|
| 131 |
-
# Update existing record
|
| 132 |
record_id = response["records"][0]["Id"]
|
| 133 |
-
|
| 134 |
-
return f"β
Updated record for
|
| 135 |
else:
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
return f"β
Data successfully exported to Salesforce object {object_name}."
|
| 139 |
|
| 140 |
except Exception as e:
|
| 141 |
return f"β Error exporting data to Salesforce: {str(e)}"
|
|
@@ -144,10 +135,10 @@ def export_to_salesforce(mode, entry_type, quantity, extracted_text):
|
|
| 144 |
def process_image(image, mode, entry_type, quantity):
|
| 145 |
extracted_text = extract_text(image)
|
| 146 |
if not extracted_text:
|
| 147 |
-
return "No text detected in the image.", None
|
| 148 |
|
| 149 |
result = export_to_salesforce(mode, entry_type, quantity, extracted_text)
|
| 150 |
-
return f"Extracted Text:\n{extracted_text}", result
|
| 151 |
|
| 152 |
# Gradio App
|
| 153 |
def app():
|
|
@@ -163,7 +154,7 @@ def app():
|
|
| 163 |
quantity_input = gr.Number(label="π’ Quantity", value=1, interactive=True)
|
| 164 |
|
| 165 |
with gr.Column():
|
| 166 |
-
image_view = gr.Text(label="π
|
| 167 |
result_output = gr.Text(label="π Salesforce Export Result", interactive=False)
|
| 168 |
submit_button = gr.Button("π Process & Export")
|
| 169 |
|
|
|
|
| 15 |
SALESFORCE_PASSWORD = "Venkat12345@"
|
| 16 |
SALESFORCE_SECURITY_TOKEN = "GhcJJmjBEefdnukJoz4CAQlR"
|
| 17 |
|
| 18 |
+
# π Product Name List for Fuzzy Matching
|
| 19 |
+
PRODUCT_NAMES = [
|
| 20 |
+
"Centrifugal mono block pump", "SINGLE PHASE MOTOR STARTER", "EasyPact EZC 100",
|
| 21 |
+
"Openwell Submersible Pumpset", "Electric Motor", "Self Priming Pump",
|
| 22 |
+
"Control panel for single phase submersible pumps", "MOTOR", "Submersible pump set",
|
| 23 |
+
"Fusion submersible pump set", "DCT", "Shock proof water proof", "CG COMMERCIAL MOTORS",
|
| 24 |
+
"Flowshine Submersible pump", "5HP AV1 XL Kirloskar Pump",
|
| 25 |
+
"Submersible pump", "WB15X", "Havells open well Submersible pump",
|
| 26 |
+
"Bertolini pump CK3 90pp", "Water Tank, Filters, Water Pump",
|
| 27 |
+
"Earthmax Pump", "Electric Motor with Pump BodyBlue and White",
|
| 28 |
+
]
|
| 29 |
+
|
| 30 |
+
# π Attribute Mapping (Readable Name β Salesforce API Name)
|
| 31 |
+
ATTRIBUTE_MAPPING = {
|
| 32 |
+
"Product name": "Product_Name__c",
|
| 33 |
+
"Model": "Model__c",
|
| 34 |
+
"Quantity": "Quantity__c",
|
| 35 |
+
"Voltage": "Voltage__c",
|
| 36 |
+
"Horsepower": "Horsepower__c",
|
| 37 |
+
"Serial Number": "Serialnumber__c",
|
| 38 |
+
"Warranty": "Warranty__c",
|
| 39 |
+
"Brand": "Brand__c",
|
| 40 |
+
"Motor Phase": "Motorphase__c",
|
| 41 |
+
"Size": "Size__c",
|
| 42 |
+
"Frame": "Frame__c",
|
| 43 |
+
"Usage": "Usage_Application__c",
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
# π§ Initialize PaddleOCR
|
| 47 |
ocr = PaddleOCR(use_angle_cls=True, lang='en')
|
| 48 |
|
|
|
|
| 54 |
extracted_text.append(line[1][0])
|
| 55 |
return "\n".join(extracted_text)
|
| 56 |
|
| 57 |
+
# Function to match product name using fuzzy matching
|
| 58 |
+
def match_product_name(extracted_text):
|
| 59 |
+
best_match, best_score = None, 0
|
| 60 |
+
for line in extracted_text.split("\n"):
|
| 61 |
+
match, score = process.extractOne(line, PRODUCT_NAMES)
|
| 62 |
+
if score > best_score:
|
| 63 |
+
best_match, best_score = match, score
|
| 64 |
+
return best_match if best_score >= 70 else None # Threshold: 70
|
| 65 |
+
|
| 66 |
+
# Function to extract attributes from text
|
| 67 |
+
def extract_attributes(extracted_text):
|
| 68 |
+
attributes = {}
|
| 69 |
+
for readable_attr, sf_attr in ATTRIBUTE_MAPPING.items():
|
| 70 |
+
pattern = rf"{re.escape(readable_attr)}[:\-]?\s*(.+)"
|
| 71 |
+
match = re.search(pattern, extracted_text, re.IGNORECASE)
|
| 72 |
+
if match:
|
| 73 |
+
attributes[readable_attr] = match.group(1).strip()
|
| 74 |
+
return attributes
|
| 75 |
+
|
| 76 |
+
# Function to filter attributes for valid Salesforce fields
|
| 77 |
+
def filter_valid_attributes(attributes, valid_fields):
|
| 78 |
+
return {ATTRIBUTE_MAPPING[key]: value for key, value in attributes.items() if ATTRIBUTE_MAPPING[key] in valid_fields}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
# Function to export extracted data to Salesforce
|
| 81 |
def export_to_salesforce(mode, entry_type, quantity, extracted_text):
|
|
|
|
| 87 |
)
|
| 88 |
|
| 89 |
# Determine Object & Field Mapping
|
| 90 |
+
object_name, field_name = None, None
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
if mode == "Entry":
|
| 93 |
+
object_name = "Inventory_Management__c" if entry_type == "Sales" else "Un_Billable__c"
|
| 94 |
+
field_name = "Quantity__c"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
elif mode == "Exit":
|
| 96 |
+
object_name = "Inventory_Management__c" if entry_type == "Sales" else "Un_Billable__c"
|
| 97 |
+
field_name = "Quantity_Sold__c"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
|
| 99 |
if not object_name or not field_name:
|
| 100 |
+
return "β Invalid mode or entry type."
|
| 101 |
+
|
| 102 |
+
# Extract Product Name & Attributes
|
| 103 |
+
product_name = match_product_name(extracted_text)
|
| 104 |
+
attributes = extract_attributes(extracted_text)
|
| 105 |
|
|
|
|
|
|
|
| 106 |
if not product_name:
|
| 107 |
+
return "β No matching product found."
|
| 108 |
+
|
| 109 |
+
attributes["Product name"] = product_name
|
| 110 |
+
|
| 111 |
+
# Validate Salesforce fields
|
| 112 |
+
sf_object = sf.__getattr__(object_name)
|
| 113 |
+
schema = sf_object.describe()
|
| 114 |
+
valid_fields = {field["name"] for field in schema["fields"]}
|
| 115 |
+
|
| 116 |
+
filtered_attributes = filter_valid_attributes(attributes, valid_fields)
|
| 117 |
+
filtered_attributes[field_name] = quantity
|
| 118 |
|
| 119 |
# Check if record exists
|
| 120 |
+
query = f"SELECT Id FROM {object_name} WHERE Product_Name__c = '{product_name}' LIMIT 1"
|
| 121 |
response = sf.query(query)
|
| 122 |
|
| 123 |
if response["records"]:
|
|
|
|
| 124 |
record_id = response["records"][0]["Id"]
|
| 125 |
+
sf_object.update(record_id, filtered_attributes)
|
| 126 |
+
return f"β
Updated record for '{product_name}' in {object_name}."
|
| 127 |
else:
|
| 128 |
+
sf_object.create(filtered_attributes)
|
| 129 |
+
return f"β
Created new record in {object_name} for '{product_name}'."
|
|
|
|
| 130 |
|
| 131 |
except Exception as e:
|
| 132 |
return f"β Error exporting data to Salesforce: {str(e)}"
|
|
|
|
| 135 |
def process_image(image, mode, entry_type, quantity):
|
| 136 |
extracted_text = extract_text(image)
|
| 137 |
if not extracted_text:
|
| 138 |
+
return "β No text detected in the image.", None
|
| 139 |
|
| 140 |
result = export_to_salesforce(mode, entry_type, quantity, extracted_text)
|
| 141 |
+
return f"π Extracted Text:\n{extracted_text}", result
|
| 142 |
|
| 143 |
# Gradio App
|
| 144 |
def app():
|
|
|
|
| 154 |
quantity_input = gr.Number(label="π’ Quantity", value=1, interactive=True)
|
| 155 |
|
| 156 |
with gr.Column():
|
| 157 |
+
image_view = gr.Text(label="π Extracted Data", interactive=False)
|
| 158 |
result_output = gr.Text(label="π Salesforce Export Result", interactive=False)
|
| 159 |
submit_button = gr.Button("π Process & Export")
|
| 160 |
|