VaneshDev commited on
Commit
3624a59
Β·
verified Β·
1 Parent(s): 66745e6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -270
app.py CHANGED
@@ -1,6 +1,5 @@
1
  import datetime
2
  import logging
3
- import os
4
  import sys
5
  import uuid
6
  from pathlib import Path
@@ -9,10 +8,6 @@ import gradio as gr
9
  from reportlab.lib.pagesizes import letter
10
  from reportlab.pdfgen import canvas
11
  from simple_salesforce import Salesforce
12
- from dotenv import load_dotenv
13
-
14
- # Load environment variables
15
- load_dotenv()
16
 
17
  # Configure logging
18
  logging.basicConfig(
@@ -22,13 +17,10 @@ logging.basicConfig(
22
  )
23
  logger = logging.getLogger(__name__)
24
 
25
- # Salesforce credentials from environment variables
26
- SALESFORCE_USERNAME = os.getenv("SALESFORCE_USERNAME", "your_username@example.com")
27
- SALESFORCE_PASSWORD = os.getenv("SALESFORCE_PASSWORD", "your_password")
28
- SALESFORCE_SECURITY_TOKEN = os.getenv("SALESFORCE_SECURITY_TOKEN", "your_security_token")
29
-
30
- # Base URL configuration
31
- BASE_URL = os.getenv("BASE_URL", "http://localhost:7860")
32
 
33
  # Connect to Salesforce
34
  def connect_to_salesforce():
@@ -47,79 +39,66 @@ def connect_to_salesforce():
47
 
48
  sf = connect_to_salesforce()
49
 
50
- # Equipment choices
51
  equipment_choices = [
52
  "Bulldozer", "Crane", "Excavator", "Loader", "Forklift",
53
  "Backhoe", "Grader", "Scraper", "Dump Truck", "Roller"
54
  ]
55
 
56
- # Project choices
57
  project_choices = [
58
  "Project Alpha", "Project Beta", "Project Gamma", "Project Delta", "Project Epsilon",
59
  "Project Zeta", "Project Theta", "Project Sigma", "Project Omega", "Project Phoenix"
60
  ]
61
 
62
- # AI suggestion choices
63
  ai_suggestion_choices = ["Move", "Pause Rent", "Repair", "Replace"]
64
 
 
65
  def generate_pdf_report(record_id, data_dict):
66
- """Generate PDF report and return both local path and public URL"""
67
  report_id = str(uuid.uuid4())[:8]
68
  report_filename = f"report_{report_id}.pdf"
69
- report_dir = Path("static/reports/")
70
- report_dir.mkdir(parents=True, exist_ok=True)
71
- report_path = report_dir / report_filename
72
 
73
- # Create PDF
74
  c = canvas.Canvas(str(report_path), pagesize=letter)
75
- c.setFont("Helvetica-Bold", 16)
76
- c.drawString(100, 750, "Equipment Utilization Report")
77
  c.setFont("Helvetica", 12)
78
- c.drawString(100, 730, f"Generated on: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
79
- c.drawString(100, 710, f"Salesforce Record ID: {record_id}")
80
-
81
- y = 680
82
  for key, val in data_dict.items():
83
  c.drawString(100, y, f"{key}: {val}")
84
  y -= 20
85
-
86
  c.save()
87
-
88
- public_url = f"{BASE_URL}/static/reports/{report_filename}"
89
- return str(report_path), public_url
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
  def call_ai_model(usage_hours, idle_hours, movement_frequency, cost_per_hour, last_maintenance_str):
92
- """Mock AI model call"""
93
- logger.info("AI model called with parameters:")
94
- logger.info(f"Usage Hours: {usage_hours}, Idle Hours: {idle_hours}")
95
- logger.info(f"Movement Frequency: {movement_frequency}, Cost per Hour: {cost_per_hour}")
96
- logger.info(f"Last Maintenance: {last_maintenance_str}")
97
-
98
- # Simple logic for demo purposes
99
- utilization_score = min(1.0, usage_hours / (usage_hours + idle_hours + 0.001))
100
-
101
- if utilization_score < 0.3:
102
- return "Pause Rent", 0.85, utilization_score
103
- elif last_maintenance_str and (datetime.datetime.now() - datetime.datetime.strptime(last_maintenance_str, "%Y-%m-%d")).days > 180:
104
- return "Repair", 0.9, utilization_score
105
- elif cost_per_hour > 100 and idle_hours > usage_hours:
106
- return "Move", 0.8, utilization_score
107
- else:
108
- return "No Action", 0.7, utilization_score
109
 
110
  def process_equipment_utilization(equipment_name, project_name, usage_hours, idle_hours,
111
- movement_frequency, cost_per_hour, last_maintenance, ai_suggestion=None):
112
- """Process equipment data and create Salesforce record"""
113
  last_maintenance_str = last_maintenance.strftime('%Y-%m-%d') if last_maintenance else None
114
-
115
- # Get AI suggestion if not provided
116
  if not ai_suggestion:
117
  ai_suggestion, suggestion_confidence, utilization_score = call_ai_model(
118
- float(usage_hours),
119
- float(idle_hours),
120
- float(movement_frequency),
121
- float(cost_per_hour),
122
- last_maintenance_str or ""
123
  )
124
  else:
125
  suggestion_confidence = 0.9
@@ -128,244 +107,153 @@ def process_equipment_utilization(equipment_name, project_name, usage_hours, idl
128
  summary_data = {
129
  "Equipment Name": equipment_name,
130
  "Project": project_name,
131
- "Usage Hours": f"{usage_hours:.2f}",
132
- "Idle Hours": f"{idle_hours:.2f}",
133
- "Movement Frequency": f"{movement_frequency:.2f}",
134
- "Cost per Hour": f"${cost_per_hour:.2f}",
135
- "AI Suggestion": ai_suggestion,
136
- "Confidence Level": f"{suggestion_confidence*100:.1f}%",
137
- "Utilization Score": f"{utilization_score*100:.1f}%",
138
- "Last Maintenance": last_maintenance_str or "Not Recorded",
139
- "Report Date": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
140
  }
141
 
142
  try:
143
- # Create Salesforce record
144
  record_data = {
145
  "Equipment_Name__c": equipment_name,
146
  "Project_Name__c": project_name,
147
- "Usage_Hours__c": float(usage_hours),
148
- "Idle_Hours__c": float(idle_hours),
149
- "Movement_Frequency__c": float(movement_frequency),
150
- "Cost_per_Hour__c": float(cost_per_hour),
151
  "AI_Suggestion__c": ai_suggestion,
152
  "Suggestion_Confidence__c": suggestion_confidence * 100,
153
  "Utilization_Score__c": utilization_score * 100,
154
- "Last_Maintenance__c": last_maintenance_str,
155
  "Report_Link__c": "Pending",
 
156
  "Dashboard_Flag__c": False
157
  }
 
158
 
159
  response = sf.Equipment_Utilization_Record__c.create(record_data)
 
160
  record_id = response.get("id")
161
- logger.info(f"Created Salesforce record with ID: {record_id}")
162
-
163
- # Generate PDF report
164
- pdf_path, pdf_url = generate_pdf_report(record_id, summary_data)
165
-
166
- # Update record with report URL
167
- sf.Equipment_Utilization_Record__c.update(record_id, {"Report_Link__c": pdf_url})
168
-
 
 
169
  return {
 
170
  "status": "Success",
171
- "record_id": record_id,
172
- "equipment": equipment_name,
173
- "project": project_name,
174
- "ai_suggestion": ai_suggestion,
175
- "confidence": f"{suggestion_confidence*100:.1f}%",
176
- "utilization": f"{utilization_score*100:.1f}%",
177
- "report_url": pdf_url,
178
- "pdf_path": pdf_path
179
  }
180
  except Exception as e:
181
- logger.error(f"Error processing equipment utilization: {str(e)}")
182
- return {
183
- "status": "Error",
184
- "error": str(e)
185
- }
186
 
187
- def gradio_interface(equipment_name, project_name, usage_hours, idle_hours,
188
- movement_frequency, cost_per_hour, last_maintenance, ai_suggestion):
189
- """Gradio interface handler function"""
190
  try:
191
- # Validate numeric inputs
192
- usage_hours = float(usage_hours) if usage_hours else 0.0
193
- idle_hours = float(idle_hours) if idle_hours else 0.0
194
- movement_frequency = float(movement_frequency) if movement_frequency else 0.0
195
- cost_per_hour = float(cost_per_hour) if cost_per_hour else 0.0
196
-
197
- # Validate date input
198
- last_maintenance_dt = None
199
- if last_maintenance:
200
- try:
201
- last_maintenance_dt = datetime.datetime.strptime(last_maintenance, "%Y-%m-%d")
202
- except ValueError:
203
- return (
204
- {"status": "Error", "error": "Invalid date format. Use YYYY-MM-DD."},
205
- None,
206
- None
207
- )
208
-
209
- # Process the data
210
- result = process_equipment_utilization(
211
- equipment_name,
212
- project_name,
213
- usage_hours,
214
- idle_hours,
215
- movement_frequency,
216
- cost_per_hour,
217
- last_maintenance_dt,
218
- ai_suggestion if ai_suggestion else None
219
- )
220
 
221
- # Return results
222
- if result["status"] == "Success":
223
- return (
224
- result,
225
- result["pdf_path"],
226
- result["report_url"]
227
- )
228
- else:
229
- return (
230
- result,
231
- None,
232
- None
233
- )
234
  except Exception as e:
235
- logger.error(f"Error in Gradio interface: {str(e)}")
236
- return (
237
- {"status": "Error", "error": str(e)},
238
- None,
239
- None
240
- )
241
 
242
- # Create Gradio interface
243
- with gr.Blocks(theme=gr.themes.Soft()) as app:
244
- gr.Markdown("# πŸ—οΈ Equipment Utilization Analyzer")
245
- gr.Markdown("Track and optimize your construction equipment usage with AI-powered recommendations.")
246
-
247
- with gr.Row():
248
- with gr.Column():
249
- equipment_dropdown = gr.Dropdown(
250
- choices=equipment_choices,
251
- label="Equipment Type",
252
- interactive=True,
253
- value=equipment_choices[0] if equipment_choices else None
254
- )
255
-
256
- project_dropdown = gr.Dropdown(
257
- choices=project_choices,
258
- label="Project",
259
- interactive=True,
260
- value=project_choices[0] if project_choices else None
261
- )
262
-
263
- ai_suggestion_dropdown = gr.Dropdown(
264
- choices=[""] + ai_suggestion_choices,
265
- label="Pre-selected AI Suggestion (optional)",
266
- interactive=True
267
- )
268
-
269
- last_maintenance = gr.Textbox(
270
- label="Last Maintenance Date (YYYY-MM-DD)",
271
- placeholder="e.g., 2023-01-15",
272
- interactive=True
273
- )
274
-
275
- with gr.Column():
276
- usage_hours = gr.Number(
277
- label="Usage Hours (last 30 days)",
278
- value=0.0,
279
- minimum=0,
280
- step=1.0,
281
- interactive=True
282
- )
283
-
284
- idle_hours = gr.Number(
285
- label="Idle Hours (last 30 days)",
286
- value=0.0,
287
- minimum=0,
288
- step=1.0,
289
- interactive=True
290
- )
291
-
292
- movement_frequency = gr.Number(
293
- label="Movement Frequency (times moved)",
294
- value=0.0,
295
- minimum=0,
296
- step=1.0,
297
- interactive=True
298
- )
299
-
300
- cost_per_hour = gr.Number(
301
- label="Cost per Hour ($)",
302
- value=0.0,
303
- minimum=0,
304
- step=0.1,
305
- precision=2,
306
- interactive=True
307
- )
308
-
309
- submit_btn = gr.Button("Analyze Equipment", variant="primary")
310
-
311
- with gr.Row():
312
- with gr.Column():
313
- result_json = gr.JSON(
314
- label="Analysis Results",
315
- visible=True
316
- )
317
-
318
- report_url = gr.Textbox(
319
- label="Report URL",
320
- interactive=False,
321
- visible=True
322
- )
323
-
324
- report_download = gr.File(
325
- label="Download Report",
326
- visible=True
327
- )
328
-
329
- error_output = gr.Textbox(
330
- label="Error Messages",
331
- visible=False,
332
- interactive=False
333
- )
334
-
335
- # Handle form submission
336
- submit_btn.click(
337
- fn=gradio_interface,
338
- inputs=[
339
- equipment_dropdown,
340
- project_dropdown,
341
- usage_hours,
342
- idle_hours,
343
- movement_frequency,
344
- cost_per_hour,
345
- last_maintenance,
346
- ai_suggestion_dropdown
347
- ],
348
- outputs=[
349
- result_json,
350
- report_download,
351
- report_url
352
- ]
353
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
 
355
- # Run the application
356
  if __name__ == "__main__":
357
- # Create static directory if it doesn't exist
358
- Path("static/reports").mkdir(parents=True, exist_ok=True)
359
-
360
- # Launch with ngrok if enabled
361
- if os.getenv("USE_NGROK", "False").lower() == "true":
362
- from pyngrok import ngrok
363
- public_url = ngrok.connect(7860).public_url
364
- logger.info(f"Ngrok tunnel created: {public_url}")
365
- BASE_URL = public_url
366
-
367
- app.launch(
368
- server_name="0.0.0.0",
369
- server_port=7860,
370
- share=os.getenv("GRADIO_SHARE", "False").lower() == "true"
371
- )
 
1
  import datetime
2
  import logging
 
3
  import sys
4
  import uuid
5
  from pathlib import Path
 
8
  from reportlab.lib.pagesizes import letter
9
  from reportlab.pdfgen import canvas
10
  from simple_salesforce import Salesforce
 
 
 
 
11
 
12
  # Configure logging
13
  logging.basicConfig(
 
17
  )
18
  logger = logging.getLogger(__name__)
19
 
20
+ # Salesforce credentials
21
+ SALESFORCE_USERNAME = "vaneshdevarapalli866@agentforce.com"
22
+ SALESFORCE_PASSWORD = "vanesh@331"
23
+ SALESFORCE_SECURITY_TOKEN = "VRUVbBOdG0s9Q4xy0W6DB1Y6b"
 
 
 
24
 
25
  # Connect to Salesforce
26
  def connect_to_salesforce():
 
39
 
40
  sf = connect_to_salesforce()
41
 
 
42
  equipment_choices = [
43
  "Bulldozer", "Crane", "Excavator", "Loader", "Forklift",
44
  "Backhoe", "Grader", "Scraper", "Dump Truck", "Roller"
45
  ]
46
 
 
47
  project_choices = [
48
  "Project Alpha", "Project Beta", "Project Gamma", "Project Delta", "Project Epsilon",
49
  "Project Zeta", "Project Theta", "Project Sigma", "Project Omega", "Project Phoenix"
50
  ]
51
 
 
52
  ai_suggestion_choices = ["Move", "Pause Rent", "Repair", "Replace"]
53
 
54
+ # Generate PDF report
55
  def generate_pdf_report(record_id, data_dict):
 
56
  report_id = str(uuid.uuid4())[:8]
57
  report_filename = f"report_{report_id}.pdf"
58
+ report_path = Path(f"static/reports/{report_filename}")
59
+ report_path.parent.mkdir(parents=True, exist_ok=True)
 
60
 
 
61
  c = canvas.Canvas(str(report_path), pagesize=letter)
 
 
62
  c.setFont("Helvetica", 12)
63
+ c.drawString(100, 750, f"Equipment Utilization Report")
64
+ c.drawString(100, 735, f"Salesforce Record ID: {record_id}")
65
+
66
+ y = 710
67
  for key, val in data_dict.items():
68
  c.drawString(100, y, f"{key}: {val}")
69
  y -= 20
70
+
71
  c.save()
72
+ return str(report_path)
73
+
74
+ # Generate CSV report (without public URL)
75
+ def generate_csv_report(record_id, data_dict):
76
+ report_id = str(uuid.uuid4())[:8]
77
+ csv_filename = f"report_{report_id}.csv"
78
+ csv_path = Path(f"static/reports/{csv_filename}")
79
+ csv_path.parent.mkdir(parents=True, exist_ok=True)
80
+
81
+ with open(csv_path, mode='w', newline='') as f:
82
+ writer = csv.writer(f)
83
+ writer.writerow(["Field", "Value"])
84
+ writer.writerow(["Salesforce Record ID", record_id])
85
+ for k, v in data_dict.items():
86
+ writer.writerow([k, v])
87
+
88
+ return str(csv_path)
89
 
90
  def call_ai_model(usage_hours, idle_hours, movement_frequency, cost_per_hour, last_maintenance_str):
91
+ # Placeholder response since API endpoint is removed
92
+ logger.info("AI model endpoint removed; returning placeholder response.")
93
+ return "No Action", 0.0, 0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
95
  def process_equipment_utilization(equipment_name, project_name, usage_hours, idle_hours,
96
+ movement_frequency, cost_per_hour, last_maintenance, ai_suggestion):
 
97
  last_maintenance_str = last_maintenance.strftime('%Y-%m-%d') if last_maintenance else None
98
+
 
99
  if not ai_suggestion:
100
  ai_suggestion, suggestion_confidence, utilization_score = call_ai_model(
101
+ usage_hours, idle_hours, movement_frequency, cost_per_hour, last_maintenance_str or ""
 
 
 
 
102
  )
103
  else:
104
  suggestion_confidence = 0.9
 
107
  summary_data = {
108
  "Equipment Name": equipment_name,
109
  "Project": project_name,
110
+ "Usage Hours": usage_hours,
111
+ "Idle Hours": idle_hours,
112
+ "Suggestion": ai_suggestion,
113
+ "Confidence": suggestion_confidence,
114
+ "Utilization Score": utilization_score,
115
+ "Cost per Hour": cost_per_hour # Added to summary_data for the report
 
 
 
116
  }
117
 
118
  try:
119
+ # Log the data being sent to Salesforce
120
  record_data = {
121
  "Equipment_Name__c": equipment_name,
122
  "Project_Name__c": project_name,
123
+ "Usage_Hours__c": usage_hours,
124
+ "Idle_Hours__c": idle_hours,
 
 
125
  "AI_Suggestion__c": ai_suggestion,
126
  "Suggestion_Confidence__c": suggestion_confidence * 100,
127
  "Utilization_Score__c": utilization_score * 100,
128
+ "Cost_per_Hour__c": cost_per_hour,
129
  "Report_Link__c": "Pending",
130
+ "Last_Maintenance__c": last_maintenance_str,
131
  "Dashboard_Flag__c": False
132
  }
133
+ logger.info(f"Creating Salesforce record with data: {record_data}")
134
 
135
  response = sf.Equipment_Utilization_Record__c.create(record_data)
136
+
137
  record_id = response.get("id")
138
+ logger.info(f"Successfully created Salesforce record with ID: {record_id}")
139
+
140
+ # Generate both CSV and PDF reports
141
+ csv_path = generate_csv_report(record_id, summary_data)
142
+ pdf_path = generate_pdf_report(record_id, summary_data)
143
+
144
+ # Update the Salesforce record with the local PDF path
145
+ sf.Equipment_Utilization_Record__c.update(record_id, {"Report_Link__c": pdf_path})
146
+ logger.info(f"Updated Salesforce record {record_id} with Report_Link__c: {pdf_path}")
147
+
148
  return {
149
+ "Salesforce_Record_Id": record_id,
150
  "status": "Success",
151
+ "AI_Suggestion": ai_suggestion,
152
+ "Suggestion_Confidence": suggestion_confidence,
153
+ "Utilization_Score": utilization_score,
154
+ "Report_Link": pdf_path,
155
+ "report_file_path": pdf_path
 
 
 
156
  }
157
  except Exception as e:
158
+ logger.error(f"Error creating or updating Salesforce record: {e}")
159
+ return {"error": str(e)}
 
 
 
160
 
161
+ def gradio_upload_process(equipment_name, project_name, usage_hours, idle_hours,
162
+ movement_frequency, cost_per_hour, last_maintenance, ai_suggestion):
 
163
  try:
164
+ usage_hours = float(usage_hours)
165
+ idle_hours = float(idle_hours)
166
+ movement_frequency = float(movement_frequency)
167
+ cost_per_hour = float(cost_per_hour)
168
+ except Exception as e:
169
+ return {"error": f"Invalid numeric input: {str(e)}"}, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
+ try:
172
+ last_maintenance_dt = datetime.datetime.strptime(last_maintenance, "%Y-%m-%d") if last_maintenance else None
 
 
 
 
 
 
 
 
 
 
 
173
  except Exception as e:
174
+ return {"error": f"Invalid date format for Last Maintenance (expected YYYY-MM-DD): {str(e)}"}, None
 
 
 
 
 
175
 
176
+ result = process_equipment_utilization(
177
+ equipment_name,
178
+ project_name,
179
+ usage_hours,
180
+ idle_hours,
181
+ movement_frequency,
182
+ cost_per_hour,
183
+ last_maintenance_dt,
184
+ ai_suggestion
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  )
186
+ return result, result.get("report_file_path")
187
+
188
+ with gr.Blocks() as app:
189
+ gr.Markdown("## πŸ“‹ Equipment Utilization Record Uploader")
190
+ gr.Markdown("Fill in the details below to generate AI suggestions and save them to Salesforce.")
191
+
192
+ with gr.Group():
193
+ with gr.Row():
194
+ equipment_dropdown = gr.Dropdown(choices=equipment_choices, label="πŸ”§ Equipment Name", interactive=True)
195
+ project_dropdown = gr.Dropdown(choices=project_choices, label="🏍️ Project Name", interactive=True)
196
+ ai_suggestion_dropdown = gr.Dropdown(choices=[""] + ai_suggestion_choices, label="🧐 AI Suggestion (optional)", interactive=True)
197
+
198
+ gr.Markdown("---")
199
+
200
+ with gr.Row():
201
+ usage_hours = gr.Number(label="⏱️ Usage Hours", value=0, minimum=0)
202
+ idle_hours = gr.Number(label="πŸ•’ Idle Hours", value=0, minimum=0)
203
+
204
+ with gr.Row():
205
+ movement_frequency = gr.Number(label="πŸ“ˆ Movement Frequency", value=0, minimum=0)
206
+ cost_per_hour = gr.Number(label="πŸ’° Cost per Hour", value=0, minimum=0)
207
+
208
+ with gr.Row():
209
+ last_maintenance = gr.Textbox(label="πŸ› οΈ Last Maintenance Date (YYYY-MM-DD)", placeholder="Optional")
210
+
211
+ gr.Markdown("---")
212
+
213
+ with gr.Row():
214
+ submit_button = gr.Button("πŸš€ Submit", variant="primary")
215
+ output = gr.JSON(label="πŸ“„ Salesforce Record Creation Result")
216
+ report_file_output = gr.File(label="πŸ“ƒ Download PDF Report")
217
+
218
+ submit_button.click(
219
+ fn=gradio_upload_process,
220
+ inputs=[
221
+ equipment_dropdown, project_dropdown,
222
+ usage_hours, idle_hours,
223
+ movement_frequency, cost_per_hour,
224
+ last_maintenance, ai_suggestion_dropdown
225
+ ],
226
+ outputs=[output, report_file_output]
227
+ )
228
+
229
+ app.css = """
230
+ .gradio-container {
231
+ background-color: #000000 !important;
232
+ padding: 20px;
233
+ color: #ffffff !important;
234
+ }
235
+ .gr-button-primary {
236
+ background-color: #1e90ff !important;
237
+ color: white !important;
238
+ }
239
+ .gr-button-primary:hover {
240
+ background-color: #0d6efd !important;
241
+ }
242
+ .gr-markdown {
243
+ font-size: 18px;
244
+ font-weight: 600;
245
+ color: #ffffff !important;
246
+ }
247
+ label {
248
+ font-weight: 500;
249
+ color: #ffffff !important;
250
+ }
251
+ input, textarea, select {
252
+ background-color: #1c1c1c !important;
253
+ color: #ffffff !important;
254
+ border: 1px solid #444 !important;
255
+ }
256
+ """
257
 
 
258
  if __name__ == "__main__":
259
+ app.launch()