Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -78,7 +78,7 @@ ATTRIBUTE_MAPPING = {
|
|
| 78 |
|
| 79 |
# List of product names to match
|
| 80 |
PRODUCT_NAMES = [
|
| 81 |
-
|
| 82 |
]
|
| 83 |
|
| 84 |
# Salesforce credentials
|
|
@@ -98,7 +98,7 @@ def extract_text(image):
|
|
| 98 |
return "\n".join(extracted_text)
|
| 99 |
|
| 100 |
# Function to match product name using fuzzy matching
|
| 101 |
-
def match_product_name(extracted_text
|
| 102 |
best_match = None
|
| 103 |
best_score = 0
|
| 104 |
|
|
@@ -108,7 +108,7 @@ def match_product_name(extracted_text, threshold=70):
|
|
| 108 |
best_match = match
|
| 109 |
best_score = score
|
| 110 |
|
| 111 |
-
return best_match if best_score >=
|
| 112 |
|
| 113 |
# Function to extract attributes and their values
|
| 114 |
def extract_attributes(extracted_text):
|
|
@@ -167,25 +167,19 @@ def interact_with_salesforce(mode, entry_type, quantity, attributes):
|
|
| 167 |
schema = sf_object.describe()
|
| 168 |
valid_fields = {field["name"] for field in schema["fields"]}
|
| 169 |
|
| 170 |
-
#
|
| 171 |
-
|
| 172 |
-
model_name = attributes.get("Model Name", "").strip()
|
| 173 |
-
stage = attributes.get("Stage", "").strip()
|
| 174 |
-
hp = attributes.get("H.P.", "").strip()
|
| 175 |
-
|
| 176 |
-
if not product_name:
|
| 177 |
-
return "Product name could not be matched from the extracted text."
|
| 178 |
|
| 179 |
# Handling "Exit" Mode (Updating Records)
|
| 180 |
if mode == "Exit":
|
| 181 |
# Query should match exact product name, model name, stage, and hp if available
|
| 182 |
-
query_conditions = [f"{product_field_name} = '{
|
| 183 |
-
if
|
| 184 |
-
query_conditions.append(f"{model_field_name} = '{
|
| 185 |
-
if
|
| 186 |
-
query_conditions.append(f"{stage_field_name} = '{
|
| 187 |
-
if
|
| 188 |
-
query_conditions.append(f"{hp_field_name} = '{
|
| 189 |
|
| 190 |
query = f"SELECT Id, {', '.join(field_names)} FROM {object_name} WHERE {' AND '.join(query_conditions)} LIMIT 1"
|
| 191 |
response = sf.query(query)
|
|
@@ -194,23 +188,12 @@ def interact_with_salesforce(mode, entry_type, quantity, attributes):
|
|
| 194 |
record_id = response["records"][0]["Id"]
|
| 195 |
updated_fields = {field: quantity for field in field_names}
|
| 196 |
sf_object.update(record_id, updated_fields)
|
| 197 |
-
return f"β
Updated record for product '{
|
| 198 |
else:
|
| 199 |
-
|
| 200 |
-
query_conditions = [f"{product_field_name} = '{product_name}'"]
|
| 201 |
-
query = f"SELECT Id, {', '.join(field_names)} FROM {object_name} WHERE {' AND '.join(query_conditions)} LIMIT 1"
|
| 202 |
-
response = sf.query(query)
|
| 203 |
-
if response["records"]:
|
| 204 |
-
record_id = response["records"][0]["Id"]
|
| 205 |
-
updated_fields = {field: quantity for field in field_names}
|
| 206 |
-
sf_object.update(record_id, updated_fields)
|
| 207 |
-
return f"β
Updated record for product '{product_name}' in {object_name}. Updated fields: {updated_fields}."
|
| 208 |
-
else:
|
| 209 |
-
return f"β No matching record found for product '{product_name}' in {object_name}."
|
| 210 |
|
| 211 |
# Handling "Entry" Mode (Creating Records)
|
| 212 |
else:
|
| 213 |
-
filtered_attributes = filter_valid_attributes(attributes, valid_fields)
|
| 214 |
filtered_attributes[field_name] = quantity
|
| 215 |
sf_object.create(filtered_attributes)
|
| 216 |
return f"β
Data successfully exported to Salesforce object {object_name}."
|
|
@@ -218,129 +201,67 @@ def interact_with_salesforce(mode, entry_type, quantity, attributes):
|
|
| 218 |
except Exception as e:
|
| 219 |
return f"β Error interacting with Salesforce: {str(e)}"
|
| 220 |
|
| 221 |
-
# Function to
|
| 222 |
-
def
|
| 223 |
-
try:
|
| 224 |
-
sf = Salesforce(
|
| 225 |
-
username=SALESFORCE_USERNAME,
|
| 226 |
-
password=SALESFORCE_PASSWORD,
|
| 227 |
-
security_token=SALESFORCE_SECURITY_TOKEN
|
| 228 |
-
)
|
| 229 |
-
|
| 230 |
-
if selected_object == "Inventory_Management__c":
|
| 231 |
-
query = "SELECT Productname__c, Current_Stocks__c, soldstock__c FROM Inventory_Management__c LIMIT 100"
|
| 232 |
-
elif selected_object == "Un_Billable__c":
|
| 233 |
-
query = "SELECT Productname__c, Current_Stock__c, soldstock__c FROM Un_Billable__c LIMIT 100"
|
| 234 |
-
else:
|
| 235 |
-
return "Invalid object selected.", None, None, None
|
| 236 |
-
|
| 237 |
-
response = sf.query_all(query)
|
| 238 |
-
records = response.get("records", [])
|
| 239 |
-
|
| 240 |
-
if not records:
|
| 241 |
-
return "No data found in Salesforce.", None, None, None
|
| 242 |
-
|
| 243 |
-
df = pd.DataFrame(records)
|
| 244 |
-
df = df.drop(columns=['attributes'], errors='ignore')
|
| 245 |
-
|
| 246 |
-
# Rename columns for better readability
|
| 247 |
-
df.rename(columns={
|
| 248 |
-
"Productname__c": "Product Name",
|
| 249 |
-
"Current_Stocks__c": "Current Stocks",
|
| 250 |
-
"Current_Stock__c": "Current Stocks",
|
| 251 |
-
"soldstock__c": "Sold Stock"
|
| 252 |
-
}, inplace=True)
|
| 253 |
-
|
| 254 |
-
excel_path = "salesforce_data.xlsx"
|
| 255 |
-
df.to_excel(excel_path, index=False)
|
| 256 |
-
|
| 257 |
-
# Generate interactive vertical bar graph using Matplotlib
|
| 258 |
-
fig, ax = plt.subplots(figsize=(12, 8))
|
| 259 |
-
df.plot(kind='bar', x="Product Name", y="Current Stocks", ax=ax, legend=False)
|
| 260 |
-
ax.set_title("Stock Distribution by Product Name")
|
| 261 |
-
ax.set_xlabel("Product Name")
|
| 262 |
-
ax.set_ylabel("Current Stocks")
|
| 263 |
-
plt.xticks(rotation=45, ha="right", fontsize=10)
|
| 264 |
-
plt.tight_layout()
|
| 265 |
-
buffer = BytesIO()
|
| 266 |
-
plt.savefig(buffer, format="png")
|
| 267 |
-
buffer.seek(0)
|
| 268 |
-
img = Image.open(buffer)
|
| 269 |
-
|
| 270 |
-
return "Data successfully retrieved.", df, excel_path, img
|
| 271 |
-
except Exception as e:
|
| 272 |
-
return f"Error fetching data: {str(e)}", None, None, None
|
| 273 |
-
|
| 274 |
-
# Unified function to handle image processing and Salesforce interaction
|
| 275 |
-
def process_image(image, mode, entry_type, quantity, threshold=70):
|
| 276 |
extracted_text = extract_text(image)
|
| 277 |
if not extracted_text:
|
| 278 |
return "No text detected in the image.", None, None
|
| 279 |
|
| 280 |
-
product_name = match_product_name(extracted_text
|
| 281 |
attributes = extract_attributes(extracted_text)
|
| 282 |
if product_name:
|
| 283 |
attributes["Product name"] = product_name
|
| 284 |
-
else:
|
| 285 |
-
attributes["Product name"] = "Unknown"
|
| 286 |
|
| 287 |
-
#
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
combined_text += f"{key}: {value}\n"
|
| 291 |
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 298 |
|
| 299 |
# Gradio Interface
|
| 300 |
def app():
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
download_link_output = gr.File(label="Download Salesforce Data")
|
| 334 |
-
bar_graph_output = gr.Image(label="π Stock Distribution Bar Graph")
|
| 335 |
-
pull_data_button = gr.Button("Pull Data")
|
| 336 |
-
|
| 337 |
-
def pull_data(selected_object):
|
| 338 |
-
status, df, excel_path, img = pull_data_from_salesforce(selected_object)
|
| 339 |
-
return status, df, excel_path, img
|
| 340 |
-
|
| 341 |
-
pull_data_button.click(pull_data, inputs=[selected_object_input], outputs=[status_output, data_table_output, download_link_output, bar_graph_output])
|
| 342 |
-
|
| 343 |
-
demo.launch(share=True)
|
| 344 |
|
| 345 |
if __name__ == "__main__":
|
| 346 |
-
app()
|
|
|
|
| 78 |
|
| 79 |
# List of product names to match
|
| 80 |
PRODUCT_NAMES = [
|
| 81 |
+
"Fusion", "Agroking", "openwell", "CG commercial motors", "Jaguar", "Submersible pumps", "Gaurav"
|
| 82 |
]
|
| 83 |
|
| 84 |
# Salesforce credentials
|
|
|
|
| 98 |
return "\n".join(extracted_text)
|
| 99 |
|
| 100 |
# Function to match product name using fuzzy matching
|
| 101 |
+
def match_product_name(extracted_text):
|
| 102 |
best_match = None
|
| 103 |
best_score = 0
|
| 104 |
|
|
|
|
| 108 |
best_match = match
|
| 109 |
best_score = score
|
| 110 |
|
| 111 |
+
return best_match if best_score >= 70 else None # Threshold of 70 for a match
|
| 112 |
|
| 113 |
# Function to extract attributes and their values
|
| 114 |
def extract_attributes(extracted_text):
|
|
|
|
| 167 |
schema = sf_object.describe()
|
| 168 |
valid_fields = {field["name"] for field in schema["fields"]}
|
| 169 |
|
| 170 |
+
# Filter attributes for valid Salesforce fields
|
| 171 |
+
filtered_attributes = filter_valid_attributes(attributes, valid_fields)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
|
| 173 |
# Handling "Exit" Mode (Updating Records)
|
| 174 |
if mode == "Exit":
|
| 175 |
# Query should match exact product name, model name, stage, and hp if available
|
| 176 |
+
query_conditions = [f"{product_field_name} = '{attributes['Product name']}'"]
|
| 177 |
+
if "Model Name" in attributes:
|
| 178 |
+
query_conditions.append(f"{model_field_name} = '{attributes['Model Name']}'")
|
| 179 |
+
if "Stage" in attributes:
|
| 180 |
+
query_conditions.append(f"{stage_field_name} = '{attributes['Stage']}'")
|
| 181 |
+
if "H.P." in attributes:
|
| 182 |
+
query_conditions.append(f"{hp_field_name} = '{attributes['H.P.']}'")
|
| 183 |
|
| 184 |
query = f"SELECT Id, {', '.join(field_names)} FROM {object_name} WHERE {' AND '.join(query_conditions)} LIMIT 1"
|
| 185 |
response = sf.query(query)
|
|
|
|
| 188 |
record_id = response["records"][0]["Id"]
|
| 189 |
updated_fields = {field: quantity for field in field_names}
|
| 190 |
sf_object.update(record_id, updated_fields)
|
| 191 |
+
return f"β
Updated record for product '{attributes['Product name']}' in {object_name}. Updated fields: {updated_fields}."
|
| 192 |
else:
|
| 193 |
+
return f"β No matching record found for product '{attributes['Product name']}' in {object_name}."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
|
| 195 |
# Handling "Entry" Mode (Creating Records)
|
| 196 |
else:
|
|
|
|
| 197 |
filtered_attributes[field_name] = quantity
|
| 198 |
sf_object.create(filtered_attributes)
|
| 199 |
return f"β
Data successfully exported to Salesforce object {object_name}."
|
|
|
|
| 201 |
except Exception as e:
|
| 202 |
return f"β Error interacting with Salesforce: {str(e)}"
|
| 203 |
|
| 204 |
+
# Function to process image, extract attributes, and allow editing
|
| 205 |
+
def process_image(image, mode, entry_type, quantity):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
extracted_text = extract_text(image)
|
| 207 |
if not extracted_text:
|
| 208 |
return "No text detected in the image.", None, None
|
| 209 |
|
| 210 |
+
product_name = match_product_name(extracted_text)
|
| 211 |
attributes = extract_attributes(extracted_text)
|
| 212 |
if product_name:
|
| 213 |
attributes["Product name"] = product_name
|
|
|
|
|
|
|
| 214 |
|
| 215 |
+
# Convert attributes to DataFrame for editing
|
| 216 |
+
df = pd.DataFrame(list(attributes.items()), columns=["Attribute", "Value"])
|
| 217 |
+
return f"Extracted Text:\n{extracted_text}", df, None
|
|
|
|
| 218 |
|
| 219 |
+
# Function to handle edited attributes and export to Salesforce
|
| 220 |
+
def export_to_salesforce(mode, entry_type, quantity, edited_df):
|
| 221 |
+
try:
|
| 222 |
+
# Convert edited DataFrame back to dictionary
|
| 223 |
+
edited_attributes = dict(zip(edited_df["Attribute"], edited_df["Value"]))
|
| 224 |
+
|
| 225 |
+
# Export to Salesforce
|
| 226 |
+
message = interact_with_salesforce(mode, entry_type, quantity, edited_attributes)
|
| 227 |
+
return message
|
| 228 |
+
except Exception as e:
|
| 229 |
+
return f"β Error exporting to Salesforce: {str(e)}"
|
| 230 |
|
| 231 |
# Gradio Interface
|
| 232 |
def app():
|
| 233 |
+
return gr.TabbedInterface([
|
| 234 |
+
gr.Interface(
|
| 235 |
+
fn=process_image,
|
| 236 |
+
inputs=[
|
| 237 |
+
gr.Image(type="numpy", label="π Upload Image"),
|
| 238 |
+
gr.Dropdown(label="π Mode", choices=["Entry", "Exit"], value="Entry"),
|
| 239 |
+
gr.Radio(label="π¦ Entry Type", choices=["Sales", "Non-Sales"], value="Sales"),
|
| 240 |
+
gr.Number(label="π’ Quantity", value=1, interactive=True),
|
| 241 |
+
],
|
| 242 |
+
outputs=[
|
| 243 |
+
gr.Text(label="π Extracted Image Data"),
|
| 244 |
+
gr.Dataframe(label="βοΈ Edit Attributes (Key-Value Pairs)"),
|
| 245 |
+
gr.Text(label="π Result")
|
| 246 |
+
],
|
| 247 |
+
title="π’ π½π¬π΅π²π¨π»π¨πΉπ¨π΄π¨π΅π¨ π΄πΆπ»πΆπΉπΊ",
|
| 248 |
+
description="π¦ πππππππππ ππππππππππ"
|
| 249 |
+
),
|
| 250 |
+
gr.Interface(
|
| 251 |
+
fn=export_to_salesforce,
|
| 252 |
+
inputs=[
|
| 253 |
+
gr.Dropdown(label="π Mode", choices=["Entry", "Exit"], value="Entry"),
|
| 254 |
+
gr.Radio(label="π¦ Entry Type", choices=["Sales", "Non-Sales"], value="Sales"),
|
| 255 |
+
gr.Number(label="π’ Quantity", value=1, interactive=True),
|
| 256 |
+
gr.Dataframe(label="βοΈ Edited Attributes (Key-Value Pairs)")
|
| 257 |
+
],
|
| 258 |
+
outputs=[
|
| 259 |
+
gr.Text(label="π Result")
|
| 260 |
+
],
|
| 261 |
+
title="π€ Export to Salesforce",
|
| 262 |
+
description="Edit attributes and export to Salesforce."
|
| 263 |
+
)
|
| 264 |
+
], ["π₯ OCR Processing", "π€ Export to Salesforce"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 265 |
|
| 266 |
if __name__ == "__main__":
|
| 267 |
+
app().launch(share=True)
|