Duplicatespace / app.py
Ajay98's picture
Update app.py
87a3951 verified
raw
history blame
12.8 kB
import os
from paddleocr import PaddleOCR
from PIL import Image
import gradio as gr
import requests
import re
from simple_salesforce import Salesforce
import pandas as pd
import matplotlib.pyplot as plt
from io import BytesIO
from fuzzywuzzy import process
gr.Image(
type="numpy",
source="camera", # Enables camera access
label="Upload or Take a Photo",
tool="editor", # Optional: Add editing tools for cropping or annotations
mirror_webcam=False # Ensures the image is not mirrored
)
from PIL import ImageOps
def correct_orientation(image):
return ImageOps.mirror(image)
# Attribute mappings: readable names to Salesforce API names
ATTRIBUTE_MAPPING = {
"Product name": "Productname__c",
"Colour": "Colour__c",
"Motortype": "Motortype__c",
"Frequency": "Frequency__c",
"Grossweight": "Grossweight__c",
"Ratio": "Ratio__c",
"MotorFrame": "Motorframe__c",
"Model": "Model__c",
"Speed": "Speed__c",
"Quantity": "Quantity__c",
"Voltage": "Voltage__c",
"Material": "Material__c",
"Type": "Type__c",
"Horsepower": "Horsepower__c",
"Consignee": "Consignee__c",
"LOT": "LOT__c",
"Stage": "Stage__c",
"Outlet": "Outlet__c",
"Serialnumber": "Serialnumber__c",
"HeadSize": "Headsize__c",
"Deliverysize": "Deliverysize__c",
"Phase": "Phase__c",
"Size": "Size__c",
"MRP": "MRP__c",
"Usebefore": "Usebefore__c",
"Height": "Height__c",
"MaximumDischarge Flow": "Maximumdischargeflow__c",
"DischargeRange": "Dischargeflow__c",
"Assembledby": "Manufacturer__c",
"Manufacturedate": "Manufacturedate__c",
"Companyname": "Companyname__c",
"Customercarenumber": "Customercarenumber__c",
"SellerAddress": "Selleraddress__c",
"Selleremail": "Selleremail__c",
"GSTIN": "GSTIN__c",
"Totalamount": "Totalamount__c",
"Paymentstatus": "Paymentstatus__c",
"Paymentmethod": "Paymentstatus__c",
"Invoicedate": "Manufacturedate__c",
"Warranty": "Warranty__c",
"Brand": "Brand__c",
"Motorhorsepower": "Motorhorsepower__c",
"Power": "Power__c",
"Motorphase": "Motorphase__c",
"Enginetype": "Enginetype__c",
"Tankcapacity": "Tankcapacity__c",
"Head": "Head__c",
"Usage/Application": "Usage_Application__c",
"Volts": "volts__c",
"Hertz": "Hertz__c",
"Frame": "frame__c",
"Mounting": "Mounting__c",
"Tollfreenumber": "Tollfreenumber__c",
"Pipesize": "Pipesize__c",
"Manufacturer": "Manufacturer__c",
"Office": "Office__c",
"SRnumber": "SRnumber__c",
"TypeOfEndUse": "TypeOfEndUse__c",
"Model Name": "Model_Name_Number__c",
"coolingmethod": "coolingmethod__c"
}
# List of product names to match
PRODUCT_NAMES = [
"Centrifugal mono block pump", "SINGLE PHASE MOTOR STARTER", "EasyPact EZC 100",
"Openwell Submersible Pumpset", "Electric Motor", "Self Priming Pump",
"Control panel for single phase submersible pumps", "MOTOR", "Submersible pump set",
"Fusion submersible pump set", "DCT", "Shock proof water proof", "CG COMMERCIAL MOTORS", "Fusion",
"control panel for single phase submerisible pumps",
"single phase digital starter dry run and timer panel", "5HP AV1 XL Kirloskar Pump",
"Phase stainless steel submersible pump", "Submersible pump", "WB15X",
"Vtype self priming pump", "SP SHINE DISC", "havells submersible pump",
"Havells open well Submersible pump", "Bertolini pump CK3 90pp",
"WPA 772 Water Pump Assy", "bertolini TTL triplex high pressure plunger pumps",
"Generic plunger high pressure pump", "Apple Normal, Banana",
"Cast Iron KSb centrifugal pump", "5.5kw Water Pump",
"KSB reliable i line centrifuged pumps", "Apple Normal, Orange, Banana",
"Positive API 6745 hydraulic diaphragm pump", "1/2 inch Fuel Hose Pipe", "Kirloskar Water Pump",
"Rotodel motor pump", "PVC Electrical Insulation Materials",
"Electric kirloskar domestic water pump", "Electrical Insulation Materials",
"sellowell motor pump", "bhupathi submersible pump set",
"Flowshine Submersible pump set", "Index submersible pump",
"Wintoss Plastic Electric Switch Board", "Electric 18 watt ujagar cooler pump",
"Generator Service", "LG WM FHT1207ZWL, LG REF GL-S292RSCY",
"Water tank, Filters, Water Pump", "MS Control Submersible Panel",
"Centrifugal Monoblock Pumps", "Electric Motor with Pump BodyBlue and White",
"Various Repair and Maintenance Parts", "Earthmax Pump",
"Water Tank, Filters, Water Pump", "Centrifugal Water Pump for Agriculture",
"mono block pumps"
]
# Salesforce credentials
SALESFORCE_USERNAME = "venkatramana@sandbox.com"
SALESFORCE_PASSWORD = "Venkat12345@"
SALESFORCE_SECURITY_TOKEN = "GhcJJmjBEefdnukJoz4CAQlR"
# Initialize PaddleOCR
ocr = PaddleOCR(use_angle_cls=True, lang='en')
# Function to extract text using PaddleOCR
def extract_text(image):
result = ocr.ocr(image)
extracted_text = []
for line in result[0]:
extracted_text.append(line[1][0])
return "\n".join(extracted_text)
# Function to interact with Salesforce based on mode and type
def interact_with_salesforce(mode, entry_type, quantity, extracted_text):
try:
sf = Salesforce(
username=SALESFORCE_USERNAME,
password=SALESFORCE_PASSWORD,
security_token=SALESFORCE_SECURITY_TOKEN
)
# Mapping mode and entry_type to Salesforce object and field
object_name = None
field_name = None
product_field_name = "Product_Name__c" # Correct field for product name in the object
model_field_name = "Modal_Name__c" # Correct field for model name in the object
if mode == "Entry":
if entry_type == "Sales":
object_name = "VENKATA_RAMANA_MOTORS__c"
field_name = "Quantity__c"
elif entry_type == "Non-Sales":
object_name = "UNBILLING_DATA__c"
field_name = "TotalQuantity__c"
elif mode == "Exit":
if entry_type == "Sales":
object_name = "Inventory_Management__c"
product_field_name = "Product_Name__c"
model_field_name = "Modal_Name__c"
field_name = "Quantity_Sold__c"
elif entry_type == "Non-Sales":
object_name = "Un_Billable__c"
product_field_name = "Product_Name__c"
model_field_name = "Model_Name__c"
field_name = "Sold_Out__c"
if not object_name or not field_name:
return "Invalid mode or entry type."
# Get valid fields for the specified Salesforce object
sf_object = sf.__getattr__(object_name)
schema = sf_object.describe()
valid_fields = {field["name"] for field in schema["fields"]}
# Extract product name or model number
product_name_match = re.search(r"Product name[:\-]?\s*(.+)", extracted_text, re.IGNORECASE)
model_name_match = re.search(r"Model[:\-]?\s*(.+)", extracted_text, re.IGNORECASE)
if not product_name_match and not model_name_match:
return "Product name or model name not found in the extracted text."
product_name_value = product_name_match.group(1).strip() if product_name_match else None
model_name_value = model_name_match.group(1).strip() if model_name_match else None
# Query for existing record by product name or model name
if mode == "Exit":
query = f"SELECT Id, {field_name} FROM {object_name} WHERE {product_field_name} = '{product_name_value}' OR {model_field_name} = '{model_name_value}' LIMIT 1"
response = sf.query(query)
if response["records"]:
record_id = response["records"][0]["Id"]
current_quantity = response["records"][0].get(field_name, 0) or 0 # Ensure current_quantity is not None
updated_quantity = max(0, current_quantity + quantity) # Add the quantity directly for sales
sf_object.update(record_id, {field_name: updated_quantity})
return f"Updated record for product '{product_name_value}' in {object_name}. New {field_name}: {updated_quantity}."
else:
return f"No matching record found for product '{product_name_value}' in {object_name}."
else:
# For Entry mode, include all mapped attributes
structured_data = {field_name: quantity}
for readable_attr, sf_attr in ATTRIBUTE_MAPPING.items():
pattern = rf"{re.escape(readable_attr)}[:\-]?\s*(.+)"
match = re.search(pattern, extracted_text, re.IGNORECASE)
if match and sf_attr in valid_fields:
structured_data[sf_attr] = match.group(1).strip()
# Insert data into Salesforce
sf_object.create(structured_data)
return f"Data successfully exported to Salesforce object {object_name}."
except Exception as e:
return f"Error interacting with Salesforce: {str(e)}"
# Function to pull data from Salesforce MotorDataAPI
def pull_data_from_motor_api():
try:
sf = Salesforce(
username=SALESFORCE_USERNAME,
password=SALESFORCE_PASSWORD,
security_token=SALESFORCE_SECURITY_TOKEN,
)
motor_data = sf.apexecute("MotorDataAPI/", method="GET")
return motor_data # API returns the list of records
except Exception as e:
return f"Error pulling data from MotorDataAPI: {str(e)}"
# Function to format Salesforce data into a DataFrame with readable headers
def format_salesforce_data():
try:
data = pull_data_from_motor_api()
if isinstance(data, list):
df = pd.DataFrame(data)
df = df.rename(columns={
"Product_Name__c": "Product Name",
"Modal_Name__c": "Model Name",
"Current_Stocks__c": "Current Stocks"
})
# Remove unnecessary columns
df = df[["Product Name", "Model Name", "Current Stocks"]]
return df
else:
return None
except Exception as e:
return None
# Function to generate a bar graph from Salesforce data
def generate_bar_graph(df):
try:
fig, ax = plt.subplots(figsize=(12, 8))
df.plot(kind='bar', x="Product Name", y="Current Stocks", ax=ax, legend=False)
ax.set_title("Stock Distribution by Product Name")
ax.set_xlabel("Product Name")
ax.set_ylabel("Current Stocks")
plt.xticks(rotation=45, ha="right", fontsize=10)
plt.tight_layout()
buffer = BytesIO()
plt.savefig(buffer, format="png")
buffer.seek(0)
img = Image.open(buffer)
return img
except Exception as e:
return None
# Unified function to handle image processing and Salesforce interaction
def process_image(image, mode, entry_type, quantity):
extracted_text = extract_text(image)
if not extracted_text:
return "No text detected in the image.", None
# Interact with Salesforce
message = interact_with_salesforce(mode, entry_type, quantity, extracted_text)
return extracted_text, message
# Gradio Interface
def app():
df = format_salesforce_data()
table_component = None
bar_graph_component = None
if df is not None:
table_component = df.to_html(index=False)
bar_graph_image = generate_bar_graph(df)
if bar_graph_image:
bar_graph_component = bar_graph_image
return gr.TabbedInterface([
gr.Interface(
fn=process_image,
inputs=[
gr.Image(type="numpy", label="Upload Image"),
gr.Dropdown(label="Mode", choices=["Entry", "Exit"], value="Entry"),
gr.Radio(label="Entry Type", choices=["Sales", "Non-Sales"], value="Sales"),
gr.Number(label="Quantity", value=1, interactive=True),
],
outputs=[
gr.Text(label="Image Data Viewer"),
gr.Text(label="Result")
],
title="Salesforce Export",
description="Upload an image, select Entry/Exit mode and Sales/Non-Sales type, and specify quantity."
),
gr.Interface(
fn=lambda: (table_component, bar_graph_component),
inputs=[],
outputs=[
gr.HTML(label="Salesforce Data Table"),
gr.Image(type="pil", label="Stock Distribution Bar Graph")
],
title="Salesforce Data",
description="View structured Salesforce data as a table and bar graph."
)
], ["Processing", "Salesforce Data"])
if __name__ == "__main__":
app().launch(share=True)