gopichandra commited on
Commit
e27d3ef
Β·
verified Β·
1 Parent(s): 951eafd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +440 -104
app.py CHANGED
@@ -2,6 +2,7 @@ import os
2
  from paddleocr import PaddleOCR
3
  from PIL import Image
4
  import gradio as gr
 
5
  import re
6
  from simple_salesforce import Salesforce
7
  import pandas as pd
@@ -9,77 +10,145 @@ import matplotlib.pyplot as plt
9
  from io import BytesIO
10
  from fuzzywuzzy import process
11
 
12
- # πŸ“Œ Salesforce Credentials
13
- SALESFORCE_USERNAME = "venkatramana@sandbox.com"
14
- SALESFORCE_PASSWORD = "Venkat12345@"
15
- SALESFORCE_SECURITY_TOKEN = "GhcJJmjBEefdnukJoz4CAQlR"
16
-
17
- # πŸ“Œ Attribute Mapping (Ensures proper export)
18
  ATTRIBUTE_MAPPING = {
19
- "Product name": "Product_Name__c",
20
- "Model": "Modal_Name__c",
 
 
 
 
 
 
 
21
  "Quantity": "Quantity__c",
22
  "Voltage": "Voltage__c",
 
 
23
  "Horsepower": "Horsepower__c",
24
- "Serial Number": "Serialnumber__c",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  "Warranty": "Warranty__c",
26
  "Brand": "Brand__c",
27
- "Motor Phase": "Motorphase__c",
28
- "Size": "Size__c",
29
- "Frame": "Frame__c",
30
- "Usage": "Usage_Application__c",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
32
 
33
- # πŸ“Œ Product Names for Fuzzy Matching
34
  PRODUCT_NAMES = [
35
- "Centrifugal mono block pump", "SINGLE PHASE MOTOR STARTER", "Electric Motor", "Self Priming Pump",
 
36
  "Control panel for single phase submersible pumps", "MOTOR", "Submersible pump set",
37
- "Havells open well Submersible pump", "Bertolini pump CK3 90pp", "Water Tank, Filters, Water Pump"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  ]
39
 
40
- # 🧠 Initialize PaddleOCR
 
 
 
 
 
41
  ocr = PaddleOCR(use_angle_cls=True, lang='en')
42
 
43
  # Function to extract text using PaddleOCR
44
  def extract_text(image):
45
  result = ocr.ocr(image)
46
- extracted_text = [line[1][0] for line in result[0]]
 
 
47
  return "\n".join(extracted_text)
48
 
49
- # Function to extract product name from attributes or use fuzzy matching
50
- def get_product_name(attributes, extracted_text):
51
- if "Product name" in attributes and attributes["Product name"]:
52
- return attributes["Product name"]
53
- return match_product_name(extracted_text)
54
-
55
  # Function to match product name using fuzzy matching
56
  def match_product_name(extracted_text):
57
- best_match, best_score = None, 0
 
 
58
  for line in extracted_text.split("\n"):
59
  match, score = process.extractOne(line, PRODUCT_NAMES)
60
  if score > best_score:
61
- best_match, best_score = match, score
62
- return best_match if best_score >= 70 else None # Threshold: 70
 
 
63
 
64
- # Function to extract attributes from text
65
  def extract_attributes(extracted_text):
66
  attributes = {}
67
 
68
- # Extract attributes based on predefined mapping
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
 
75
- # Extract Quantity from text (e.g., "Quantity: 10")
76
- quantity_match = re.search(r"\bQuantity[:\-]?\s*(\d+)", extracted_text, re.IGNORECASE)
77
- if quantity_match:
78
- attributes["Quantity"] = quantity_match.group(1)
79
-
80
  return attributes
81
 
82
- # Function to interact with Salesforce (Handles Entry & Exit Modes)
 
 
 
 
83
  def interact_with_salesforce(mode, entry_type, quantity, extracted_text):
84
  try:
85
  sf = Salesforce(
@@ -88,117 +157,384 @@ def interact_with_salesforce(mode, entry_type, quantity, extracted_text):
88
  security_token=SALESFORCE_SECURITY_TOKEN
89
  )
90
 
91
- # Map Entry & Exit to Salesforce Object
92
- object_name, field_name = None, None
93
- product_field_name = "Product_Name__c"
 
 
94
 
95
  if mode == "Entry":
96
- object_name = "VENKATA_RAMANA_MOTORS__c" if entry_type == "Sales" else "UNBILLING_DATA__c"
97
- field_name = "Quantity__c" if entry_type == "Sales" else "TotalQuantity__c"
 
 
 
 
98
  elif mode == "Exit":
99
- object_name = "Inventory_Management__c" if entry_type == "Sales" else "Un_Billable__c"
100
- field_name = "Quantity_Sold__c" if entry_type == "Sales" else "Sold_Out__c"
 
 
 
 
 
 
 
 
101
 
102
  if not object_name or not field_name:
103
- return "❌ Invalid mode or entry type."
104
-
105
- attributes = extract_attributes(extracted_text)
106
- product_name = get_product_name(attributes, extracted_text)
107
 
108
- if not product_name:
109
- return "❌ No matching product found."
110
-
111
- # Map extracted data to 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 = {ATTRIBUTE_MAPPING[key]: value for key, value in attributes.items() if ATTRIBUTE_MAPPING[key] in valid_fields}
117
- filtered_attributes[field_name] = quantity
118
- filtered_attributes[product_field_name] = product_name # Ensure product name is exported
 
 
 
 
 
119
 
120
  if mode == "Exit":
121
- query = f"SELECT Id FROM {object_name} WHERE {product_field_name} = '{product_name}' LIMIT 1"
122
  response = sf.query(query)
123
 
124
  if response["records"]:
125
  record_id = response["records"][0]["Id"]
126
- sf_object.update(record_id, filtered_attributes)
127
- return f"βœ… Updated record for '{product_name}' in {object_name}."
 
128
  else:
129
- return f"❌ No matching record found for '{product_name}' in {object_name}."
130
-
131
- sf_object.create(filtered_attributes)
132
- return f"βœ… Data successfully exported to Salesforce object {object_name}."
 
 
133
 
134
  except Exception as e:
135
  return f"❌ Error interacting with Salesforce: {str(e)}"
136
 
137
- # Function to process images, extract attributes, and export to Salesforce
138
- def process_image(image, mode, entry_type, quantity):
139
- extracted_text = extract_text(image)
140
- attributes = extract_attributes(extracted_text)
141
- attributes_list = "\n".join([f"{key}: {value}" for key, value in attributes.items()])
142
- result = interact_with_salesforce(mode, entry_type, quantity, extracted_text)
143
- return f"πŸ“œ Extracted Attributes:\n{attributes_list}", result
144
-
145
- # Function to Generate Inventory Graph
146
- def generate_inventory_graph():
147
  try:
148
  sf = Salesforce(
149
  username=SALESFORCE_USERNAME,
150
  password=SALESFORCE_PASSWORD,
151
  security_token=SALESFORCE_SECURITY_TOKEN
152
  )
153
-
154
- query = "SELECT Product_Name__c, Current_Stocks__c FROM Inventory_Management__c LIMIT 100"
155
- response = sf.query(query)
156
- records = response.get('records', [])
157
-
158
- if not records:
159
- return None, None
160
-
161
- df = pd.DataFrame(records)
162
- df.rename(columns={'Product_Name__c': 'Product Name', 'Current_Stocks__c': 'Current Stocks'}, inplace=True)
163
- df.drop(columns=['attributes'], inplace=True, errors='ignore')
164
-
165
- # Generate Graph
166
- fig, ax = plt.subplots(figsize=(12, 6))
167
  df.plot(kind='bar', x="Product Name", y="Current Stocks", ax=ax, legend=False)
168
- ax.set_title("Inventory Stock Distribution")
169
  ax.set_xlabel("Product Name")
170
- ax.set_ylabel("Stock Quantity")
171
  plt.xticks(rotation=45, ha="right", fontsize=10)
172
  plt.tight_layout()
173
  buffer = BytesIO()
174
  plt.savefig(buffer, format="png")
175
  buffer.seek(0)
176
- return df.to_html(index=False), Image.open(buffer)
177
-
178
  except Exception as e:
179
- return f"Error generating graph: {str(e)}", None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
- # Gradio UI
182
  def app():
183
- with gr.Blocks() as interface:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  gr.Markdown("<h1>🏒 VENKATARAMANA MOTORS</h1>")
185
 
186
- with gr.Row():
187
- with gr.Column():
188
- image_input = gr.Image(type="numpy", label="πŸ“„ Upload Image")
189
- mode_dropdown = gr.Dropdown(label="πŸ“Œ Mode", choices=["Entry", "Exit"], value="Entry")
190
- entry_type_radio = gr.Radio(label="πŸ“¦ Entry Type", choices=["Sales", "Non-Sales"], value="Sales")
191
- quantity_input = gr.Number(label="πŸ”’ Quantity", value=1, interactive=True)
 
 
 
 
 
 
 
 
192
 
193
- with gr.Column():
194
- image_view = gr.Text(label="πŸ“œ Extracted Attributes", interactive=False)
195
- result_output = gr.Text(label="πŸ“ Salesforce Export Result", interactive=False)
196
- submit_button = gr.Button("πŸ” Process & Export")
 
 
 
 
 
 
 
 
 
197
 
198
  submit_button.click(fn=process_image, inputs=[image_input, mode_dropdown, entry_type_radio, quantity_input], outputs=[image_view, result_output])
199
 
200
- return interface
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
  if __name__ == "__main__":
203
- interface = app()
204
- interface.launch(share=True)
 
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
 
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(
 
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
+ def pull_data_from_motor_api():
 
 
 
 
 
 
 
 
 
223
  try:
224
  sf = Salesforce(
225
  username=SALESFORCE_USERNAME,
226
  password=SALESFORCE_PASSWORD,
227
  security_token=SALESFORCE_SECURITY_TOKEN
228
  )
229
+ motor_data = sf.apexecute("MotorDataAPI/", method="GET")
230
+ return motor_data # API returns the list of records
231
+ except Exception as e:
232
+ return f"Error pulling data from MotorDataAPI: {str(e)}"
233
+ # Function to generate a bar graph from Salesforce data
234
+ def generate_bar_graph(df):
235
+ try:
236
+ fig, ax = plt.subplots(figsize=(12, 8))
 
 
 
 
 
 
237
  df.plot(kind='bar', x="Product Name", y="Current Stocks", ax=ax, legend=False)
238
+ ax.set_title("Stock Distribution by Product Name")
239
  ax.set_xlabel("Product Name")
240
+ ax.set_ylabel("Current Stocks")
241
  plt.xticks(rotation=45, ha="right", fontsize=10)
242
  plt.tight_layout()
243
  buffer = BytesIO()
244
  plt.savefig(buffer, format="png")
245
  buffer.seek(0)
246
+ img = Image.open(buffer)
247
+ return img
248
  except Exception as e:
249
+ return None
250
+
251
+ # Unified function to handle image processing and Salesforce interaction
252
+ def process_image(image, mode, entry_type, quantity):
253
+ extracted_text = extract_text(image)
254
+ if not extracted_text:
255
+ return "No text detected in the image.", None
256
+
257
+ product_name = match_product_name(extracted_text)
258
+ attributes = extract_attributes(extracted_text)
259
+ if product_name:
260
+ attributes["Product name"] = product_name
261
+
262
+ # Interact with Salesforce
263
+ message = interact_with_salesforce(mode, entry_type, quantity, extracted_text)
264
+
265
+ numbered_output = "\n".join([f"{key}: {value}" for key, value in attributes.items()])
266
+ return f"Extracted Text:\n{extracted_text}\n\nAttributes and Values:\n{numbered_output}", message
267
+
268
+
269
+ import gradio as gr
270
+ import numpy as np
271
+ from PIL import Image
272
+
273
+ # Function to fetch and return Salesforce data
274
+ def generate_salesforce_data():
275
+ df = format_salesforce_data()
276
+ if df is not None:
277
+ table_component = df.to_html(index=False)
278
+ bar_graph_image = generate_bar_graph(df)
279
+ return table_component, bar_graph_image
280
+ return "<p>No Data Available</p>", None
281
 
 
282
  def app():
283
+ with gr.Blocks(css="""
284
+ /* General Styling */
285
+ .gradio-container {
286
+ background: #0b0f29; /* Deep Dark Blue */
287
+ font-family: 'Poppins', sans-serif;
288
+ color: white;
289
+ padding: 10px;
290
+ }
291
+
292
+ h1, h2, h3 {
293
+ text-align: center;
294
+ color: white;
295
+ font-weight: bold;
296
+ text-shadow: 0px 0px 10px rgba(255,255,255,0.8);
297
+ }
298
+
299
+ /* Cards & Elements */
300
+ .card {
301
+ background: rgba(255, 255, 255, 0.1);
302
+ border-radius: 15px;
303
+ padding: 20px;
304
+ width: 100%;
305
+ max-width: 900px; /* Prevents extra-wide tables */
306
+ margin: auto; /* Centers the table */
307
+ box-shadow: 0px 0px 25px rgba(0, 255, 255, 0.6);
308
+ transition: 0.3s;
309
+ }
310
+
311
+ .card:hover {
312
+ box-shadow: 0px 0px 30px rgba(0, 255, 255, 0.9);
313
+ }
314
+
315
+ /* Buttons */
316
+ .gradio-button {
317
+ background: linear-gradient(to right, #ff416c, #ff4b2b);
318
+ color: white !important;
319
+ border-radius: 10px !important;
320
+ font-weight: bold;
321
+ padding: 12px;
322
+ transition: all 0.3s ease-in-out;
323
+ box-shadow: 0px 0px 20px rgba(255, 0, 255, 0.6);
324
+ }
325
+
326
+ .gradio-button:hover {
327
+ background: linear-gradient(to right, #ff4b2b, #ff416c);
328
+ box-shadow: 0px 0px 30px rgba(255, 0, 255, 0.9);
329
+ }
330
+
331
+ /* Tabs */
332
+ .gradio-tab {
333
+ font-size: 16px;
334
+ color: white;
335
+ font-weight: bold;
336
+ text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.6);
337
+ }
338
+
339
+ /* Scrollable Table */
340
+ .table-container {
341
+ width: 100%;
342
+ max-width: 900px;
343
+ max-height: 400px; /* Controls table height */
344
+ overflow-y: auto; /* Enables vertical scrolling */
345
+ overflow-x: auto; /* Enables horizontal scrolling if needed */
346
+ display: flex;
347
+ justify-content: center;
348
+ margin: auto;
349
+ }
350
+
351
+ table {
352
+ width: 100%;
353
+ border-collapse: collapse;
354
+ background: rgba(255, 255, 255, 0.1);
355
+ color: white;
356
+ min-width: 600px;
357
+ }
358
+
359
+ th, td {
360
+ padding: 12px;
361
+ text-align: left;
362
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
363
+ font-size: 14px;
364
+ }
365
+
366
+ th {
367
+ background: rgba(0, 255, 255, 0.2);
368
+ }
369
+
370
+ /* Mobile View */
371
+ @media (max-width: 768px) {
372
+ .gradio-container {
373
+ padding: 10px;
374
+ }
375
+
376
+ .card {
377
+ width: 100%;
378
+ max-width: 100%;
379
+ padding: 10px;
380
+ }
381
+
382
+ .table-container {
383
+ max-height: 350px; /* Adjusts for mobile */
384
+ overflow-y: scroll; /* Ensures vertical scrolling */
385
+ }
386
+
387
+ table {
388
+ width: 100%;
389
+ min-width: 100%;
390
+ }
391
+
392
+ th, td {
393
+ font-size: 12px;
394
+ padding: 8px;
395
+ }
396
+ }
397
+
398
+ """) as interface:
399
+
400
  gr.Markdown("<h1>🏒 VENKATARAMANA MOTORS</h1>")
401
 
402
+ with gr.Tab("πŸ“₯ Stock Entry & Processing"):
403
+ with gr.Row():
404
+ with gr.Column():
405
+ gr.Markdown("<h3>πŸ“Œ Upload & Process</h3>")
406
+ image_input = gr.Image(type="numpy", label="πŸ“„ Upload Image", elem_classes="card")
407
+ mode_dropdown = gr.Dropdown(label="πŸ“Œ Mode", choices=["Entry", "Exit"], value="Entry", elem_classes="card")
408
+ entry_type_radio = gr.Radio(label="πŸ“¦ Entry Type", choices=["Sales", "Non-Sales"], value="Sales", elem_classes="card")
409
+ quantity_input = gr.Number(label="πŸ”’ Quantity", value=1, interactive=True, elem_classes="card")
410
+
411
+ with gr.Column():
412
+ gr.Markdown("<h3>πŸ“Š Processed Data</h3>")
413
+ image_view = gr.Text(label="πŸ“œ Image Data Viewer", interactive=False, elem_classes="card")
414
+ result_output = gr.Text(label="πŸ“ Processed Result", interactive=False, elem_classes="card")
415
+ submit_button = gr.Button("πŸ” Process Image", elem_id="process-btn", elem_classes="gradio-button")
416
 
417
+ with gr.Tab("πŸ“Š Salesforce Data Overview"):
418
+ gr.Markdown("<h3>πŸ“‘ Stock Table</h3>")
419
+ with gr.Row(elem_classes="table-container"):
420
+ salesforce_table = gr.HTML(label="πŸ“¦ Salesforce Data Table", elem_classes="card")
421
+
422
+ gr.Markdown("<h3>πŸ“ˆ Inventory Analytics</h3>")
423
+ with gr.Row():
424
+ salesforce_graph = gr.Image(type="pil", label="πŸ“‰ Stock Distribution Bar Graph", elem_classes="card")
425
+
426
+ generate_button = gr.Button("⚑ Generate Data", elem_classes="gradio-button")
427
+
428
+ # Clicking "Generate Data" fetches table & graph
429
+ generate_button.click(fn=generate_salesforce_data, inputs=[], outputs=[salesforce_table, salesforce_graph])
430
 
431
  submit_button.click(fn=process_image, inputs=[image_input, mode_dropdown, entry_type_radio, quantity_input], outputs=[image_view, result_output])
432
 
433
+ return interface
434
+
435
+ interface = app()
436
+ interface.launch()
437
+ css = """
438
+ body {
439
+ background: linear-gradient(135deg, #282c34, #4b79a1);
440
+ font-family: 'Poppins', sans-serif;
441
+ }
442
+
443
+ .gradio-container {
444
+ border-radius: 20px;
445
+ padding: 30px;
446
+ background: rgba(255, 255, 255, 0.2);
447
+ backdrop-filter: blur(10px);
448
+ box-shadow: 0px 8px 30px rgba(0, 123, 255, 0.4);
449
+ border: 2px solid rgba(255, 255, 255, 0.4);
450
+ }
451
+
452
+ .gradio-title {
453
+ font-size: 48px;
454
+ font-weight: bold;
455
+ text-align: center;
456
+ background: linear-gradient(90deg, #ff7eb3, #ff758c);
457
+ -webkit-background-clip: text;
458
+ -webkit-text-fill-color: transparent;
459
+ text-shadow: 5px 5px 20px rgba(255, 105, 180, 0.6);
460
+ margin-bottom: 20px;
461
+ animation: glow 2s infinite alternate;
462
+ }
463
+
464
+ @keyframes glow {
465
+ from {
466
+ text-shadow: 5px 5px 30px rgba(255, 87, 134, 0.6);
467
+ }
468
+ to {
469
+ text-shadow: 6px 6px 40px rgba(255, 54, 90, 1);
470
+ }
471
+ }
472
+
473
+ .gradio-box {
474
+ border-radius: 15px;
475
+ padding: 25px;
476
+ background: linear-gradient(135deg, #6a11cb, #2575fc);
477
+ box-shadow: 0px 6px 25px rgba(30, 144, 255, 0.6);
478
+ border: 2px solid #6a5acd;
479
+ color: white;
480
+ font-size: 18px;
481
+ }
482
+
483
+ .gradio-button {
484
+ border-radius: 12px;
485
+ padding: 18px 36px;
486
+ font-size: 20px;
487
+ font-weight: bold;
488
+ color: #fff;
489
+ background: linear-gradient(135deg, #1e90ff, #00bfff);
490
+ box-shadow: 0px 6px 25px rgba(0, 191, 255, 0.6);
491
+ transition: all 0.3s ease-in-out;
492
+ }
493
+
494
+ .gradio-button:hover {
495
+ background: linear-gradient(135deg, #00bfff, #1e90ff);
496
+ box-shadow: 0px 10px 35px rgba(0, 191, 255, 0.9);
497
+ transform: scale(1.1);
498
+ }
499
+
500
+ .gradio-input {
501
+ border-radius: 10px;
502
+ padding: 16px;
503
+ font-size: 18px;
504
+ background: rgba(255, 255, 255, 0.3);
505
+ border: 2px solid rgba(0, 123, 255, 0.5);
506
+ color: #fff;
507
+ transition: 0.3s;
508
+ }
509
+
510
+ .gradio-input:focus {
511
+ border: 2px solid #1e90ff;
512
+ outline: none;
513
+ box-shadow: 0px 5px 20px rgba(30, 144, 255, 0.6);
514
+ }
515
+
516
+ .gradio-output {
517
+ background: linear-gradient(135deg, #f39c12, #e74c3c);
518
+ padding: 22px;
519
+ border-radius: 15px;
520
+ color: white;
521
+ font-size: 20px;
522
+ text-align: center;
523
+ border: 2px solid #f39c12;
524
+ }
525
+
526
+ .gradio-file {
527
+ background: linear-gradient(135deg, #8e44ad, #3498db);
528
+ color: white;
529
+ padding: 16px;
530
+ border-radius: 15px;
531
+ text-align: center;
532
+ font-size: 18px;
533
+ }
534
+ """
535
+
536
+
537
+
538
 
539
  if __name__ == "__main__":
540
+ app().launch(share=True)