Vishwas1 commited on
Commit
8e839af
Β·
verified Β·
1 Parent(s): 76c86ae

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +360 -0
app.py ADDED
@@ -0,0 +1,360 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import numpy as np
4
+ from simple_salesforce import Salesforce
5
+ import io
6
+ import traceback
7
+ from datetime import datetime
8
+ import os
9
+ import logging
10
+
11
+ # Set up logging
12
+ logging.basicConfig(level=logging.INFO)
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class SalesforceDataLoader:
16
+ def __init__(self):
17
+ self.sf = None
18
+ self.connected = False
19
+ self.available_objects = []
20
+
21
+ def connect_to_salesforce(self, username, password, security_token, sandbox=False):
22
+ """Connect to Salesforce using credentials"""
23
+ try:
24
+ domain = 'test' if sandbox else None
25
+ self.sf = Salesforce(
26
+ username=username,
27
+ password=password,
28
+ security_token=security_token,
29
+ domain=domain
30
+ )
31
+ self.connected = True
32
+
33
+ # Get available objects
34
+ self._get_available_objects()
35
+
36
+ return f"βœ… Successfully connected to Salesforce as {username}", gr.update(visible=True), gr.update(choices=self.available_objects, value=None)
37
+
38
+ except Exception as e:
39
+ logger.error(f"Connection failed: {str(e)}")
40
+ self.connected = False
41
+ return f"❌ Connection failed: {str(e)}", gr.update(visible=False), gr.update(choices=[], value=None)
42
+
43
+ def _get_available_objects(self):
44
+ """Get list of available Salesforce objects"""
45
+ try:
46
+ # Get commonly used objects
47
+ common_objects = ['Account', 'Contact', 'Lead', 'Opportunity', 'Case', 'Campaign', 'User', 'Product2']
48
+ self.available_objects = []
49
+
50
+ for obj_name in common_objects:
51
+ try:
52
+ # Test if object exists and is accessible
53
+ getattr(self.sf, obj_name).describe()
54
+ self.available_objects.append(obj_name)
55
+ except:
56
+ continue
57
+
58
+ except Exception as e:
59
+ logger.error(f"Error getting objects: {str(e)}")
60
+ self.available_objects = ['Account', 'Contact', 'Lead'] # Fallback
61
+
62
+ def get_object_fields(self, object_name):
63
+ """Get fields for selected Salesforce object"""
64
+ if not self.connected or not object_name:
65
+ return gr.update(choices=[], value=None), ""
66
+
67
+ try:
68
+ obj = getattr(self.sf, object_name)
69
+ metadata = obj.describe()
70
+
71
+ fields = []
72
+ field_info = []
73
+
74
+ for field in metadata['fields']:
75
+ if field['createable'] or field['updateable']:
76
+ field_name = field['name']
77
+ field_type = field['type']
78
+ required = "Required" if not field['nillable'] and not field['defaultedOnCreate'] else "Optional"
79
+
80
+ fields.append(field_name)
81
+ field_info.append(f"**{field_name}** ({field_type}) - {required}")
82
+
83
+ field_info_text = "\n".join(field_info[:20]) # Show first 20 fields
84
+ if len(field_info) > 20:
85
+ field_info_text += f"\n... and {len(field_info) - 20} more fields"
86
+
87
+ return gr.update(choices=fields, value=None), field_info_text
88
+
89
+ except Exception as e:
90
+ logger.error(f"Error getting fields: {str(e)}")
91
+ return gr.update(choices=[], value=None), f"Error: {str(e)}"
92
+
93
+ def upload_data_to_salesforce(self, file, object_name, operation, external_id_field=None):
94
+ """Upload data to Salesforce"""
95
+ if not self.connected:
96
+ return "❌ Please connect to Salesforce first", None
97
+
98
+ if not file or not object_name:
99
+ return "❌ Please select a file and object", None
100
+
101
+ try:
102
+ # Read the uploaded file
103
+ if file.name.endswith('.csv'):
104
+ df = pd.read_csv(file.name)
105
+ elif file.name.endswith(('.xlsx', '.xls')):
106
+ df = pd.read_excel(file.name)
107
+ else:
108
+ return "❌ Please upload a CSV or Excel file", None
109
+
110
+ if df.empty:
111
+ return "❌ The uploaded file is empty", None
112
+
113
+ # Get Salesforce object
114
+ sf_object = getattr(self.sf, object_name)
115
+
116
+ # Prepare data for upload
117
+ records = df.to_dict('records')
118
+
119
+ # Clean data - remove NaN values
120
+ for record in records:
121
+ record = {k: v for k, v in record.items() if pd.notna(v)}
122
+
123
+ results = []
124
+ errors = []
125
+
126
+ # Perform bulk operation
127
+ if operation == "Insert":
128
+ try:
129
+ result = sf_object.bulk.insert(records)
130
+ results = result
131
+ except Exception as e:
132
+ return f"❌ Bulk insert failed: {str(e)}", None
133
+
134
+ elif operation == "Update":
135
+ try:
136
+ result = sf_object.bulk.update(records)
137
+ results = result
138
+ except Exception as e:
139
+ return f"❌ Bulk update failed: {str(e)}", None
140
+
141
+ elif operation == "Upsert":
142
+ if not external_id_field:
143
+ return "❌ External ID field is required for upsert operation", None
144
+ try:
145
+ result = sf_object.bulk.upsert(records, external_id_field)
146
+ results = result
147
+ except Exception as e:
148
+ return f"❌ Bulk upsert failed: {str(e)}", None
149
+
150
+ # Process results
151
+ success_count = 0
152
+ error_count = 0
153
+
154
+ for result in results:
155
+ if result.get('success'):
156
+ success_count += 1
157
+ else:
158
+ error_count += 1
159
+ errors.append(result.get('errors', []))
160
+
161
+ # Create results summary
162
+ summary = f"βœ… Operation completed!\n"
163
+ summary += f"πŸ“Š Total records: {len(records)}\n"
164
+ summary += f"βœ… Successful: {success_count}\n"
165
+ summary += f"❌ Failed: {error_count}\n"
166
+
167
+ if errors:
168
+ summary += f"\n**First few errors:**\n"
169
+ for i, error in enumerate(errors[:5]):
170
+ summary += f"{i+1}. {error}\n"
171
+
172
+ # Create downloadable results file
173
+ results_df = pd.DataFrame(results)
174
+ results_csv = results_df.to_csv(index=False)
175
+ results_file = f"salesforce_upload_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
176
+
177
+ with open(results_file, 'w') as f:
178
+ f.write(results_csv)
179
+
180
+ return summary, results_file
181
+
182
+ except Exception as e:
183
+ logger.error(f"Upload error: {str(e)}")
184
+ logger.error(traceback.format_exc())
185
+ return f"❌ Error: {str(e)}", None
186
+
187
+ def export_data_from_salesforce(self, object_name, fields, record_limit=1000):
188
+ """Export data from Salesforce"""
189
+ if not self.connected:
190
+ return "❌ Please connect to Salesforce first", None
191
+
192
+ if not object_name:
193
+ return "❌ Please select an object", None
194
+
195
+ try:
196
+ # Build SOQL query
197
+ if not fields:
198
+ # Get some default fields
199
+ obj = getattr(self.sf, object_name)
200
+ metadata = obj.describe()
201
+ fields = [field['name'] for field in metadata['fields'][:10]] # First 10 fields
202
+
203
+ fields_str = ', '.join(fields)
204
+ query = f"SELECT {fields_str} FROM {object_name} LIMIT {record_limit}"
205
+
206
+ # Execute query
207
+ result = self.sf.query_all(query)
208
+ records = result['records']
209
+
210
+ if not records:
211
+ return "❌ No records found", None
212
+
213
+ # Convert to DataFrame
214
+ df = pd.DataFrame(records)
215
+
216
+ # Remove Salesforce metadata columns
217
+ if 'attributes' in df.columns:
218
+ df = df.drop('attributes', axis=1)
219
+
220
+ # Create downloadable file
221
+ export_file = f"salesforce_export_{object_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
222
+ df.to_csv(export_file, index=False)
223
+
224
+ summary = f"βœ… Export completed!\n"
225
+ summary += f"πŸ“Š Records exported: {len(records)}\n"
226
+ summary += f"πŸ“‹ Fields: {', '.join(fields)}\n"
227
+ summary += f"πŸ“ File: {export_file}"
228
+
229
+ return summary, export_file
230
+
231
+ except Exception as e:
232
+ logger.error(f"Export error: {str(e)}")
233
+ return f"❌ Error: {str(e)}", None
234
+
235
+ # Initialize the Salesforce Data Loader
236
+ sf_loader = SalesforceDataLoader()
237
+
238
+ # Create the Gradio interface
239
+ def create_interface():
240
+ with gr.Blocks(title="Salesforce Data Loader", theme=gr.themes.Soft()) as interface:
241
+ gr.Markdown("""
242
+ # πŸš€ Salesforce Data Loader
243
+
244
+ A powerful tool to upload and download data from Salesforce. Connect with your credentials and start managing your data!
245
+ """)
246
+
247
+ with gr.Tab("πŸ” Connection"):
248
+ gr.Markdown("### Connect to Salesforce")
249
+ with gr.Row():
250
+ with gr.Column():
251
+ username = gr.Textbox(label="Username", placeholder="[email protected]")
252
+ password = gr.Textbox(label="Password", type="password")
253
+ security_token = gr.Textbox(label="Security Token", type="password",
254
+ info="Get this from Salesforce Setup β†’ Personal Information β†’ Reset Security Token")
255
+ with gr.Column():
256
+ sandbox = gr.Checkbox(label="Sandbox Environment", info="Check if connecting to a sandbox")
257
+ connect_btn = gr.Button("πŸ”— Connect to Salesforce", variant="primary")
258
+
259
+ connection_status = gr.Markdown("")
260
+
261
+ with gr.Tab("πŸ“€ Upload Data", visible=False) as upload_tab:
262
+ gr.Markdown("### Upload CSV/Excel data to Salesforce")
263
+
264
+ with gr.Row():
265
+ with gr.Column():
266
+ file_upload = gr.File(label="Upload CSV or Excel file", file_types=[".csv", ".xlsx", ".xls"])
267
+ object_dropdown = gr.Dropdown(label="Select Salesforce Object", choices=[])
268
+ operation_dropdown = gr.Dropdown(
269
+ label="Operation Type",
270
+ choices=["Insert", "Update", "Upsert"],
271
+ value="Insert"
272
+ )
273
+ external_id_field = gr.Dropdown(label="External ID Field (for Upsert)", choices=[], visible=False)
274
+
275
+ with gr.Column():
276
+ object_fields_info = gr.Markdown("Select an object to see available fields")
277
+
278
+ upload_btn = gr.Button("πŸ“€ Upload Data", variant="primary")
279
+ upload_results = gr.Markdown("")
280
+ download_results = gr.File(label="Download Results", visible=False)
281
+
282
+ with gr.Tab("πŸ“₯ Export Data", visible=False) as export_tab:
283
+ gr.Markdown("### Export data from Salesforce")
284
+
285
+ with gr.Row():
286
+ with gr.Column():
287
+ export_object = gr.Dropdown(label="Select Object to Export", choices=[])
288
+ export_fields = gr.CheckboxGroup(label="Select Fields to Export", choices=[])
289
+ record_limit = gr.Slider(minimum=100, maximum=10000, value=1000, step=100,
290
+ label="Record Limit")
291
+
292
+ with gr.Column():
293
+ export_fields_info = gr.Markdown("Select an object to see available fields")
294
+
295
+ export_btn = gr.Button("πŸ“₯ Export Data", variant="primary")
296
+ export_results = gr.Markdown("")
297
+ download_export = gr.File(label="Download Export", visible=False)
298
+
299
+ # Event handlers
300
+ connect_btn.click(
301
+ fn=sf_loader.connect_to_salesforce,
302
+ inputs=[username, password, security_token, sandbox],
303
+ outputs=[connection_status, upload_tab, object_dropdown]
304
+ )
305
+
306
+ # Update export object dropdown when connection is made
307
+ connect_btn.click(
308
+ fn=lambda status, visible, choices: gr.update(choices=choices),
309
+ inputs=[connection_status, upload_tab, object_dropdown],
310
+ outputs=[export_object]
311
+ )
312
+
313
+ object_dropdown.change(
314
+ fn=sf_loader.get_object_fields,
315
+ inputs=[object_dropdown],
316
+ outputs=[external_id_field, object_fields_info]
317
+ )
318
+
319
+ export_object.change(
320
+ fn=sf_loader.get_object_fields,
321
+ inputs=[export_object],
322
+ outputs=[export_fields, export_fields_info]
323
+ )
324
+
325
+ operation_dropdown.change(
326
+ fn=lambda op: gr.update(visible=(op == "Upsert")),
327
+ inputs=[operation_dropdown],
328
+ outputs=[external_id_field]
329
+ )
330
+
331
+ upload_btn.click(
332
+ fn=sf_loader.upload_data_to_salesforce,
333
+ inputs=[file_upload, object_dropdown, operation_dropdown, external_id_field],
334
+ outputs=[upload_results, download_results]
335
+ )
336
+
337
+ download_results.change(
338
+ fn=lambda file: gr.update(visible=file is not None),
339
+ inputs=[download_results],
340
+ outputs=[download_results]
341
+ )
342
+
343
+ export_btn.click(
344
+ fn=sf_loader.export_data_from_salesforce,
345
+ inputs=[export_object, export_fields, record_limit],
346
+ outputs=[export_results, download_export]
347
+ )
348
+
349
+ download_export.change(
350
+ fn=lambda file: gr.update(visible=file is not None),
351
+ inputs=[download_export],
352
+ outputs=[download_export]
353
+ )
354
+
355
+ return interface
356
+
357
+ # Launch the interface
358
+ if __name__ == "__main__":
359
+ interface = create_interface()
360
+ interface.launch(server_name="0.0.0.0", server_port=7860)