gopichandra commited on
Commit
850c91c
Β·
verified Β·
1 Parent(s): 0b7dd6f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +470 -107
app.py CHANGED
@@ -9,14 +9,8 @@ import pandas as pd
9
  import matplotlib.pyplot as plt
10
  from io import BytesIO
11
  from fuzzywuzzy import process
12
- import plotly.graph_objects as go # For interactive graphs
13
 
14
- # πŸ“Œ Salesforce Credentials (HARDCODED)
15
- SALESFORCE_USERNAME = "venkatramana@sandbox.com"
16
- SALESFORCE_PASSWORD = "Venkat12345@"
17
- SALESFORCE_SECURITY_TOKEN = "GhcJJmjBEefdnukJoz4CAQlR"
18
-
19
- # πŸ“Œ Attribute mappings: readable names to Salesforce API names
20
  ATTRIBUTE_MAPPING = {
21
  "Product name": "Productname__c",
22
  "Colour": "Colour__c",
@@ -24,175 +18,544 @@ ATTRIBUTE_MAPPING = {
24
  "Frequency": "Frequency__c",
25
  "Grossweight": "Grossweight__c",
26
  "Ratio": "Ratio__c",
 
 
 
27
  "Quantity": "Quantity__c",
28
  "Voltage": "Voltage__c",
 
29
  "Type": "Type__c",
30
  "Horsepower": "Horsepower__c",
 
 
 
 
31
  "Serialnumber": "Serialnumber__c",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  }
33
 
34
- # πŸ“Œ List of product names for matching
35
  PRODUCT_NAMES = [
36
- "Centrifugal mono block pump", "SINGLE PHASE MOTOR STARTER", "Electric Motor",
37
- "Submersible pump set", "Self Priming Pump", "HAVELL'S MOTOR", "Kirloskar 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 = "\n".join([line[1][0] for line in result[0]])
47
- return extracted_text
 
 
48
 
49
- # πŸ“Œ Function to match product name using fuzzy matching
50
  def match_product_name(extracted_text):
51
- match, score = process.extractOne(extracted_text, PRODUCT_NAMES) if extracted_text else (None, 0)
52
- return match if score >= 70 else None # Threshold of 70 for matching
 
 
 
 
 
 
53
 
54
- # πŸ“Œ Function to extract attributes and values from text
 
 
55
  def extract_attributes(extracted_text):
56
  attributes = {}
 
57
  for readable_attr, sf_attr in ATTRIBUTE_MAPPING.items():
58
  pattern = rf"{re.escape(readable_attr)}[:\-]?\s*(.+)"
59
  match = re.search(pattern, extracted_text, re.IGNORECASE)
60
  if match:
61
  attributes[readable_attr] = match.group(1).strip()
 
62
  return attributes
63
 
64
- # πŸ“Œ Function to connect to Salesforce
65
- def connect_to_salesforce():
 
 
 
 
66
  try:
67
  sf = Salesforce(
68
  username=SALESFORCE_USERNAME,
69
  password=SALESFORCE_PASSWORD,
70
  security_token=SALESFORCE_SECURITY_TOKEN
71
  )
72
- return sf
73
- except Exception as e:
74
- return f"❌ Salesforce API error: {str(e)}"
75
 
76
- # πŸ“Œ Function to interact with Salesforce
77
- def interact_with_salesforce(mode, entry_type, quantity, extracted_text):
78
- try:
79
- sf = connect_to_salesforce()
80
- if isinstance(sf, str):
81
- return sf # Return error message
82
 
83
- # πŸ“Œ Define the correct Salesforce object and field names
84
  if mode == "Entry":
85
- object_name = "Stock_Entry__c"
86
- field_name = "Quantity__c"
 
 
 
 
87
  elif mode == "Exit":
88
- object_name = "Stock_Exit__c"
89
- field_name = "Quantity_Sold__c"
90
- else:
91
- return "❌ Invalid mode selected."
92
-
93
- # πŸ“Œ Match product name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  product_name = match_product_name(extracted_text)
95
  attributes = extract_attributes(extracted_text)
96
 
97
- if product_name:
98
- attributes["Product name"] = product_name
99
 
100
- # πŸ“Œ Fetch the current stock for updates
101
- query = f"SELECT Id, {field_name} FROM {object_name} WHERE Product_Name__c = '{product_name}' LIMIT 1"
102
- response = sf.query(query)
103
 
104
- if response["records"]:
105
- record_id = response["records"][0]["Id"]
106
- sf.__getattr__(object_name).update(record_id, {field_name: quantity})
107
- return f"βœ… Updated stock record for '{product_name}' in {object_name}."
 
 
 
 
 
 
 
108
  else:
109
- return f"⚠️ No existing record found for '{product_name}' in {object_name}."
 
 
 
110
 
111
  except Exception as e:
112
- return f"❌ Salesforce API error: {str(e)}"
113
 
114
- # πŸ“Œ Function to pull data from Salesforce
115
- def pull_data_from_salesforce():
116
  try:
117
- sf = connect_to_salesforce()
118
- if isinstance(sf, str):
119
- return sf, None, None # Return error message
120
-
121
- query = "SELECT Product_Name__c, Current_Stocks__c FROM Inventory_Management__c LIMIT 100"
122
- response = sf.query_all(query)
123
- records = response.get("records", [])
124
-
125
- if not records:
126
- return "⚠️ No data found in Salesforce.", None, None
127
-
128
- df = pd.DataFrame(records)
129
- df = df.drop(columns=['attributes'], errors='ignore')
130
-
131
- # πŸ“Œ Rename columns for better readability
132
- df.rename(columns={"Product_Name__c": "Product Name", "Current_Stocks__c": "Current Stocks"}, inplace=True)
133
-
134
- # πŸ“Œ Generate a bar chart using Plotly
135
- fig = go.Figure()
136
- fig.add_trace(go.Bar(
137
- x=df['Product Name'],
138
- y=df['Current Stocks'],
139
- marker=dict(color='blue'),
140
- text=df['Current Stocks'],
141
- textposition='outside'
142
- ))
143
-
144
- fig.update_layout(
145
- title="Current Stocks of Products",
146
- xaxis=dict(title="Product Name", tickangle=-45),
147
- yaxis=dict(title="Stock Quantity"),
148
- hovermode='x'
149
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
- return "βœ… Data retrieved successfully.", df, fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  except Exception as e:
153
- return f"❌ Error fetching data: {str(e)}", None, None
154
 
155
- # πŸ“Œ Function to process images and send data to Salesforce
156
  def process_image(image, mode, entry_type, quantity):
157
  extracted_text = extract_text(image)
158
  if not extracted_text:
159
- return "⚠️ No text detected in the image.", None
160
 
 
161
  attributes = extract_attributes(extracted_text)
 
 
 
 
162
  message = interact_with_salesforce(mode, entry_type, quantity, extracted_text)
163
 
164
- return f"Extracted Text:\n{extracted_text}\n\nAttributes:\n{attributes}", message
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
- # πŸ“Œ Define the Gradio UI
167
  def app():
168
- with gr.Blocks() as interface:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  gr.Markdown("<h1>🏒 VENKATARAMANA MOTORS</h1>")
170
 
171
  with gr.Tab("πŸ“₯ Stock Entry & Processing"):
172
  with gr.Row():
173
  with gr.Column():
174
- image_input = gr.Image(type="numpy", label="πŸ“„ Upload Image")
175
- mode_dropdown = gr.Dropdown(label="πŸ“Œ Mode", choices=["Entry", "Exit"], value="Entry")
176
- entry_type_radio = gr.Radio(label="πŸ“¦ Entry Type", choices=["Sales", "Non-Sales"], value="Sales")
177
- quantity_input = gr.Number(label="πŸ”’ Quantity", value=1, interactive=True)
 
178
 
179
  with gr.Column():
180
- image_view = gr.Text(label="πŸ“œ Image Data Viewer", interactive=False)
181
- result_output = gr.Text(label="πŸ“ Processed Result", interactive=False)
182
- submit_button = gr.Button("πŸ” Process Image")
183
-
184
- submit_button.click(fn=process_image, inputs=[image_input, mode_dropdown, entry_type_radio, quantity_input],
185
- outputs=[image_view, result_output])
186
 
187
  with gr.Tab("πŸ“Š Salesforce Data Overview"):
188
- salesforce_table = gr.Dataframe()
189
- salesforce_graph = gr.Plot()
190
- generate_button = gr.Button("⚑ Generate Data")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
- generate_button.click(fn=pull_data_from_salesforce, inputs=[], outputs=[salesforce_table, salesforce_graph])
193
 
194
- return interface
195
 
196
- # πŸš€ Launch the app
197
  if __name__ == "__main__":
198
- app().launch(share=True)
 
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",
 
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
+ import gradio as gr
291
+ import numpy as np
292
+ from PIL import Image
293
+
294
+ # Function to fetch and return Salesforce data
295
+ def generate_salesforce_data():
296
+ df = format_salesforce_data()
297
+ if df is not None:
298
+ table_component = df.to_html(index=False)
299
+ bar_graph_image = generate_bar_graph(df)
300
+ return table_component, bar_graph_image
301
+ return "<p>No Data Available</p>", None
302
 
 
303
  def app():
304
+ with gr.Blocks(css="""
305
+ /* General Styling */
306
+ .gradio-container {
307
+ background: #0b0f29; /* Deep Dark Blue */
308
+ font-family: 'Poppins', sans-serif;
309
+ color: white;
310
+ padding: 10px;
311
+ }
312
+
313
+ h1, h2, h3 {
314
+ text-align: center;
315
+ color: white;
316
+ font-weight: bold;
317
+ text-shadow: 0px 0px 10px rgba(255,255,255,0.8);
318
+ }
319
+
320
+ /* Cards & Elements */
321
+ .card {
322
+ background: rgba(255, 255, 255, 0.1);
323
+ border-radius: 15px;
324
+ padding: 20px;
325
+ width: 100%;
326
+ max-width: 900px; /* Prevents extra-wide tables */
327
+ margin: auto; /* Centers the table */
328
+ box-shadow: 0px 0px 25px rgba(0, 255, 255, 0.6);
329
+ transition: 0.3s;
330
+ }
331
+
332
+ .card:hover {
333
+ box-shadow: 0px 0px 30px rgba(0, 255, 255, 0.9);
334
+ }
335
+
336
+ /* Buttons */
337
+ .gradio-button {
338
+ background: linear-gradient(to right, #ff416c, #ff4b2b);
339
+ color: white !important;
340
+ border-radius: 10px !important;
341
+ font-weight: bold;
342
+ padding: 12px;
343
+ transition: all 0.3s ease-in-out;
344
+ box-shadow: 0px 0px 20px rgba(255, 0, 255, 0.6);
345
+ }
346
+
347
+ .gradio-button:hover {
348
+ background: linear-gradient(to right, #ff4b2b, #ff416c);
349
+ box-shadow: 0px 0px 30px rgba(255, 0, 255, 0.9);
350
+ }
351
+
352
+ /* Tabs */
353
+ .gradio-tab {
354
+ font-size: 16px;
355
+ color: white;
356
+ font-weight: bold;
357
+ text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.6);
358
+ }
359
+
360
+ /* Scrollable Table */
361
+ .table-container {
362
+ width: 100%;
363
+ max-width: 900px;
364
+ max-height: 400px; /* Controls table height */
365
+ overflow-y: auto; /* Enables vertical scrolling */
366
+ overflow-x: auto; /* Enables horizontal scrolling if needed */
367
+ display: flex;
368
+ justify-content: center;
369
+ margin: auto;
370
+ }
371
+
372
+ table {
373
+ width: 100%;
374
+ border-collapse: collapse;
375
+ background: rgba(255, 255, 255, 0.1);
376
+ color: white;
377
+ min-width: 600px;
378
+ }
379
+
380
+ th, td {
381
+ padding: 12px;
382
+ text-align: left;
383
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
384
+ font-size: 14px;
385
+ }
386
+
387
+ th {
388
+ background: rgba(0, 255, 255, 0.2);
389
+ }
390
+
391
+ /* Mobile View */
392
+ @media (max-width: 768px) {
393
+ .gradio-container {
394
+ padding: 10px;
395
+ }
396
+
397
+ .card {
398
+ width: 100%;
399
+ max-width: 100%;
400
+ padding: 10px;
401
+ }
402
+
403
+ .table-container {
404
+ max-height: 350px; /* Adjusts for mobile */
405
+ overflow-y: scroll; /* Ensures vertical scrolling */
406
+ }
407
+
408
+ table {
409
+ width: 100%;
410
+ min-width: 100%;
411
+ }
412
+
413
+ th, td {
414
+ font-size: 12px;
415
+ padding: 8px;
416
+ }
417
+ }
418
+
419
+ """) as interface:
420
+
421
  gr.Markdown("<h1>🏒 VENKATARAMANA MOTORS</h1>")
422
 
423
  with gr.Tab("πŸ“₯ Stock Entry & Processing"):
424
  with gr.Row():
425
  with gr.Column():
426
+ gr.Markdown("<h3>πŸ“Œ Upload & Process</h3>")
427
+ image_input = gr.Image(type="numpy", label="πŸ“„ Upload Image", elem_classes="card")
428
+ mode_dropdown = gr.Dropdown(label="πŸ“Œ Mode", choices=["Entry", "Exit"], value="Entry", elem_classes="card")
429
+ entry_type_radio = gr.Radio(label="πŸ“¦ Entry Type", choices=["Sales", "Non-Sales"], value="Sales", elem_classes="card")
430
+ quantity_input = gr.Number(label="πŸ”’ Quantity", value=1, interactive=True, elem_classes="card")
431
 
432
  with gr.Column():
433
+ gr.Markdown("<h3>πŸ“Š Processed Data</h3>")
434
+ image_view = gr.Text(label="πŸ“œ Image Data Viewer", interactive=False, elem_classes="card")
435
+ result_output = gr.Text(label="πŸ“ Processed Result", interactive=False, elem_classes="card")
436
+ submit_button = gr.Button("πŸ” Process Image", elem_id="process-btn", elem_classes="gradio-button")
 
 
437
 
438
  with gr.Tab("πŸ“Š Salesforce Data Overview"):
439
+ gr.Markdown("<h3>πŸ“‘ Stock Table</h3>")
440
+ with gr.Row(elem_classes="table-container"):
441
+ salesforce_table = gr.HTML(label="πŸ“¦ Salesforce Data Table", elem_classes="card")
442
+
443
+ gr.Markdown("<h3>πŸ“ˆ Inventory Analytics</h3>")
444
+ with gr.Row():
445
+ salesforce_graph = gr.Image(type="pil", label="πŸ“‰ Stock Distribution Bar Graph", elem_classes="card")
446
+
447
+ generate_button = gr.Button("⚑ Generate Data", elem_classes="gradio-button")
448
+
449
+ # Clicking "Generate Data" fetches table & graph
450
+ generate_button.click(fn=generate_salesforce_data, inputs=[], outputs=[salesforce_table, salesforce_graph])
451
+
452
+ submit_button.click(fn=process_image, inputs=[image_input, mode_dropdown, entry_type_radio, quantity_input], outputs=[image_view, result_output])
453
+
454
+ return interface
455
+
456
+ interface = app()
457
+ interface.launch()
458
+ css = """
459
+ body {
460
+ background: linear-gradient(135deg, #282c34, #4b79a1);
461
+ font-family: 'Poppins', sans-serif;
462
+ }
463
+
464
+ .gradio-container {
465
+ border-radius: 20px;
466
+ padding: 30px;
467
+ background: rgba(255, 255, 255, 0.2);
468
+ backdrop-filter: blur(10px);
469
+ box-shadow: 0px 8px 30px rgba(0, 123, 255, 0.4);
470
+ border: 2px solid rgba(255, 255, 255, 0.4);
471
+ }
472
+
473
+ .gradio-title {
474
+ font-size: 48px;
475
+ font-weight: bold;
476
+ text-align: center;
477
+ background: linear-gradient(90deg, #ff7eb3, #ff758c);
478
+ -webkit-background-clip: text;
479
+ -webkit-text-fill-color: transparent;
480
+ text-shadow: 5px 5px 20px rgba(255, 105, 180, 0.6);
481
+ margin-bottom: 20px;
482
+ animation: glow 2s infinite alternate;
483
+ }
484
+
485
+ @keyframes glow {
486
+ from {
487
+ text-shadow: 5px 5px 30px rgba(255, 87, 134, 0.6);
488
+ }
489
+ to {
490
+ text-shadow: 6px 6px 40px rgba(255, 54, 90, 1);
491
+ }
492
+ }
493
+
494
+ .gradio-box {
495
+ border-radius: 15px;
496
+ padding: 25px;
497
+ background: linear-gradient(135deg, #6a11cb, #2575fc);
498
+ box-shadow: 0px 6px 25px rgba(30, 144, 255, 0.6);
499
+ border: 2px solid #6a5acd;
500
+ color: white;
501
+ font-size: 18px;
502
+ }
503
+
504
+ .gradio-button {
505
+ border-radius: 12px;
506
+ padding: 18px 36px;
507
+ font-size: 20px;
508
+ font-weight: bold;
509
+ color: #fff;
510
+ background: linear-gradient(135deg, #1e90ff, #00bfff);
511
+ box-shadow: 0px 6px 25px rgba(0, 191, 255, 0.6);
512
+ transition: all 0.3s ease-in-out;
513
+ }
514
+
515
+ .gradio-button:hover {
516
+ background: linear-gradient(135deg, #00bfff, #1e90ff);
517
+ box-shadow: 0px 10px 35px rgba(0, 191, 255, 0.9);
518
+ transform: scale(1.1);
519
+ }
520
+
521
+ .gradio-input {
522
+ border-radius: 10px;
523
+ padding: 16px;
524
+ font-size: 18px;
525
+ background: rgba(255, 255, 255, 0.3);
526
+ border: 2px solid rgba(0, 123, 255, 0.5);
527
+ color: #fff;
528
+ transition: 0.3s;
529
+ }
530
+
531
+ .gradio-input:focus {
532
+ border: 2px solid #1e90ff;
533
+ outline: none;
534
+ box-shadow: 0px 5px 20px rgba(30, 144, 255, 0.6);
535
+ }
536
+
537
+ .gradio-output {
538
+ background: linear-gradient(135deg, #f39c12, #e74c3c);
539
+ padding: 22px;
540
+ border-radius: 15px;
541
+ color: white;
542
+ font-size: 20px;
543
+ text-align: center;
544
+ border: 2px solid #f39c12;
545
+ }
546
+
547
+ .gradio-file {
548
+ background: linear-gradient(135deg, #8e44ad, #3498db);
549
+ color: white;
550
+ padding: 16px;
551
+ border-radius: 15px;
552
+ text-align: center;
553
+ font-size: 18px;
554
+ }
555
+ """
556
+
557
 
 
558
 
 
559
 
 
560
  if __name__ == "__main__":
561
+ app().launch(share=True)