gopichandra commited on
Commit
dddb168
ยท
verified ยท
1 Parent(s): 772d94e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +151 -73
app.py CHANGED
@@ -6,8 +6,8 @@ import requests
6
  import re
7
  from simple_salesforce import Salesforce
8
  import pandas as pd
9
- import plotly.graph_objects as go
10
- import kaleido # Ensure kaleido is imported for saving the plot
11
  from fuzzywuzzy import process
12
 
13
  # Attribute mappings: readable names to Salesforce API names
@@ -74,6 +74,35 @@ ATTRIBUTE_MAPPING = {
74
  "coolingmethod": "coolingmethod__c"
75
  }
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  # Salesforce credentials
78
  SALESFORCE_USERNAME = "venkatramana@sandbox.com"
79
  SALESFORCE_PASSWORD = "Venkat12345@"
@@ -92,32 +121,33 @@ def extract_text(image):
92
 
93
  # Function to match product name using fuzzy matching
94
  def match_product_name(extracted_text):
95
- PRODUCT_NAMES = [
96
- "Centrifugal mono block pump", "SINGLE PHASE MOTOR STARTER", "EasyPact EZC 100",
97
- "Openwell Submersible Pumpset", "Electric Motor", "Self Priming Pump",
98
- "Control panel for single phase submersible pumps", "MOTOR", "Submersible pump set",
99
- "Fusion submersible pump set", "DCT", "Shock proof water proof", "CG COMMERCIAL MOTORS", "Fusion",
100
- "control panel for single phase submersible pumps", "single phase digital starter dry run and timer panel", "5HP AV1 XL Kirloskar Pump",
101
- "Phase stainless steel submersible pump", "Submersible pump", "WB15X", "Vtype self priming pump", "SP SHINE DISC", "havells submersible pump",
102
- "Havells open well Submersible pump", "Bertolini pump CK3 90pp", "WPA 772 Water Pump Assy", "bertolini TTL triplex high pressure plunger pumps",
103
- "Generic plunger high pressure pump", "Apple Normal, Banana", "Cast Iron KSb centrifugal pump", "5.5kw Water Pump",
104
- "KSB reliable i line centrifuged pumps", "Apple Normal, Orange, Banana", "Positive API 6745 hydraulic diaphragm pump",
105
- "1/2 inch Fuel Hose Pipe", "Kirloskar Water Pump", "Rotodel motor pump", "PVC Electrical Insulation Materials", "Electric kirloskar domestic water pump",
106
- "Electrical Insulation Materials", "sellowell motor pump", "bhupathi submersible pump set", "Flowshine Submersible pump set",
107
- "Index submersible pump", "Wintoss Plastic Electric Switch Board", "Electric 18 watt ujagar cooler pump",
108
- "Generator Service", "LG WM FHT1207ZWL, LG REF GL-S292RSCY", "Water tank, Filters, Water Pump", "MS Control Submersible Panel",
109
- "Centrifugal Monoblock Pumps", "Electric Motor with Pump BodyBlue and White", "Various Repair and Maintenance Parts", "Earthmax Pump",
110
- "Water Tank, Filters, Water Pump", "Centrifugal Water Pump for Agriculture", "mono block pumps"
111
- ]
112
  best_match = None
113
  best_score = 0
 
114
  for line in extracted_text.split("\n"):
115
  match, score = process.extractOne(line, PRODUCT_NAMES)
116
  if score > best_score:
117
  best_match = match
118
  best_score = score
 
119
  return best_match if best_score >= 70 else None # Threshold of 70 for a match
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  # Function to interact with Salesforce based on mode and type
122
  def interact_with_salesforce(mode, entry_type, quantity, extracted_text):
123
  try:
@@ -130,8 +160,8 @@ def interact_with_salesforce(mode, entry_type, quantity, extracted_text):
130
  # Mapping mode and entry_type to Salesforce object and field
131
  object_name = None
132
  field_name = None
133
- product_field_name = "Product_Name__c"
134
- model_field_name = "Modal_Name__c"
135
 
136
  if mode == "Entry":
137
  if entry_type == "Sales":
@@ -143,9 +173,13 @@ def interact_with_salesforce(mode, entry_type, quantity, extracted_text):
143
  elif mode == "Exit":
144
  if entry_type == "Sales":
145
  object_name = "Inventory_Management__c"
 
 
146
  field_name = "Quantity_Sold__c"
147
  elif entry_type == "Non-Sales":
148
  object_name = "Un_Billable__c"
 
 
149
  field_name = "Sold_Out__c"
150
 
151
  if not object_name or not field_name:
@@ -158,72 +192,116 @@ def interact_with_salesforce(mode, entry_type, quantity, extracted_text):
158
 
159
  # Extract product name or model number
160
  product_name = match_product_name(extracted_text)
 
 
161
  if not product_name:
162
  return "Product name could not be matched from the extracted text."
163
 
164
- # Continue with further processing (creating or updating Salesforce data)
165
- return "Processed successfully."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
  except Exception as e:
168
- return f"โŒ Error interacting with Salesforce: {str(e)}"
169
 
170
- # Function to retrieve Salesforce data
171
- def pull_data_from_salesforce():
172
  try:
173
  sf = Salesforce(
174
  username=SALESFORCE_USERNAME,
175
  password=SALESFORCE_PASSWORD,
176
  security_token=SALESFORCE_SECURITY_TOKEN
177
  )
 
 
 
 
178
 
179
- query = "SELECT Product_Name__c, Model_Name__c, Current_Stocks__c FROM Inventory_Management__c LIMIT 100"
180
- response = sf.query_all(query)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
 
182
- records = response.get("records", [])
183
- if not records:
184
- return "No data found in Salesforce.", None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
 
186
- df = pd.DataFrame(records)
187
- df = df.drop(columns=['attributes'], errors='ignore')
188
- df.rename(columns={
189
- "Product_Name__c": "Product Name",
190
- "Model_Name__c": "Model Name",
191
- "Current_Stocks__c": "Current Stocks"
192
- }, inplace=True)
193
 
194
- return "Data successfully retrieved.", df
195
- except Exception as e:
196
- return f"Error fetching data: {str(e)}", None
 
197
 
198
- # Function to generate the graph based on Salesforce data
199
- def generate_graph(df):
200
- try:
201
- fig = go.Figure()
202
- fig.add_trace(go.Bar(
203
- x=df['Product Name'],
204
- y=df['Current Stocks'],
205
- marker=dict(color='blue'),
206
- hoverinfo='x+y',
207
- hovertemplate='<b>Product Name:</b> %{x}<br><b>Current Stocks:</b> %{y}<extra></extra>',
208
- ))
209
-
210
- fig.update_layout(
211
- title="Current Stocks of Products",
212
- xaxis=dict(title="Product Name", tickangle=-45),
213
- yaxis=dict(title="Current Stocks"),
214
- showlegend=False
215
- )
216
 
217
- return fig
218
- except Exception as e:
219
- return f"Error generating graph: {str(e)}"
 
 
 
 
 
220
 
221
- # Main Gradio interface function
 
 
 
222
  def app():
223
- data_status, data_table = pull_data_from_salesforce()
224
-
225
  with gr.Blocks() as demo:
226
- with gr.Tab("๐Ÿ“ฆ OCR Processing"):
 
 
227
  gr.Interface(
228
  fn=process_image,
229
  inputs=[
@@ -233,20 +311,20 @@ def app():
233
  gr.Number(label="๐Ÿ”ข Quantity", value=1, interactive=True),
234
  ],
235
  outputs=[
236
- gr.Text(label="๐Ÿ“ Extracted Text"),
237
  gr.Text(label="๐Ÿš€ Result")
238
  ],
239
  title="๐Ÿข VENKATARAMANA MOTORS",
240
  description="๐Ÿ“ฆ Inventory Management System"
241
  )
242
 
243
- with gr.Tab("๐Ÿ“Š Salesforce Data Export"):
244
  gr.Markdown("## ๐Ÿ“Š Salesforce Data Export")
245
- status_text = gr.Textbox(value=data_status, interactive=False)
246
- table_output = gr.DataFrame(value=data_table if data_table is not None else "No Data Available", interactive=False)
247
- graph_output = gr.Plot(value=generate_graph(data_table) if data_table is not None else None, interactive=False)
 
248
 
249
- demo.launch(share=True)
250
 
251
  if __name__ == "__main__":
252
- app()
 
6
  import re
7
  from simple_salesforce import Salesforce
8
  import pandas as pd
9
+ import matplotlib.pyplot as plt
10
+ from io import BytesIO
11
  from fuzzywuzzy import process
12
 
13
  # Attribute mappings: readable names to Salesforce API names
 
74
  "coolingmethod": "coolingmethod__c"
75
  }
76
 
77
+ # List of product names to match
78
+ PRODUCT_NAMES = [
79
+ "Centrifugal mono block pump", "SINGLE PHASE MOTOR STARTER", "EasyPact EZC 100",
80
+ "Openwell Submersible Pumpset", "Electric Motor", "Self Priming Pump",
81
+ "Control panel for single phase submersible pumps", "MOTOR", "Submersible pump set",
82
+ "Fusion submersible pump set", "DCT", "Shock proof water proof", "CG COMMERCIAL MOTORS", "Fusion",
83
+ "control panel for single phase submerisible pumps",
84
+ "single phase digital starter dry run and timer panel", "5HP AV1 XL Kirloskar Pump",
85
+ "Phase stainless steel submersible pump", "Submersible pump", "WB15X",
86
+ "Vtype self priming pump", "SP SHINE DISC", "havells submersible pump",
87
+ "Havells open well Submersible pump", "Bertolini pump CK3 90pp",
88
+ "WPA 772 Water Pump Assy", "bertolini TTL triplex high pressure plunger pumps",
89
+ "Generic plunger high pressure pump", "Apple Normal, Banana",
90
+ "Cast Iron KSb centrifugal pump", "5.5kw Water Pump",
91
+ "KSB reliable i line centrifuged pumps", "Apple Normal, Orange, Banana",
92
+ "Positive API 6745 hydraulic diaphragm pump", "1/2 inch Fuel Hose Pipe", "Kirloskar Water Pump",
93
+ "Rotodel motor pump", "PVC Electrical Insulation Materials",
94
+ "Electric kirloskar domestic water pump", "Electrical Insulation Materials",
95
+ "sellowell motor pump", "bhupathi submersible pump set",
96
+ "Flowshine Submersible pump set", "Index submersible pump",
97
+ "Wintoss Plastic Electric Switch Board", "Electric 18 watt ujagar cooler pump",
98
+ "Generator Service", "LG WM FHT1207ZWL, LG REF GL-S292RSCY",
99
+ "Water tank, Filters, Water Pump", "MS Control Submersible Panel",
100
+ "Centrifugal Monoblock Pumps", "Electric Motor with Pump BodyBlue and White",
101
+ "Various Repair and Maintenance Parts", "Earthmax Pump",
102
+ "Water Tank, Filters, Water Pump", "Centrifugal Water Pump for Agriculture",
103
+ "mono block pumps"
104
+ ]
105
+
106
  # Salesforce credentials
107
  SALESFORCE_USERNAME = "venkatramana@sandbox.com"
108
  SALESFORCE_PASSWORD = "Venkat12345@"
 
121
 
122
  # Function to match product name using fuzzy matching
123
  def match_product_name(extracted_text):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  best_match = None
125
  best_score = 0
126
+
127
  for line in extracted_text.split("\n"):
128
  match, score = process.extractOne(line, PRODUCT_NAMES)
129
  if score > best_score:
130
  best_match = match
131
  best_score = score
132
+
133
  return best_match if best_score >= 70 else None # Threshold of 70 for a match
134
 
135
+ # Function to extract attributes and their values
136
+ def extract_attributes(extracted_text):
137
+ attributes = {}
138
+
139
+ for readable_attr, sf_attr in ATTRIBUTE_MAPPING.items():
140
+ pattern = rf"{re.escape(readable_attr)}[:\-]?\s*(.+)"
141
+ match = re.search(pattern, extracted_text, re.IGNORECASE)
142
+ if match:
143
+ attributes[readable_attr] = match.group(1).strip()
144
+
145
+ return attributes
146
+
147
+ # Function to filter attributes for valid Salesforce fields
148
+ def filter_valid_attributes(attributes, valid_fields):
149
+ return {ATTRIBUTE_MAPPING[key]: value for key, value in attributes.items() if ATTRIBUTE_MAPPING[key] in valid_fields}
150
+
151
  # Function to interact with Salesforce based on mode and type
152
  def interact_with_salesforce(mode, entry_type, quantity, extracted_text):
153
  try:
 
160
  # Mapping mode and entry_type to Salesforce object and field
161
  object_name = None
162
  field_name = None
163
+ product_field_name = "Product_Name__c" # Correct field for product name in the object
164
+ model_field_name = "Modal_Name__c" # Correct field for model name in the object
165
 
166
  if mode == "Entry":
167
  if entry_type == "Sales":
 
173
  elif mode == "Exit":
174
  if entry_type == "Sales":
175
  object_name = "Inventory_Management__c"
176
+ product_field_name = "Product_Name__c"
177
+ model_field_name = "Modal_Name__c"
178
  field_name = "Quantity_Sold__c"
179
  elif entry_type == "Non-Sales":
180
  object_name = "Un_Billable__c"
181
+ product_field_name = "Product_Name__c"
182
+ model_field_name = "Model_Name__c"
183
  field_name = "Sold_Out__c"
184
 
185
  if not object_name or not field_name:
 
192
 
193
  # Extract product name or model number
194
  product_name = match_product_name(extracted_text)
195
+ attributes = extract_attributes(extracted_text)
196
+
197
  if not product_name:
198
  return "Product name could not be matched from the extracted text."
199
 
200
+ attributes["Product name"] = product_name
201
+
202
+ if mode == "Exit":
203
+ query = f"SELECT Id, {field_name} FROM {object_name} WHERE {product_field_name} = '{product_name}' OR {model_field_name} = '{attributes.get('Model Name', '')}' LIMIT 1"
204
+ response = sf.query(query)
205
+
206
+ if response["records"]:
207
+ record_id = response["records"][0]["Id"]
208
+ current_quantity = response["records"][0].get(field_name, 0) or 0
209
+ updated_quantity = max(0, current_quantity + quantity)
210
+ sf_object.update(record_id, {field_name: updated_quantity})
211
+ return f"Updated record for product '{product_name}' in {object_name}. New {field_name}: {updated_quantity}."
212
+ else:
213
+ return f"No matching record found for product '{product_name}' in {object_name}."
214
+ else:
215
+ filtered_attributes = filter_valid_attributes(attributes, valid_fields)
216
+ filtered_attributes[field_name] = quantity
217
+ sf_object.create(filtered_attributes)
218
+ return f"Data successfully exported to Salesforce object {object_name}."
219
 
220
  except Exception as e:
221
+ return f"Error interacting with Salesforce: {str(e)}"
222
 
223
+ # Function to pull data from Salesforce MotorDataAPI
224
+ def pull_data_from_motor_api():
225
  try:
226
  sf = Salesforce(
227
  username=SALESFORCE_USERNAME,
228
  password=SALESFORCE_PASSWORD,
229
  security_token=SALESFORCE_SECURITY_TOKEN
230
  )
231
+ motor_data = sf.apexecute("MotorDataAPI/", method="GET")
232
+ return motor_data # API returns the list of records
233
+ except Exception as e:
234
+ return f"Error pulling data from MotorDataAPI: {str(e)}"
235
 
236
+ # Function to format Salesforce data into a DataFrame with readable headers
237
+ def format_salesforce_data():
238
+ try:
239
+ data = pull_data_from_motor_api()
240
+ if isinstance(data, list):
241
+ df = pd.DataFrame(data)
242
+ df = df.rename(columns={
243
+ "Product_Name__c": "Product Name",
244
+ "Modal_Name__c": "Model Name",
245
+ "Current_Stocks__c": "Current Stocks"
246
+ })
247
+ # Remove unnecessary columns
248
+ df = df[["Product Name", "Model Name", "Current Stocks"]]
249
+ return df
250
+ else:
251
+ return None
252
+ except Exception as e:
253
+ return None
254
 
255
+ # Function to generate a bar graph from Salesforce data
256
+ def generate_bar_graph(df):
257
+ try:
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
+ return img
270
+ except Exception as e:
271
+ return None
272
 
273
+ # Unified function to handle image processing and Salesforce interaction
274
+ def process_image(image, mode, entry_type, quantity, state):
275
+ extracted_text = extract_text(image)
276
+ if not extracted_text:
277
+ return "No text detected in the image.", None
 
 
278
 
279
+ product_name = match_product_name(extracted_text)
280
+ attributes = extract_attributes(extracted_text)
281
+ if product_name:
282
+ attributes["Product name"] = product_name
283
 
284
+ # Interact with Salesforce
285
+ message = interact_with_salesforce(mode, entry_type, quantity, extracted_text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
 
287
+ # Fetch updated data and graph
288
+ df = format_salesforce_data()
289
+ if df is not None:
290
+ table_component = df.to_html(index=False)
291
+ bar_graph_image = generate_bar_graph(df)
292
+ if bar_graph_image:
293
+ state["graph"] = bar_graph_image
294
+ state["table"] = table_component
295
 
296
+ numbered_output = "\n".join([f"{key}: {value}" for key, value in attributes.items()])
297
+ return f"Extracted Text:\n{extracted_text}\n\nAttributes and Values:\n{numbered_output}", message
298
+
299
+ # Gradio Interface
300
  def app():
 
 
301
  with gr.Blocks() as demo:
302
+ state = gr.State({"table": "", "graph": None}) # State for storing table and graph
303
+
304
+ with gr.Tab("๐Ÿ“ฆ ๐‘ท๐‘น๐‘ถ๐‘ช๐‘ฌ๐‘บ๐‘บ ๐‘ฐ๐‘ด๐‘จ๐‘ฎ๐‘ฌ"):
305
  gr.Interface(
306
  fn=process_image,
307
  inputs=[
 
311
  gr.Number(label="๐Ÿ”ข Quantity", value=1, interactive=True),
312
  ],
313
  outputs=[
314
+ gr.Text(label="๐Ÿ“ Extracted Image Data"),
315
  gr.Text(label="๐Ÿš€ Result")
316
  ],
317
  title="๐Ÿข VENKATARAMANA MOTORS",
318
  description="๐Ÿ“ฆ Inventory Management System"
319
  )
320
 
321
+ with gr.Tab("๐Ÿ“Š SALESFORCE DATA EXPORT"):
322
  gr.Markdown("## ๐Ÿ“Š Salesforce Data Export")
323
+ table_output = gr.HTML(value=state["table"])
324
+ graph_output = gr.Image(value=state["graph"], type="pil")
325
+
326
+ return demo
327
 
 
328
 
329
  if __name__ == "__main__":
330
+ app().launch(share=True)