Ajay98 commited on
Commit
fda9dfd
Β·
verified Β·
1 Parent(s): 7442a9e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -391
app.py CHANGED
@@ -1,426 +1,112 @@
1
  import os
2
  from paddleocr import PaddleOCR
3
- from PIL import Image
4
  import gradio as gr
5
- import requests
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
14
- ATTRIBUTE_MAPPING = {
15
- "Product name": "Productname__c",
16
- "Colour": "Colour__c",
17
- "Motortype": "Motortype__c",
18
- "Frequency": "Frequency__c",
19
- "Grossweight": "Grossweight__c",
20
- "Ratio": "Ratio__c",
21
- "MotorFrame": "Motorframe__c",
22
- "Model": "Model__c",
23
- "Speed": "Speed__c",
24
- "Quantity": "Quantity__c",
25
- "Voltage": "Voltage__c",
26
- "Material": "Material__c",
27
- "Type": "Type__c",
28
- "Horsepower": "Horsepower__c",
29
- "Consignee": "Consignee__c",
30
- "LOT": "LOT__c",
31
- "Stage": "Stage__c",
32
- "Outlet": "Outlet__c",
33
- "Serialnumber": "Serialnumber__c",
34
- "HeadSize": "Headsize__c",
35
- "Deliverysize": "Deliverysize__c",
36
- "Phase": "Phase__c",
37
- "Size": "Size__c",
38
- "MRP": "MRP__c",
39
- "Usebefore": "Usebefore__c",
40
- "Height": "Height__c",
41
- "MaximumDischarge Flow": "Maximumdischargeflow__c",
42
- "DischargeRange": "Dischargeflow__c",
43
- "Assembledby": "Manufacturer__c",
44
- "Manufacturedate": "Manufacturedate__c",
45
- "Companyname": "Companyname__c",
46
- "Customercarenumber": "Customercarenumber__c",
47
- "SellerAddress": "Selleraddress__c",
48
- "Selleremail": "Selleremail__c",
49
- "GSTIN": "GSTIN__c",
50
- "Totalamount": "Totalamount__c",
51
- "Paymentstatus": "Paymentstatus__c",
52
- "Paymentmethod": "Paymentstatus__c",
53
- "Invoicedate": "Manufacturedate__c",
54
- "Warranty": "Warranty__c",
55
- "Brand": "Brand__c",
56
- "Motorhorsepower": "Motorhorsepower__c",
57
- "Power": "Power__c",
58
- "Motorphase": "Motorphase__c",
59
- "Enginetype": "Enginetype__c",
60
- "Tankcapacity": "Tankcapacity__c",
61
- "Head": "Head__c",
62
- "Usage/Application": "Usage_Application__c",
63
- "Volts": "volts__c",
64
- "Hertz": "Hertz__c",
65
- "Frame": "frame__c",
66
- "Mounting": "Mounting__c",
67
- "Tollfreenumber": "Tollfreenumber__c",
68
- "Pipesize": "Pipesize__c",
69
- "Manufacturer": "Manufacturer__c",
70
- "Office": "Office__c",
71
- "SRnumber": "SRnumber__c",
72
- "TypeOfEndUse": "TypeOfEndUse__c",
73
- "Model Name": "Model_Name_Number__c",
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@"
109
- SALESFORCE_SECURITY_TOKEN = "GhcJJmjBEefdnukJoz4CAQlR"
110
 
111
- #🧠 Initialize PaddleOCR
112
- ocr = PaddleOCR(use_angle_cls=True, lang='en')
 
 
 
 
 
113
 
114
- # Function to extract text using PaddleOCR
115
  def extract_text(image):
116
  result = ocr.ocr(image)
117
- extracted_text = []
118
- for line in result[0]:
119
- extracted_text.append(line[1][0])
120
- return "\n".join(extracted_text)
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:
154
- sf = Salesforce(
155
- username=SALESFORCE_USERNAME,
156
- password=SALESFORCE_PASSWORD,
157
- security_token=SALESFORCE_SECURITY_TOKEN
158
- )
159
-
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":
168
- object_name = "VENKATA_RAMANA_MOTORS__c"
169
- field_name = "Quantity__c"
170
- elif entry_type == "Non-Sales":
171
- object_name = "UNBILLING_DATA__c"
172
- field_name = "TotalQuantity__c"
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:
186
  return "Invalid mode or entry type."
187
-
188
- # Get valid fields for the specified Salesforce object
189
- sf_object = sf.__getattr__(object_name)
190
- schema = sf_object.describe()
191
- valid_fields = {field["name"] for field in schema["fields"]}
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
- updated_quantity = quantity # Overwrite the quantity, don't add
209
- sf_object.update(record_id, {field_name: updated_quantity})
210
- return f"Updated record for product '{product_name}' in {object_name}. New {field_name}: {updated_quantity}."
211
- else:
212
- return f"No matching record found for product '{product_name}' in {object_name}."
213
- else:
214
- filtered_attributes = filter_valid_attributes(attributes, valid_fields)
215
- filtered_attributes[field_name] = quantity
216
- sf_object.create(filtered_attributes)
217
- return f"βœ… Data successfully exported to Salesforce object {object_name}."
218
-
219
- except Exception as e:
220
- return f"❌ Error interacting with Salesforce: {str(e)}"
221
-
222
- # Function to pull data from Salesforce MotorDataAPI
223
- def pull_data_from_motor_api():
224
- try:
225
- sf = Salesforce(
226
- username=SALESFORCE_USERNAME,
227
- password=SALESFORCE_PASSWORD,
228
- security_token=SALESFORCE_SECURITY_TOKEN
229
- )
230
- motor_data = sf.apexecute("MotorDataAPI/", method="GET")
231
- return motor_data # API returns the list of records
232
- except Exception as e:
233
- return f"Error pulling data from MotorDataAPI: {str(e)}"
234
-
235
- # Function to format Salesforce data into a DataFrame with readable headers
236
- def format_salesforce_data():
237
- try:
238
- data = pull_data_from_motor_api()
239
- if isinstance(data, list):
240
- df = pd.DataFrame(data)
241
- df = df.rename(columns={
242
- "Product_Name__c": "Product Name",
243
- "Modal_Name__c": "Model Name",
244
- "Current_Stocks__c": "Current Stocks"
245
- })
246
- # Remove unnecessary columns
247
- df = df[["Product Name", "Model Name", "Current Stocks"]]
248
- return df
249
  else:
250
- return None
 
251
  except Exception as e:
252
- return None
253
 
254
- # Function to generate a bar graph from Salesforce data
255
- def generate_bar_graph(df):
256
- try:
257
- fig, ax = plt.subplots(figsize=(12, 8))
258
- df.plot(kind='bar', x="Product Name", y="Current Stocks", ax=ax, legend=False)
259
- ax.set_title("Stock Distribution by Product Name")
260
- ax.set_xlabel("Product Name")
261
- ax.set_ylabel("Current Stocks")
262
- plt.xticks(rotation=45, ha="right", fontsize=10)
263
- plt.tight_layout()
264
- buffer = BytesIO()
265
- plt.savefig(buffer, format="png")
266
- buffer.seek(0)
267
- img = Image.open(buffer)
268
- return img
269
- except Exception as e:
270
- return None
271
-
272
- # Unified function to handle image processing and Salesforce interaction
273
  def process_image(image, mode, entry_type, quantity):
274
  extracted_text = extract_text(image)
275
- if not extracted_text:
276
- return "No text detected in the image.", None
277
-
278
- product_name = match_product_name(extracted_text)
279
- attributes = extract_attributes(extracted_text)
280
- if product_name:
281
- attributes["Product name"] = product_name
282
-
283
- # Interact with Salesforce
284
  message = interact_with_salesforce(mode, entry_type, quantity, extracted_text)
 
285
 
286
- numbered_output = "\n".join([f"{key}: {value}" for key, value in attributes.items()])
287
- return f"Extracted Text:\n{extracted_text}\n\nAttributes and Values:\n{numbered_output}", message
288
-
289
-
290
- def app():
291
- df = format_salesforce_data()
292
- table_component = None
293
- bar_graph_component = None
294
-
295
- if df is not None:
296
- table_component = df.to_html(index=False)
297
- bar_graph_image = generate_bar_graph(df)
298
- if bar_graph_image:
299
- bar_graph_component = bar_graph_image
300
-
301
- return gr.TabbedInterface([
302
- gr.Interface(
303
- fn=process_image,
304
- inputs=[
305
- gr.Image(type="numpy", label="πŸ“„α΄œα΄˜ΚŸα΄α΄€α΄… Ιͺᴍᴀɒᴇ"),
306
- gr.Dropdown(label="πŸ“ŒMode", choices=["ᴇɴᴛʀʏ", "ᴇxΙͺα΄›"], value="Entry"),
307
- gr.Radio(label="πŸ“¦Entry Type", choices=["Sales", "Non-Sales"], value="Sales"),
308
- gr.Number(label="πŸ”’Quantity", value=1, interactive=True),
309
- ],
310
- outputs=[
311
- gr.Text(label="Ιͺᴍᴀɒᴇ α΄…α΄€α΄›α΄€ α΄ Ιͺᴇᴑᴇʀ"),
312
- gr.Text(label="πŸ“οΌ²οΌ₯οΌ³οΌ΅οΌ¬οΌ΄")
313
- ],
314
- title="𝑽𝑬𝑡𝑲𝑨𝑻𝑨𝑹𝑨𝑴𝑨𝑡𝑨 𝑴𝑢𝑻𝑢𝑹𝑺",
315
- description="πŸ“¦πˆππ•π„ππ“πŽπ‘π˜ πŒπ€ππ€π†π„πŒπ„ππ“"
316
- ),
317
- gr.Interface(
318
- fn=lambda: (table_component, bar_graph_component),
319
- inputs=[],
320
- outputs=[
321
- gr.HTML(label="Salesforce Data Table"),
322
- gr.Image(type="pil", label="Stock Distribution Bar Graph")
323
- ],
324
- title="Salesforce Data",
325
- description="View structured Salesforce data as a table and bar graph."
326
- )
327
- ], ["Processing", "Salesforce Data"])
328
-
329
- def get_valid_fields(object_name):
330
  try:
331
- sf = Salesforce(
332
- username=SALESFORCE_USERNAME,
333
- password=SALESFORCE_PASSWORD,
334
- security_token=SALESFORCE_SECURITY_TOKEN
335
- )
336
- obj_desc = sf.__getattr__(object_name).describe()
337
- return [field["name"] for field in obj_desc["fields"]]
338
- except Exception as e:
339
- return []
340
-
341
- # Function to pull structured data from Salesforce and display as a table
342
- def pull_data_from_salesforce():
343
- try:
344
- sf = Salesforce(
345
- username=SALESFORCE_USERNAME,
346
- password=SALESFORCE_PASSWORD,
347
- security_token=SALESFORCE_SECURITY_TOKEN
348
- )
349
-
350
- query = "SELECT Product_Name__c, Modal_Name__c, Current_Stocks__c FROM Inventory_Management__c LIMIT 100"
351
- response = sf.query_all(query)
352
-
353
- records = response.get("records", [])
354
- if not records:
355
- return "No data found in Salesforce.", None, None, None
356
 
357
- df = pd.DataFrame(records)
358
- df = df.drop(columns=['attributes'], errors='ignore')
359
 
360
- # Rename columns for better readability
361
- df.rename(columns={
362
- "Product_Name__c": "Product Name",
363
- "Modal_Name__c": "Model Name",
364
- "Current_Stocks__c": "Current Stocks"
365
- }, inplace=True)
366
-
367
- excel_path = "salesforce_data.xlsx"
368
- df.to_excel(excel_path, index=False)
369
-
370
- # Generate interactive bar graph using Plotly with Tooltip, Hover Effect, and Zooming
371
- fig = go.Figure()
372
- fig.add_trace(go.Bar(
373
- x=df['Product Name'],
374
- y=df['Current Stocks'],
375
- marker=dict(color='blue'),
376
- hoverinfo='x+y',
377
- text=df['Current Stocks'],
378
- textposition='outside'
379
- ))
380
-
381
- fig.update_layout(
382
- title="Current Stocks of Products",
383
- xaxis=dict(title="Product Name", tickangle=-45),
384
- yaxis=dict(title="Stock Quantity"),
385
- hovermode='x',
386
- dragmode='zoom',
387
- showlegend=False
388
- )
389
-
390
- return "Data successfully retrieved.", df, excel_path, fig
391
  except Exception as e:
392
- return f"Error fetching data: {str(e)}", None, None, None
393
-
394
- # Function to process image for OCR extraction
395
- def process_image(image):
396
- extracted_text = extract_text(image)
397
- if not extracted_text:
398
- return "No text detected in the image."
399
- return extracted_text
400
 
401
  # Gradio Interface
402
  def app():
403
- return gr.TabbedInterface([
404
- gr.Interface(
405
- fn=process_image,
406
- inputs=[gr.Image(type="numpy", label="Upload Image")],
407
- outputs=gr.Text(label="Extracted Text"),
408
- title="Image Text Extraction",
409
- description="Upload an image and extract text using OCR."
410
- ),
411
- gr.Interface(
412
- fn=pull_data_from_salesforce,
413
- inputs=[],
414
- outputs=[
415
- gr.Text(label="Status"),
416
- gr.Dataframe(label="Salesforce Data Table"),
417
- gr.File(label="Download Salesforce Data"),
418
- gr.Plot(label="Stock Distribution Bar Graph")
419
- ],
420
- title="Salesforce Data Export",
421
- description="View, visualize (zoom-in/out, hover details), and download Salesforce data (Product Name, Model Name, Current Stocks)."
422
- )
423
- ], ["OCR Processing", "Salesforce Data Export"])
424
 
425
  if __name__ == "__main__":
426
- app().launch(share=True)
 
1
  import os
2
  from paddleocr import PaddleOCR
 
3
  import gradio as gr
 
 
4
  from simple_salesforce import Salesforce
5
  import pandas as pd
6
+ import plotly.graph_objects as go
7
+ import re
8
  from fuzzywuzzy import process
9
 
10
+ # Load Salesforce Credentials Securely
11
+ SALESFORCE_USERNAME = os.getenv("SALESFORCE_USERNAME")
12
+ SALESFORCE_PASSWORD = os.getenv("SALESFORCE_PASSWORD")
13
+ SALESFORCE_SECURITY_TOKEN = os.getenv("SALESFORCE_SECURITY_TOKEN")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ # Initialize PaddleOCR
16
+ ocr = PaddleOCR(use_angle_cls=True, lang='en')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
+ # Product names list for fuzzy matching
19
+ PRODUCT_NAMES = ["Honda Activa", "Yamaha R15", "Suzuki Access", "Hero Splendor"]
 
 
20
 
21
+ # Salesforce Object Mapping
22
+ OBJECT_MAPPING = {
23
+ "Entry_Sales": ("VENKATA_RAMANA_MOTORS__c", "Quantity__c"),
24
+ "Entry_NonSales": ("UNBILLING_DATA__c", "TotalQuantity__c"),
25
+ "Exit_Sales": ("Inventory_Management__c", "Quantity_Sold__c"),
26
+ "Exit_NonSales": ("Un_Billable__c", "Sold_Out__c"),
27
+ }
28
 
29
+ # Extract text from image
30
  def extract_text(image):
31
  result = ocr.ocr(image)
32
+ return "\n".join([line[1][0] for line in result[0]])
 
 
 
 
 
 
 
 
33
 
34
+ # Fuzzy match product name
35
+ def match_product_name(text):
36
+ match, score = process.extractOne(text, PRODUCT_NAMES)
37
+ return match if score >= 70 else "Unknown"
 
38
 
39
+ # Salesforce Interaction
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  def interact_with_salesforce(mode, entry_type, quantity, extracted_text):
41
  try:
42
+ sf = Salesforce(username=SALESFORCE_USERNAME, password=SALESFORCE_PASSWORD, security_token=SALESFORCE_SECURITY_TOKEN)
43
+ obj_key = f"{mode}_{entry_type}"
44
+ object_name, field_name = OBJECT_MAPPING.get(obj_key, (None, None))
45
+
46
+ if not object_name:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  return "Invalid mode or entry type."
48
+
 
 
 
 
 
 
49
  product_name = match_product_name(extracted_text)
50
+ query = f"SELECT Id, {field_name} FROM {object_name} WHERE Product_Name__c = '{product_name}' LIMIT 1"
51
+ response = sf.query(query)
52
+
53
+ if mode == "Exit" and response["records"]:
54
+ record = response["records"][0]
55
+ record_id = record["Id"]
56
+ new_quantity = max(0, int(record[field_name]) - quantity)
57
+ sf.__getattr__(object_name).update(record_id, {field_name: new_quantity})
58
+ return f"Updated {object_name}: New {field_name} = {new_quantity}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  else:
60
+ sf.__getattr__(object_name).create({"Product_Name__c": product_name, field_name: quantity})
61
+ return f"βœ… Data exported to {object_name}."
62
  except Exception as e:
63
+ return f"❌ Salesforce Error: {str(e)}"
64
 
65
+ # Process image and update Salesforce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  def process_image(image, mode, entry_type, quantity):
67
  extracted_text = extract_text(image)
 
 
 
 
 
 
 
 
 
68
  message = interact_with_salesforce(mode, entry_type, quantity, extracted_text)
69
+ return f"Extracted Text:\n{extracted_text}\n\n{message}"
70
 
71
+ # Fetch Salesforce Data & Generate Graph
72
+ def fetch_salesforce_data():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  try:
74
+ sf = Salesforce(username=SALESFORCE_USERNAME, password=SALESFORCE_PASSWORD, security_token=SALESFORCE_SECURITY_TOKEN)
75
+ query = "SELECT Product_Name__c, Current_Stocks__c FROM Inventory_Management__c"
76
+ records = sf.query_all(query)["records"]
77
+ df = pd.DataFrame(records).drop(columns=['attributes'], errors='ignore')
78
+ df.rename(columns={"Product_Name__c": "Product Name", "Current_Stocks__c": "Stock Quantity"}, inplace=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
+ fig = go.Figure(data=[go.Bar(x=df['Product Name'], y=df['Stock Quantity'], text=df['Stock Quantity'], textposition='outside')])
81
+ fig.update_layout(title="Stock Distribution", xaxis_title="Products", yaxis_title="Quantity", hovermode='x')
82
 
83
+ return df.to_html(index=False), fig.to_html()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  except Exception as e:
85
+ return f"Error fetching Salesforce data: {str(e)}", ""
 
 
 
 
 
 
 
86
 
87
  # Gradio Interface
88
  def app():
89
+ with gr.Blocks() as interface:
90
+ gr.Markdown("<h1>🏒 VENKATARAMANA MOTORS</h1>")
91
+
92
+ with gr.Tab("πŸ“₯ Stock Entry & Processing"):
93
+ with gr.Row():
94
+ image_input = gr.Image(type="numpy", label="πŸ“„ Upload Image")
95
+ mode_dropdown = gr.Dropdown(label="πŸ“Œ Mode", choices=["Entry", "Exit"], value="Entry")
96
+ entry_type_radio = gr.Radio(label="πŸ“¦ Entry Type", choices=["Sales", "Non-Sales"], value="Sales")
97
+ quantity_input = gr.Number(label="πŸ”’ Quantity", value=1)
98
+ submit_button = gr.Button("πŸ” Process Image")
99
+
100
+ result_output = gr.Text(label="πŸ“ Processed Result")
101
+ submit_button.click(fn=process_image, inputs=[image_input, mode_dropdown, entry_type_radio, quantity_input], outputs=result_output)
102
+
103
+ with gr.Tab("πŸ“Š Salesforce Data Overview"):
104
+ fetch_button = gr.Button("⚑ Fetch Salesforce Data")
105
+ salesforce_table = gr.HTML(label="πŸ“¦ Data Table")
106
+ salesforce_graph = gr.HTML(label="πŸ“‰ Stock Graph")
107
+ fetch_button.click(fn=fetch_salesforce_data, inputs=[], outputs=[salesforce_table, salesforce_graph])
108
+
109
+ return interface
110
 
111
  if __name__ == "__main__":
112
+ app().launch(share=True)