petter2025 commited on
Commit
b1fa2d5
Β·
verified Β·
1 Parent(s): 68150cc

Update ui/styles.py

Browse files
Files changed (1) hide show
  1. ui/styles.py +334 -674
ui/styles.py CHANGED
@@ -1,684 +1,344 @@
1
  """
2
- Enhanced CSS styles for ARF demo
3
- Comprehensive styling for expressive Tab 1
4
  """
 
 
 
 
5
 
6
- def get_styles() -> str:
7
- """Get all CSS styles for the ARF demo"""
8
- return """
9
- /* ===== Base Styles ===== */
10
- .demo-container {
11
- max-width: 1800px;
12
- margin: 0 auto;
13
- padding: 20px;
14
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
15
- }
16
-
17
- .header-section {
18
- text-align: center;
19
- margin-bottom: 25px;
20
- padding: 30px 40px;
21
- background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%);
22
- color: white;
23
- border-radius: 16px;
24
- box-shadow: 0 8px 32px rgba(59, 130, 246, 0.15);
25
- }
26
-
27
- .status-bar {
28
- display: flex;
29
- justify-content: center;
30
- gap: 20px;
31
- margin-bottom: 30px;
32
- padding: 15px;
33
- background: #f8fafc;
34
- border-radius: 12px;
35
- border: 1px solid #e2e8f0;
36
- flex-wrap: wrap;
37
- }
38
-
39
- .status-item {
40
- padding: 8px 16px;
41
- background: white;
42
- border-radius: 8px;
43
- font-size: 14px;
44
- font-weight: 500;
45
- display: flex;
46
- align-items: center;
47
- gap: 6px;
48
- border: 1px solid #e2e8f0;
49
- }
50
-
51
- .status-item.active {
52
- background: #10b981;
53
- color: white;
54
- border-color: #10b981;
55
- }
56
-
57
- /* ===== Tab 1 Specific Styles ===== */
58
-
59
- /* Scenario Card */
60
- .scenario-card {
61
- border: 1px solid #e2e8f0;
62
- border-radius: 14px;
63
- padding: 20px;
64
- background: white;
65
- box-shadow: 0 4px 12px rgba(0,0,0,0.05);
66
- margin-bottom: 20px;
67
- transition: all 0.3s ease;
68
- }
69
-
70
- .scenario-card:hover {
71
- box-shadow: 0 8px 24px rgba(0,0,0,0.08);
72
- transform: translateY(-2px);
73
- }
74
-
75
- .scenario-header {
76
- display: flex;
77
- justify-content: space-between;
78
- align-items: center;
79
- margin-bottom: 15px;
80
- padding-bottom: 12px;
81
- border-bottom: 2px solid #f1f5f9;
82
- }
83
-
84
- .scenario-header h3 {
85
- margin: 0;
86
- font-size: 18px;
87
- color: #1e293b;
88
- }
89
-
90
- .severity-badge {
91
- padding: 4px 12px;
92
- border-radius: 20px;
93
- font-size: 12px;
94
- font-weight: bold;
95
- color: white;
96
- text-transform: uppercase;
97
- letter-spacing: 0.5px;
98
- }
99
-
100
- .severity-badge.high {
101
- background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
102
- }
103
-
104
- .severity-badge.medium {
105
- background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
106
- }
107
-
108
- .severity-badge.low {
109
- background: linear-gradient(135deg, #10b981 0%, #059669 100%);
110
- }
111
-
112
- .scenario-details {
113
- margin-top: 15px;
114
- }
115
-
116
- .scenario-detail-row {
117
- display: flex;
118
- justify-content: space-between;
119
- align-items: center;
120
- margin-bottom: 8px;
121
- padding: 4px 0;
122
- }
123
-
124
- .detail-label {
125
- font-size: 13px;
126
- color: #64748b;
127
- font-weight: 500;
128
- }
129
-
130
- .detail-value {
131
- font-size: 14px;
132
- color: #1e293b;
133
- font-weight: 600;
134
- }
135
-
136
- .detail-value.revenue-risk {
137
- color: #ef4444;
138
- font-weight: 700;
139
- }
140
-
141
- .scenario-tags {
142
- display: flex;
143
- flex-wrap: wrap;
144
- gap: 6px;
145
- margin-top: 15px;
146
- padding-top: 12px;
147
- border-top: 1px solid #f1f5f9;
148
- }
149
-
150
- .scenario-tag {
151
- padding: 3px 8px;
152
- background: #f1f5f9;
153
- border-radius: 6px;
154
- font-size: 11px;
155
- color: #475569;
156
- font-weight: 500;
157
- }
158
-
159
- /* Agent Cards */
160
- .agent-card {
161
- border: 2px solid;
162
- border-radius: 14px;
163
- padding: 18px;
164
- background: white;
165
- text-align: center;
166
- flex: 1;
167
- margin: 5px;
168
- min-height: 180px;
169
- display: flex;
170
- flex-direction: column;
171
- align-items: center;
172
- justify-content: space-between;
173
- transition: all 0.3s ease;
174
- }
175
-
176
- .agent-card:hover {
177
- transform: translateY(-4px);
178
- box-shadow: 0 12px 24px rgba(0,0,0,0.1);
179
- }
180
-
181
- .agent-card.detection {
182
- border-color: #3b82f6;
183
- background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
184
- }
185
-
186
- .agent-card.recall {
187
- border-color: #8b5cf6;
188
- background: linear-gradient(135deg, #f5f3ff 0%, #ede9fe 100%);
189
- }
190
-
191
- .agent-card.decision {
192
- border-color: #10b981;
193
- background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
194
- }
195
-
196
- .agent-icon {
197
- font-size: 32px;
198
- margin-bottom: 10px;
199
- }
200
-
201
- .agent-content {
202
- width: 100%;
203
- }
204
-
205
- .agent-content h4 {
206
- margin: 0 0 8px 0;
207
- font-size: 16px;
208
- color: #1e293b;
209
- }
210
-
211
- .agent-status-text {
212
- font-size: 13px;
213
- color: #475569;
214
- margin-bottom: 12px;
215
- line-height: 1.4;
216
- }
217
-
218
- .agent-metrics {
219
- display: flex;
220
- justify-content: space-around;
221
- margin-bottom: 12px;
222
- }
223
-
224
- .agent-metric {
225
- font-size: 11px;
226
- padding: 3px 8px;
227
- background: rgba(255, 255, 255, 0.8);
228
- border-radius: 6px;
229
- color: #475569;
230
- font-weight: 500;
231
- }
232
-
233
- .agent-status {
234
- display: inline-block;
235
- padding: 5px 14px;
236
- border-radius: 20px;
237
- font-size: 12px;
238
- font-weight: bold;
239
- color: white;
240
- text-transform: uppercase;
241
- letter-spacing: 0.5px;
242
- }
243
-
244
- .agent-status.active {
245
- background: linear-gradient(135deg, #10b981 0%, #059669 100%);
246
- }
247
-
248
- /* OSS vs Enterprise Sections */
249
- .oss-section, .enterprise-section {
250
- padding: 20px;
251
- border-radius: 14px;
252
- margin-bottom: 15px;
253
- flex: 1;
254
- min-height: 320px;
255
- display: flex;
256
- flex-direction: column;
257
- }
258
-
259
- .oss-section {
260
- background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
261
- border: 2px solid #0ea5e9;
262
- }
263
-
264
- .enterprise-section {
265
- background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
266
- border: 2px solid #10b981;
267
- }
268
-
269
- .edition-header {
270
- display: flex;
271
- align-items: center;
272
- gap: 10px;
273
- margin-bottom: 15px;
274
- padding-bottom: 12px;
275
- border-bottom: 2px solid rgba(255, 255, 255, 0.3);
276
- }
277
-
278
- .edition-icon {
279
- font-size: 28px;
280
- }
281
-
282
- .edition-header h3 {
283
- margin: 0;
284
- font-size: 20px;
285
- color: #1e293b;
286
- flex: 1;
287
- }
288
-
289
- .edition-badge {
290
- padding: 4px 10px;
291
- background: rgba(255, 255, 255, 0.9);
292
- border-radius: 8px;
293
- font-size: 11px;
294
- font-weight: bold;
295
- color: #475569;
296
- }
297
-
298
- .edition-description {
299
- margin-bottom: 20px;
300
- padding: 12px;
301
- background: rgba(255, 255, 255, 0.7);
302
- border-radius: 10px;
303
- }
304
-
305
- .edition-description p {
306
- margin: 0;
307
- font-size: 14px;
308
- color: #475569;
309
- font-weight: 500;
310
- }
311
-
312
- .intent-card, .execution-card {
313
- background: white;
314
- border-radius: 12px;
315
- padding: 20px;
316
- box-shadow: 0 4px 12px rgba(0,0,0,0.05);
317
- flex: 1;
318
- display: flex;
319
- flex-direction: column;
320
- }
321
-
322
- .intent-header, .execution-header {
323
- display: flex;
324
- justify-content: space-between;
325
- align-items: center;
326
- margin-bottom: 15px;
327
- padding-bottom: 10px;
328
- border-bottom: 1px solid #f1f5f9;
329
- }
330
-
331
- .intent-header h4, .execution-header h4 {
332
- margin: 0;
333
- font-size: 16px;
334
- color: #1e293b;
335
- }
336
-
337
- .intent-confidence {
338
- padding: 4px 10px;
339
- background: #dbeafe;
340
- color: #1d4ed8;
341
- border-radius: 6px;
342
- font-size: 12px;
343
- font-weight: bold;
344
- }
345
-
346
- .execution-mode {
347
- padding: 4px 10px;
348
- background: #10b981;
349
- color: white;
350
- border-radius: 6px;
351
- font-size: 12px;
352
- font-weight: bold;
353
- text-transform: uppercase;
354
- }
355
-
356
- .execution-mode.autonomous {
357
- background: linear-gradient(135deg, #10b981 0%, #059669 100%);
358
- }
359
-
360
- .execution-mode.approval {
361
- background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
362
- }
363
-
364
- .intent-details, .execution-details {
365
- flex: 1;
366
- }
367
-
368
- .intent-details p, .execution-details p {
369
- margin: 8px 0;
370
- font-size: 14px;
371
- color: #475569;
372
- }
373
-
374
- .intent-details strong, .execution-details strong {
375
- color: #1e293b;
376
- }
377
-
378
- .savings-highlight {
379
- color: #10b981;
380
- font-weight: 700;
381
- font-size: 16px;
382
- }
383
-
384
- .boundary-stop, .boundary-start {
385
- margin-top: 20px;
386
- text-align: center;
387
- }
388
-
389
- .stop-line, .start-line {
390
- height: 2px;
391
- background: linear-gradient(90deg, transparent, #3b82f6, transparent);
392
- margin: 8px 0;
393
- }
394
-
395
- .start-line {
396
- background: linear-gradient(90deg, transparent, #10b981, transparent);
397
- }
398
-
399
- .stop-text, .start-text {
400
- font-size: 12px;
401
- font-weight: bold;
402
- padding: 6px 12px;
403
- border-radius: 8px;
404
- display: inline-block;
405
- }
406
-
407
- .stop-text {
408
- background: #fee2e2;
409
- color: #dc2626;
410
- }
411
-
412
- .start-text {
413
- background: #dcfce7;
414
- color: #166534;
415
- }
416
-
417
- /* Metric Cards */
418
- .metric-card {
419
- border: 1px solid #e2e8f0;
420
- border-radius: 12px;
421
- padding: 18px;
422
- background: white;
423
- margin: 8px;
424
- text-align: center;
425
- flex: 1;
426
- min-width: 140px;
427
- transition: all 0.3s ease;
428
- }
429
-
430
- .metric-card:hover {
431
- transform: translateY(-4px);
432
- box-shadow: 0 8px 16px rgba(0,0,0,0.08);
433
- }
434
-
435
- .metric-card.detection {
436
- border-left: 4px solid #3b82f6;
437
- }
438
-
439
- .metric-card.mttr {
440
- border-left: 4px solid #10b981;
441
- }
442
-
443
- .metric-card.auto-heal {
444
- border-left: 4px solid #8b5cf6;
445
- }
446
-
447
- .metric-card.savings {
448
- border-left: 4px solid #f59e0b;
449
- }
450
-
451
- .metric-icon {
452
- font-size: 28px;
453
- margin-bottom: 10px;
454
- }
455
-
456
- .metric-content h4 {
457
- margin: 0 0 8px 0;
458
- font-size: 14px;
459
- color: #64748b;
460
- font-weight: 600;
461
- }
462
-
463
- .metric-value {
464
- font-size: 28px;
465
- font-weight: bold;
466
- color: #1e40af;
467
- margin: 8px 0;
468
- }
469
-
470
- .metric-card.mttr .metric-value {
471
- color: #10b981;
472
- }
473
-
474
- .metric-card.auto-heal .metric-value {
475
- color: #8b5cf6;
476
- }
477
-
478
- .metric-card.savings .metric-value {
479
- color: #f59e0b;
480
- }
481
-
482
- .metric-comparison {
483
- font-size: 12px;
484
- color: #64748b;
485
- margin: 0;
486
- }
487
-
488
- /* Buttons */
489
- .oss-btn {
490
- background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
491
- color: white !important;
492
- border: none;
493
- padding: 16px 24px;
494
- border-radius: 12px;
495
- font-weight: 600;
496
- font-size: 16px;
497
- width: 100%;
498
- transition: all 0.3s ease;
499
- }
500
-
501
- .oss-btn:hover {
502
- transform: translateY(-2px);
503
- box-shadow: 0 8px 24px rgba(59, 130, 246, 0.3);
504
- }
505
-
506
- .enterprise-btn {
507
- background: linear-gradient(135deg, #10b981 0%, #059669 100%);
508
- color: white !important;
509
- border: none;
510
- padding: 16px 24px;
511
- border-radius: 12px;
512
- font-weight: 600;
513
- font-size: 16px;
514
- width: 100%;
515
- transition: all 0.3s ease;
516
- }
517
-
518
- .enterprise-btn:hover {
519
- transform: translateY(-2px);
520
- box-shadow: 0 8px 24px rgba(16, 185, 129, 0.3);
521
- }
522
-
523
- .button-info {
524
- font-size: 12px;
525
- color: #64748b;
526
- text-align: center;
527
- margin-top: 6px !important;
528
- font-style: italic;
529
- }
530
-
531
- /* Approval Status */
532
- .approval-status {
533
- border: 2px solid #e2e8f0;
534
- border-radius: 14px;
535
- padding: 20px;
536
- background: white;
537
- margin-top: 20px;
538
- }
539
-
540
- .approval-header {
541
- display: flex;
542
- justify-content: space-between;
543
- align-items: center;
544
- margin-bottom: 15px;
545
- padding-bottom: 12px;
546
- border-bottom: 2px solid #f1f5f9;
547
- }
548
-
549
- .approval-header h4 {
550
- margin: 0;
551
- font-size: 16px;
552
- color: #1e293b;
553
- }
554
-
555
- .approval-badge {
556
- padding: 4px 12px;
557
- border-radius: 8px;
558
- font-size: 12px;
559
- font-weight: bold;
560
- text-transform: uppercase;
561
- }
562
-
563
- .approval-badge.not-required {
564
- background: #10b981;
565
- color: white;
566
- }
567
-
568
- .approval-badge.required {
569
- background: #f59e0b;
570
- color: white;
571
- }
572
-
573
- .approval-badge.pending {
574
- background: #3b82f6;
575
- color: white;
576
- }
577
-
578
- .approval-content {
579
- margin-top: 15px;
580
- }
581
-
582
- .approval-content p {
583
- margin: 8px 0;
584
- font-size: 14px;
585
- color: #475569;
586
- }
587
-
588
- .approval-workflow {
589
- display: flex;
590
- flex-direction: column;
591
- gap: 10px;
592
- margin-top: 20px;
593
- }
594
-
595
- .workflow-step {
596
- padding: 12px;
597
- background: #f8fafc;
598
- border-radius: 10px;
599
- border-left: 4px solid #3b82f6;
600
- font-size: 14px;
601
- color: #475569;
602
- font-weight: 500;
603
- }
604
-
605
- .demo-info {
606
- font-size: 12px;
607
- color: #64748b;
608
- text-align: center;
609
- margin-top: 8px !important;
610
- font-style: italic;
611
- }
612
-
613
- /* Footer */
614
- .footer {
615
- text-align: center;
616
- padding: 25px;
617
- color: #6b7280;
618
- font-size: 14px;
619
- margin-top: 40px;
620
- border-top: 2px solid #e5e7eb;
621
- background: #f9fafb;
622
- border-radius: 12px;
623
- }
624
-
625
- .footer strong {
626
- color: #1e293b;
627
- font-size: 16px;
628
- }
629
-
630
- .footer-links {
631
- margin-top: 15px;
632
- display: flex;
633
- justify-content: center;
634
- gap: 20px;
635
- flex-wrap: wrap;
636
- }
637
-
638
- .footer-links a {
639
- color: #3b82f6;
640
- text-decoration: none;
641
- font-weight: 500;
642
- transition: color 0.2s ease;
643
- }
644
-
645
- .footer-links a:hover {
646
- color: #1d4ed8;
647
- text-decoration: underline;
648
- }
649
-
650
- /* Responsive Adjustments */
651
- @media (max-width: 1200px) {
652
- .status-bar {
653
- gap: 10px;
654
- }
655
 
656
- .status-item {
657
- font-size: 13px;
658
- padding: 6px 12px;
659
- }
 
 
 
 
 
660
 
661
- .agent-card {
662
- min-height: 200px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
663
  }
664
 
665
- .metric-card {
666
- min-width: 120px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
667
  }
668
- }
669
 
670
- /* Gradient backgrounds for panels */
671
- .gradio-container .tab-nav {
672
- background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
673
- border-radius: 12px;
674
- padding: 8px;
675
- margin-bottom: 20px;
676
- }
 
 
 
 
 
 
 
 
677
 
678
- .gradio-container .tab-nav .selected {
679
- background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%) !important;
680
- color: white !important;
681
- font-weight: 600;
682
- border-radius: 10px;
683
- }
684
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  """
2
+ Configuration management for ARF Demo
3
+ Updated with REAL ARF installation detection - FIXED ENUM ERROR
4
  """
5
+ from typing import Optional, Dict, Any, List
6
+ from enum import Enum
7
+ import os
8
+ import logging
9
 
10
+ logger = logging.getLogger(__name__)
11
+
12
+ # Try to import from pydantic-settings, fallback to pydantic
13
+ try:
14
+ from pydantic_settings import BaseSettings
15
+ from pydantic import Field, validator
16
+ PYDANTIC_V2 = True
17
+ logger.info("Using pydantic-settings for BaseSettings")
18
+ except ImportError:
19
+ try:
20
+ from pydantic import BaseSettings, Field, validator
21
+ PYDANTIC_V2 = False
22
+ logger.info("Using pydantic.BaseSettings (older version)")
23
+ except ImportError as e:
24
+ logger.error(f"Failed to import pydantic: {e}")
25
+ # Create minimal fallback
26
+ class BaseSettings:
27
+ def __init__(self, **kwargs):
28
+ for k, v in kwargs.items():
29
+ setattr(self, k, v)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
+ class Field:
32
+ @staticmethod
33
+ def default(value):
34
+ return value
35
+
36
+ def validator(*args, **kwargs):
37
+ def decorator(func):
38
+ return func
39
+ return decorator
40
 
41
+ PYDANTIC_V2 = False
42
+
43
+
44
+ class ARFMode(str, Enum):
45
+ """ARF operation modes"""
46
+ DEMO = "demo"
47
+ OSS = "oss"
48
+ ENTERPRISE = "enterprise"
49
+
50
+
51
+ class SafetyMode(str, Enum):
52
+ """Safety modes for execution"""
53
+ ADVISORY = "advisory"
54
+ APPROVAL = "approval"
55
+ AUTONOMOUS = "autonomous"
56
+
57
+
58
+ class InstallationStatus(str, Enum):
59
+ """ARF package installation status"""
60
+ NOT_INSTALLED = "not_installed"
61
+ OSS_ONLY = "oss_only"
62
+ ENTERPRISE = "enterprise"
63
+ BOTH = "both"
64
+
65
+
66
+ class Settings(BaseSettings):
67
+ """
68
+ Application settings with environment variable support
69
+ """
70
+
71
+ # ===== System Mode =====
72
+ arf_mode: str = Field(
73
+ default="demo", # Changed from ARFMode to string to avoid enum issues
74
+ description="ARF operation mode: demo, oss, enterprise"
75
+ )
76
+
77
+ use_true_arf: bool = Field(
78
+ default=True,
79
+ description="Use true ARF integration when available"
80
+ )
81
+
82
+ # ===== Installation Status (Auto-detected) =====
83
+ arf_oss_installed: bool = Field(
84
+ default=False,
85
+ description="ARF OSS package installed"
86
+ )
87
+
88
+ arf_enterprise_installed: bool = Field(
89
+ default=False,
90
+ description="ARF Enterprise package installed"
91
+ )
92
+
93
+ arf_oss_version: Optional[str] = Field(
94
+ default=None,
95
+ description="ARF OSS version if installed"
96
+ )
97
+
98
+ arf_enterprise_version: Optional[str] = Field(
99
+ default=None,
100
+ description="ARF Enterprise version if installed"
101
+ )
102
+
103
+ # ===== ARF Configuration =====
104
+ arf_api_key: Optional[str] = Field(
105
+ default=None,
106
+ description="ARF API key for real integration"
107
+ )
108
+
109
+ arf_base_url: str = Field(
110
+ default="https://api.arf.dev",
111
+ description="ARF API base URL"
112
+ )
113
+
114
+ # ===== Business Configuration =====
115
+ engineer_hourly_rate: float = Field(
116
+ default=150.0,
117
+ description="Engineer hourly rate in USD"
118
+ )
119
+
120
+ engineer_annual_cost: float = Field(
121
+ default=125000.0,
122
+ description="Engineer annual cost in USD"
123
+ )
124
+
125
+ default_savings_rate: float = Field(
126
+ default=0.82,
127
+ description="Default savings rate with ARF"
128
+ )
129
+
130
+ # ===== UI Configuration =====
131
+ auto_refresh_seconds: int = Field(
132
+ default=30,
133
+ description="Auto-refresh interval in seconds"
134
+ )
135
+
136
+ max_history_items: int = Field(
137
+ default=100,
138
+ description="Maximum history items to display"
139
+ )
140
+
141
+ # ===== Demo Configuration =====
142
+ default_scenario: str = Field(
143
+ default="Cache Miss Storm",
144
+ description="Default incident scenario"
145
+ )
146
+
147
+ scenario_config_path: str = Field(
148
+ default="config/scenarios",
149
+ description="Path to scenario configuration files"
150
+ )
151
+
152
+ # ===== Safety Configuration =====
153
+ default_safety_mode: str = Field(
154
+ default="advisory", # Changed from SafetyMode to string
155
+ description="Default safety mode: advisory, approval, autonomous"
156
+ )
157
+
158
+ require_approval: bool = Field(
159
+ default=True,
160
+ description="Require human approval for execution"
161
+ )
162
+
163
+ # ===== Validation =====
164
+ @validator("arf_api_key")
165
+ def validate_api_key(cls, v: Optional[str], values: Dict[str, Any]) -> Optional[str]:
166
+ if values.get("arf_mode") == "enterprise" and not v:
167
+ raise ValueError("ARF API key required for Enterprise mode")
168
+ return v
169
+
170
+ @validator("use_true_arf")
171
+ def validate_true_arf(cls, v: bool, values: Dict[str, Any]) -> bool:
172
+ if v and not values.get("arf_oss_installed"):
173
+ logger.warning("True ARF requested but OSS package not installed. Using mock mode.")
174
+ return False
175
+ return v
176
+
177
+ # ===== Installation Detection =====
178
+ @classmethod
179
+ def detect_installation(cls):
180
+ """Detect ARF package installation"""
181
+ results = {
182
+ "oss_installed": False,
183
+ "enterprise_installed": False,
184
+ "oss_version": None,
185
+ "enterprise_version": None
186
  }
187
 
188
+ # Check OSS package
189
+ try:
190
+ import agentic_reliability_framework as arf_oss
191
+ results["oss_installed"] = True
192
+ results["oss_version"] = getattr(arf_oss, '__version__', '3.3.7')
193
+ logger.info(f"βœ… ARF OSS v{results['oss_version']} detected")
194
+ except ImportError:
195
+ logger.info("⚠️ ARF OSS not installed - will use mock mode")
196
+
197
+ # Check Enterprise package
198
+ try:
199
+ import arf_enterprise
200
+ results["enterprise_installed"] = True
201
+ results["enterprise_version"] = getattr(arf_enterprise, '__version__', '1.0.2')
202
+ logger.info(f"βœ… ARF Enterprise v{results['enterprise_version']} detected")
203
+ except ImportError:
204
+ logger.info("⚠️ ARF Enterprise not installed - will use simulation")
205
+
206
+ return results
207
+
208
+ def get_installation_status(self) -> InstallationStatus:
209
+ """Get current installation status"""
210
+ if self.arf_oss_installed and self.arf_enterprise_installed:
211
+ return InstallationStatus.BOTH
212
+ elif self.arf_enterprise_installed:
213
+ return InstallationStatus.ENTERPRISE
214
+ elif self.arf_oss_installed:
215
+ return InstallationStatus.OSS_ONLY
216
+ else:
217
+ return InstallationStatus.NOT_INSTALLED
218
+
219
+ def get_installation_badges(self) -> Dict[str, Any]:
220
+ """Get badge information for UI display"""
221
+ if self.arf_oss_installed:
222
+ oss_badge = {
223
+ "text": f"βœ… ARF OSS v{self.arf_oss_version}",
224
+ "color": "#10b981",
225
+ "icon": "βœ…"
226
+ }
227
+ else:
228
+ oss_badge = {
229
+ "text": "⚠️ Mock ARF",
230
+ "color": "#f59e0b",
231
+ "icon": "⚠️"
232
+ }
233
+
234
+ if self.arf_enterprise_installed:
235
+ enterprise_badge = {
236
+ "text": f"πŸš€ Enterprise v{self.arf_enterprise_version}",
237
+ "color": "#8b5cf6",
238
+ "icon": "πŸš€"
239
+ }
240
+ else:
241
+ enterprise_badge = {
242
+ "text": "πŸ”’ Enterprise Required",
243
+ "color": "#64748b",
244
+ "icon": "πŸ”’"
245
+ }
246
+
247
+ return {
248
+ "oss": oss_badge,
249
+ "enterprise": enterprise_badge
250
  }
 
251
 
252
+ def get_installation_recommendations(self) -> List[str]:
253
+ """Get installation recommendations"""
254
+ recommendations = []
255
+
256
+ if not self.arf_oss_installed:
257
+ recommendations.append(
258
+ "Install real ARF OSS: `pip install agentic-reliability-framework==3.3.7`"
259
+ )
260
+
261
+ if not self.arf_enterprise_installed:
262
+ recommendations.append(
263
+ "Install ARF Enterprise: `pip install agentic-reliability-enterprise` (requires license)"
264
+ )
265
+
266
+ return recommendations
267
 
268
+ class Config:
269
+ env_file = ".env"
270
+ env_file_encoding = "utf-8"
271
+ case_sensitive = False
272
+
273
+
274
+ # Global settings instance with installation detection
275
+ try:
276
+ # First detect installation
277
+ installation_info = Settings.detect_installation()
278
+
279
+ # Create settings with installation info
280
+ settings = Settings(
281
+ arf_oss_installed=installation_info["oss_installed"],
282
+ arf_enterprise_installed=installation_info["enterprise_installed"],
283
+ arf_oss_version=installation_info["oss_version"],
284
+ arf_enterprise_version=installation_info["enterprise_version"],
285
+ )
286
+
287
+ # Log installation status
288
+ status = settings.get_installation_status()
289
+ logger.info(f"ARF Installation Status: {status.value}")
290
+
291
+ if status == InstallationStatus.NOT_INSTALLED:
292
+ logger.warning("No ARF packages installed. Demo will use mock mode.")
293
+ logger.warning("For real ARF experience, install: pip install agentic-reliability-framework==3.3.7")
294
+
295
+ except Exception as e:
296
+ logger.warning(f"Failed to load settings: {e}, using defaults")
297
+ settings = Settings(
298
+ arf_mode="demo",
299
+ use_true_arf=False,
300
+ arf_oss_installed=False,
301
+ arf_enterprise_installed=False,
302
+ engineer_hourly_rate=150.0,
303
+ engineer_annual_cost=125000.0,
304
+ default_savings_rate=0.82,
305
+ auto_refresh_seconds=30,
306
+ max_history_items=100,
307
+ default_scenario="Cache Miss Storm",
308
+ scenario_config_path="config/scenarios",
309
+ default_safety_mode="advisory",
310
+ require_approval=True
311
+ )
312
+
313
+
314
+ def get_settings() -> Settings:
315
+ """Get settings instance (singleton pattern)"""
316
+ return settings
317
+
318
+
319
+ def print_installation_status():
320
+ """Print installation status to console - SAFE VERSION"""
321
+ try:
322
+ s = get_settings()
323
+
324
+ print("=" * 70)
325
+ print("πŸš€ ARF Ultimate Investor Demo - Installation Status")
326
+ print("=" * 70)
327
+
328
+ print(f"πŸ“¦ ARF OSS: {'βœ… v' + s.arf_oss_version if s.arf_oss_installed else '⚠️ Not installed'}")
329
+ print(f"🏒 Enterprise: {'βœ… v' + s.arf_enterprise_version if s.arf_enterprise_installed else '⚠️ Not installed'}")
330
+
331
+ # Safe string access
332
+ print(f"🎯 Mode: {s.arf_mode.upper()}")
333
+ print(f"πŸ€– Using True ARF: {'βœ… Yes' if s.use_true_arf else '⚠️ Mock mode'}")
334
+
335
+ recommendations = s.get_installation_recommendations()
336
+ if recommendations:
337
+ print("\nπŸ’‘ Recommendations:")
338
+ for rec in recommendations:
339
+ print(f" β€’ {rec}")
340
+
341
+ print("=" * 70)
342
+
343
+ except Exception as e:
344
+ print(f"⚠️ Could not print installation status: {e}")