Ajay98 commited on
Commit
6b215e5
Β·
verified Β·
1 Parent(s): 261bc81

Upload app (2).py

Browse files
Files changed (1) hide show
  1. app (2).py +432 -0
app (2).py ADDED
@@ -0,0 +1,432 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ # Gradio Interface
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
+ # 🎨 Bright and Gradient UI with Updated Coloring
329
+ css = """
330
+ body {
331
+ background: linear-gradient(135deg, #282c34, #4b79a1);
332
+ font-family: 'Poppins', sans-serif;
333
+ }
334
+
335
+ .gradio-container {
336
+ border-radius: 20px;
337
+ padding: 30px;
338
+ background: rgba(255, 255, 255, 0.2);
339
+ backdrop-filter: blur(10px);
340
+ box-shadow: 0px 8px 30px rgba(0, 123, 255, 0.4);
341
+ border: 2px solid rgba(255, 255, 255, 0.4);
342
+ }
343
+
344
+ .gradio-title {
345
+ font-size: 48px;
346
+ font-weight: bold;
347
+ text-align: center;
348
+ background: linear-gradient(90deg, #ff7eb3, #ff758c);
349
+ -webkit-background-clip: text;
350
+ -webkit-text-fill-color: transparent;
351
+ text-shadow: 5px 5px 20px rgba(255, 105, 180, 0.6);
352
+ margin-bottom: 20px;
353
+ animation: glow 2s infinite alternate;
354
+ }
355
+
356
+ @keyframes glow {
357
+ from {
358
+ text-shadow: 5px 5px 30px rgba(255, 87, 134, 0.6);
359
+ }
360
+ to {
361
+ text-shadow: 6px 6px 40px rgba(255, 54, 90, 1);
362
+ }
363
+ }
364
+
365
+ .gradio-box {
366
+ border-radius: 15px;
367
+ padding: 25px;
368
+ background: linear-gradient(135deg, #6a11cb, #2575fc);
369
+ box-shadow: 0px 6px 25px rgba(30, 144, 255, 0.6);
370
+ border: 2px solid #6a5acd;
371
+ color: white;
372
+ font-size: 18px;
373
+ }
374
+
375
+ .gradio-button {
376
+ border-radius: 12px;
377
+ padding: 18px 36px;
378
+ font-size: 20px;
379
+ font-weight: bold;
380
+ color: #fff;
381
+ background: linear-gradient(135deg, #1e90ff, #00bfff);
382
+ box-shadow: 0px 6px 25px rgba(0, 191, 255, 0.6);
383
+ transition: all 0.3s ease-in-out;
384
+ }
385
+
386
+ .gradio-button:hover {
387
+ background: linear-gradient(135deg, #00bfff, #1e90ff);
388
+ box-shadow: 0px 10px 35px rgba(0, 191, 255, 0.9);
389
+ transform: scale(1.1);
390
+ }
391
+
392
+ .gradio-input {
393
+ border-radius: 10px;
394
+ padding: 16px;
395
+ font-size: 18px;
396
+ background: rgba(255, 255, 255, 0.3);
397
+ border: 2px solid rgba(0, 123, 255, 0.5);
398
+ color: #fff;
399
+ transition: 0.3s;
400
+ }
401
+
402
+ .gradio-input:focus {
403
+ border: 2px solid #1e90ff;
404
+ outline: none;
405
+ box-shadow: 0px 5px 20px rgba(30, 144, 255, 0.6);
406
+ }
407
+
408
+ .gradio-output {
409
+ background: linear-gradient(135deg, #f39c12, #e74c3c);
410
+ padding: 22px;
411
+ border-radius: 15px;
412
+ color: white;
413
+ font-size: 20px;
414
+ text-align: center;
415
+ border: 2px solid #f39c12;
416
+ }
417
+
418
+ .gradio-file {
419
+ background: linear-gradient(135deg, #8e44ad, #3498db);
420
+ color: white;
421
+ padding: 16px;
422
+ border-radius: 15px;
423
+ text-align: center;
424
+ font-size: 18px;
425
+ }
426
+ """
427
+
428
+
429
+
430
+
431
+ if __name__ == "__main__":
432
+ app().launch(share=True)