gopichandra commited on
Commit
82f60cd
Β·
verified Β·
1 Parent(s): 863c9cf

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +336 -0
app.py ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ import kaleido
13
+
14
+ # Attribute mappings: readable names to Salesforce API names
15
+ ATTRIBUTE_MAPPING = {
16
+ "Product name": "Productname__c",
17
+ "Colour": "Colour__c",
18
+ "Motortype": "Motortype__c",
19
+ "Frequency": "Frequency__c",
20
+ "Grossweight": "Grossweight__c",
21
+ "Ratio": "Ratio__c",
22
+ "MotorFrame": "Motorframe__c",
23
+ "Model": "Model__c",
24
+ "Speed": "Speed__c",
25
+ "Quantity": "Quantity__c",
26
+ "Voltage": "Voltage__c",
27
+ "Material": "Material__c",
28
+ "Type": "Type__c",
29
+ "Horsepower": "Horsepower__c",
30
+ "Consignee": "Consignee__c",
31
+ "LOT": "LOT__c",
32
+ "Stage": "Stage__c",
33
+ "Outlet": "Outlet__c",
34
+ "Serialnumber": "Serialnumber__c",
35
+ "HeadSize": "Headsize__c",
36
+ "Deliverysize": "Deliverysize__c",
37
+ "Phase": "Phase__c",
38
+ "Size": "Size__c",
39
+ "MRP": "MRP__c",
40
+ "Usebefore": "Usebefore__c",
41
+ "Height": "Height__c",
42
+ "MaximumDischarge Flow": "Maximumdischargeflow__c",
43
+ "DischargeRange": "Dischargeflow__c",
44
+ "Assembledby": "Manufacturer__c",
45
+ "Manufacturedate": "Manufacturedate__c",
46
+ "Companyname": "Companyname__c",
47
+ "Customercarenumber": "Customercarenumber__c",
48
+ "SellerAddress": "Selleraddress__c",
49
+ "Selleremail": "Selleremail__c",
50
+ "GSTIN": "GSTIN__c",
51
+ "Totalamount": "Totalamount__c",
52
+ "Paymentstatus": "Paymentstatus__c",
53
+ "Paymentmethod": "Paymentstatus__c",
54
+ "Invoicedate": "Manufacturedate__c",
55
+ "Warranty": "Warranty__c",
56
+ "Brand": "Brand__c",
57
+ "Motorhorsepower": "Motorhorsepower__c",
58
+ "Power": "Power__c",
59
+ "Motorphase": "Motorphase__c",
60
+ "Enginetype": "Enginetype__c",
61
+ "Tankcapacity": "Tankcapacity__c",
62
+ "Head": "Head__c",
63
+ "Usage/Application": "Usage_Application__c",
64
+ "Volts": "volts__c",
65
+ "Hertz": "Hertz__c",
66
+ "Frame": "frame__c",
67
+ "Mounting": "Mounting__c",
68
+ "Tollfreenumber": "Tollfreenumber__c",
69
+ "Pipesize": "Pipesize__c",
70
+ "Manufacturer": "Manufacturer__c",
71
+ "Office": "Office__c",
72
+ "SRnumber": "SRnumber__c",
73
+ "TypeOfEndUse": "TypeOfEndUse__c",
74
+ "Model Name": "Model_Name_Number__c",
75
+ "coolingmethod": "coolingmethod__c",
76
+ "H.P.": "H_p__c"
77
+ }
78
+
79
+ # List of product names to match
80
+ PRODUCT_NAMES = [
81
+ "Fusion", "Agroking", "CG commercial motors", "Jaguar", "Gaurav"
82
+ ]
83
+
84
+ # Salesforce credentials
85
+ SALESFORCE_USERNAME = "venkatramana@sandbox.com"
86
+ SALESFORCE_PASSWORD = "Seta12345@"
87
+ SALESFORCE_SECURITY_TOKEN = "Drl0jchCwLBfvX4ODMeFDksP"
88
+
89
+ # Initialize PaddleOCR
90
+ ocr = PaddleOCR(use_angle_cls=True, lang='en')
91
+
92
+ # Function to extract text using PaddleOCR
93
+ def extract_text(image):
94
+ result = ocr.ocr(image)
95
+ extracted_text = []
96
+ for line in result[0]:
97
+ extracted_text.append(line[1][0])
98
+ return "\n".join(extracted_text)
99
+
100
+ # Function to match product name using fuzzy matching
101
+ def match_product_name(extracted_text):
102
+ best_match = None
103
+ best_score = 0
104
+
105
+ for line in extracted_text.split("\n"):
106
+ match, score = process.extractOne(line, PRODUCT_NAMES)
107
+ if score > best_score:
108
+ best_match = match
109
+ best_score = score
110
+
111
+ return best_match if best_score >= 70 else None
112
+
113
+ # Function to extract attributes and their values
114
+ def extract_attributes(extracted_text):
115
+ attributes = {}
116
+
117
+ for readable_attr, sf_attr in ATTRIBUTE_MAPPING.items():
118
+ pattern = rf"{re.escape(readable_attr)}[:\-]?\s*(.+)"
119
+ match = re.search(pattern, extracted_text, re.IGNORECASE)
120
+ if match:
121
+ attributes[readable_attr] = match.group(1).strip()
122
+
123
+ return attributes
124
+
125
+ # Function to filter attributes for valid Salesforce fields
126
+ def filter_valid_attributes(attributes, valid_fields):
127
+ return {ATTRIBUTE_MAPPING[key]: value for key, value in attributes.items() if ATTRIBUTE_MAPPING[key] in valid_fields}
128
+
129
+ # Function to interact with Salesforce based on mode and type
130
+ def interact_with_salesforce(mode, entry_type, quantity, attributes):
131
+ try:
132
+ sf = Salesforce(
133
+ username=SALESFORCE_USERNAME,
134
+ password=SALESFORCE_PASSWORD,
135
+ security_token=SALESFORCE_SECURITY_TOKEN
136
+ )
137
+
138
+ object_name = None
139
+ field_name = None
140
+ field_names = []
141
+ product_field_name = "Productname__c"
142
+ model_field_name = "Model__c"
143
+ stage_field_name = "Stage__c"
144
+ hp_field_name = "H_p__c"
145
+ price_field_name = "Price__c"
146
+
147
+ if mode == "Entry":
148
+ if entry_type == "Sales":
149
+ object_name = "VENKATA_RAMANA_MOTORS__c"
150
+ field_name = "Quantity__c"
151
+ elif entry_type == "Non-Sales":
152
+ object_name = "UNBILLING_DATA__c"
153
+ field_name = "TotalQuantity__c"
154
+ elif mode == "Exit":
155
+ if entry_type == "Sales":
156
+ object_name = "Inventory_Management__c"
157
+ field_names = ["Quantity_Sold__c", "soldstock__c"]
158
+ elif entry_type == "Non-Sales":
159
+ object_name = "Un_Billable__c"
160
+ field_names = ["Sold_Out__c", "soldstock__c"]
161
+
162
+ if not object_name or (not field_name and not field_names):
163
+ return "Invalid mode or entry type."
164
+
165
+ sf_object = sf.__getattr__(object_name)
166
+ schema = sf_object.describe()
167
+ valid_fields = {field["name"] for field in schema["fields"]}
168
+
169
+ filtered_attributes = filter_valid_attributes(attributes, valid_fields)
170
+
171
+ if mode == "Exit":
172
+ query_conditions = [f"{product_field_name} = '{attributes['Product name']}'"]
173
+ if "Model Name" in attributes and attributes["Model Name"]:
174
+ query_conditions.append(f"{model_field_name} = '{attributes['Model Name']}'")
175
+ if "Stage" in attributes and attributes["Stage"]:
176
+ query_conditions.append(f"{stage_field_name} = '{attributes['Stage']}'")
177
+ if "H.P." in attributes and attributes["H.P."] != "":
178
+ query_conditions.append(f"{hp_field_name} = '{attributes['H.P.']}'")
179
+
180
+ query = f"SELECT Id, {', '.join(field_names)}, {price_field_name} FROM {object_name} WHERE {' AND '.join(query_conditions)} LIMIT 1"
181
+ response = sf.query(query)
182
+
183
+ if response["records"]:
184
+ record = response["records"][0]
185
+ record_id = record["Id"]
186
+ updated_fields = {field: quantity for field in field_names}
187
+ sf_object.update(record_id, updated_fields)
188
+
189
+ price = record.get(price_field_name, "N/A")
190
+ return (
191
+ f"βœ… Updated record for product '{attributes['Product name']}' in {object_name}.\n"
192
+ f"Updated fields: {updated_fields}.\n"
193
+ f"Details: Product Name: {attributes['Product name']}, H.P.: {attributes['H.P.']}, "
194
+ f"Stage: {attributes['Stage']}, Price: {price}."
195
+ )
196
+ else:
197
+ return f"❌ No matching record found for product '{attributes['Product name']}' in {object_name}."
198
+
199
+ else:
200
+ filtered_attributes[field_name] = quantity
201
+ sf_object.create(filtered_attributes)
202
+ return f"βœ… Data successfully exported to Salesforce object {object_name}."
203
+
204
+ except Exception as e:
205
+ return f"❌ Error interacting with Salesforce: {str(e)}"
206
+
207
+ # Function to process image, extract attributes, and allow editing
208
+ def process_image(image, mode, entry_type, quantity):
209
+ extracted_text = extract_text(image)
210
+ if not extracted_text:
211
+ return "No text detected in the image.", None, None
212
+
213
+ product_name = match_product_name(extracted_text)
214
+ attributes = extract_attributes(extracted_text)
215
+ if product_name:
216
+ attributes["Product name"] = product_name
217
+
218
+ # Ensure fixed attributes are present
219
+ for fixed_attr in ["Stage", "H.P.", "Product name", "Model"]:
220
+ if fixed_attr not in attributes:
221
+ attributes[fixed_attr] = ""
222
+
223
+ # Convert attributes to DataFrame for editing
224
+ df = pd.DataFrame(list(attributes.items()), columns=["Attribute", "Value"])
225
+ return f"Extracted Text:\n{extracted_text}", df, None
226
+
227
+ # Function to handle edited attributes and export to Salesforce
228
+ def export_to_salesforce(mode, entry_type, quantity, edited_df):
229
+ try:
230
+ # Convert edited DataFrame back to dictionary
231
+ edited_attributes = dict(zip(edited_df["Attribute"], edited_df["Value"]))
232
+
233
+ # Export to Salesforce
234
+ message = interact_with_salesforce(mode, entry_type, quantity, edited_attributes)
235
+ return message
236
+ except Exception as e:
237
+ return f"❌ Error exporting to Salesforce: {str(e)}"
238
+
239
+ # Function to pull structured data from Salesforce and display as a table
240
+ def pull_data_from_salesforce(data_type):
241
+ try:
242
+ sf = Salesforce(
243
+ username=SALESFORCE_USERNAME,
244
+ password=SALESFORCE_PASSWORD,
245
+ security_token=SALESFORCE_SECURITY_TOKEN
246
+ )
247
+
248
+ if data_type == "Inventory":
249
+ query = "SELECT Productname__c, Model__c, H_p__c, Stage__c, Current_Stocks__c, soldstock__c, Price__c FROM Inventory_Management__c LIMIT 100"
250
+ else:
251
+ query = "SELECT Productname__c, Model__c, H_p__c, Stage__c, Current_Stock__c, soldstock__c, Price__c FROM Un_Billable__c LIMIT 100"
252
+
253
+ response = sf.query_all(query)
254
+ records = response.get("records", [])
255
+
256
+ if not records:
257
+ return "No data found in Salesforce.", None, None, None
258
+
259
+ df = pd.DataFrame(records)
260
+ df = df.drop(columns=['attributes'], errors='ignore')
261
+
262
+ # Rename columns for better readability
263
+ df.rename(columns={
264
+ "Productname__c": "Product Name",
265
+ "Model__c": "Model",
266
+ "H_p__c": "H.P",
267
+ "Stage__c": "Stage",
268
+ "Current_Stocks__c": "Current Stocks",
269
+ "Current_Stock__c": "Current Stocks",
270
+ "soldstock__c": "Sold Stock",
271
+ "Price__c": "Price"
272
+ }, inplace=True)
273
+
274
+ excel_path = "salesforce_data.xlsx"
275
+ df.to_excel(excel_path, index=False)
276
+
277
+ # Generate interactive vertical bar graph using Matplotlib
278
+ fig, ax = plt.subplots(figsize=(12, 8))
279
+ df.plot(kind='bar', x="Product Name", y="Current Stocks", ax=ax, legend=False)
280
+ ax.set_title("Stock Distribution by Product Name")
281
+ ax.set_xlabel("Product Name")
282
+ ax.set_ylabel("Current Stocks")
283
+ plt.xticks(rotation=45, ha="right", fontsize=10)
284
+ plt.tight_layout()
285
+ buffer = BytesIO()
286
+ plt.savefig(buffer, format="png")
287
+ buffer.seek(0)
288
+ img = Image.open(buffer)
289
+
290
+ return df, excel_path, img
291
+ except Exception as e:
292
+ return f"Error fetching data: {str(e)}", None, None, None
293
+
294
+ # Gradio Interface
295
+ def app():
296
+ with gr.Blocks() as demo:
297
+ with gr.Tab("πŸ“₯ OCR Processing"):
298
+ with gr.Row():
299
+ image_input = gr.Image(type="numpy", label="πŸ“„ Upload Image")
300
+ mode_input = gr.Dropdown(label="πŸ“Œ Mode", choices=["Entry", "Exit"], value="Entry")
301
+ entry_type_input = gr.Radio(label="πŸ“¦ Entry Type", choices=["Sales", "Non-Sales"], value="Sales")
302
+ quantity_input = gr.Number(label="πŸ”’ Quantity", value=1, interactive=True)
303
+ extract_button = gr.Button("Extract Text and Attributes")
304
+ extracted_text_output = gr.Text(label="πŸ“ Extracted Image Data")
305
+ editable_df_output = gr.Dataframe(label="✏️ Edit Attributes (Key-Value Pairs)", interactive=True)
306
+ ok_button = gr.Button("OK")
307
+ result_output = gr.Text(label="πŸš€ Result")
308
+
309
+ with gr.Tab("πŸ“Š Salesforce Data"):
310
+ data_type_input = gr.Dropdown(label="Select Data Type", choices=["Inventory", "Unbilling"], value="Inventory")
311
+ pull_button = gr.Button("Pull Data from Salesforce")
312
+ salesforce_data_output = gr.Dataframe(label="πŸ“Š Salesforce Data")
313
+ excel_download_output = gr.File(label="πŸ“₯ Download Excel")
314
+ graph_output = gr.Image(label="πŸ“ˆ Stock Distribution Graph")
315
+
316
+ # Define button actions
317
+ extract_button.click(
318
+ fn=process_image,
319
+ inputs=[image_input, mode_input, entry_type_input, quantity_input],
320
+ outputs=[extracted_text_output, editable_df_output, result_output]
321
+ )
322
+ ok_button.click(
323
+ fn=export_to_salesforce,
324
+ inputs=[mode_input, entry_type_input, quantity_input, editable_df_output],
325
+ outputs=[result_output]
326
+ )
327
+ pull_button.click(
328
+ fn=pull_data_from_salesforce,
329
+ inputs=[data_type_input],
330
+ outputs=[salesforce_data_output, excel_download_output, graph_output]
331
+ )
332
+
333
+ return demo
334
+
335
+ if __name__ == "__main__":
336
+ app().launch(share=True)