NOT-OMEGA commited on
Commit
4ad7bb3
Β·
verified Β·
1 Parent(s): ada2121

Update app_gradio.py

Browse files
Files changed (1) hide show
  1. app_gradio.py +95 -503
app_gradio.py CHANGED
@@ -1,17 +1,17 @@
1
  """
2
  Log Classification System β€” HuggingFace Spaces
3
- Ultra-modern 3D UI with custom CSS
4
  """
5
  from __future__ import annotations
6
  import io
7
  import time
8
  import pandas as pd
9
- import numpy as np # <-- Added numpy for percentiles
10
  import gradio as gr
11
  from classify import classify_log, classify_csv
12
  from processor_bert import preload_models
13
 
14
- # ── Preload models in background at startup ─────────────────
15
  preload_models()
16
 
17
  SOURCES = [
@@ -32,547 +32,139 @@ EXAMPLE_LOGS = [
32
  ["BillingSystem", "GET /v2/servers/detail HTTP/1.1 status: 200 len: 1583 time: 0.19"],
33
  ["AnalyticsEngine", "System crashed due to disk I/O failure on node-3"],
34
  ["LegacyCRM", "Case escalation for ticket ID 7324 failed β€” support agent is no longer active."],
35
- ["LegacyCRM", "The 'BulkEmailSender' feature will be deprecated in v5.0. Use 'EmailCampaignManager'."],
36
  ]
37
 
38
- # ── Custom CSS β€” 3D Modern Dark Theme ──────────────────────────────────────
39
  CUSTOM_CSS = """
40
- @import url('https://fonts.googleapis.com/css2?family=Rajdhani:wght@400;500;600;700&family=Share+Tech+Mono&family=Exo+2:wght@300;400;600;700&display=swap');
41
-
42
  :root {
43
  --bg-primary: #050810;
44
- --bg-secondary: #0a0f1e;
45
- --bg-card: #0d1425;
46
- --bg-card-hover: #111a30;
47
  --accent-cyan: #00d4ff;
48
- --accent-blue: #0066ff;
49
- --accent-purple: #7c3aed;
50
- --accent-green: #00ff88;
51
- --accent-orange: #ff6b00;
52
  --text-primary: #e2e8f0;
53
- --text-secondary: #94a3b8;
54
- --text-muted: #475569;
55
- --border-glow: rgba(0, 212, 255, 0.3);
56
- --shadow-3d: 0 20px 60px rgba(0, 0, 0, 0.8), 0 0 40px rgba(0, 102, 255, 0.15);
57
- --glow-cyan: 0 0 20px rgba(0, 212, 255, 0.4), 0 0 40px rgba(0, 212, 255, 0.2);
58
- --glow-blue: 0 0 20px rgba(0, 102, 255, 0.4);
59
- }
60
-
61
- /* ── Base ── */
62
- body, .gradio-container {
63
- background: var(--bg-primary) !important;
64
- font-family: 'Exo 2', sans-serif !important;
65
- color: var(--text-primary) !important;
66
- }
67
-
68
- .gradio-container {
69
- background:
70
- radial-gradient(ellipse at 20% 20%, rgba(0, 102, 255, 0.08) 0%, transparent 50%),
71
- radial-gradient(ellipse at 80% 80%, rgba(124, 58, 237, 0.08) 0%, transparent 50%),
72
- radial-gradient(ellipse at 50% 50%, rgba(0, 212, 255, 0.03) 0%, transparent 70%),
73
- var(--bg-primary) !important;
74
- min-height: 100vh;
75
- }
76
-
77
- /* ── Header ── */
78
- .main-header {
79
- text-align: center;
80
- padding: 48px 24px 32px;
81
- position: relative;
82
- }
83
-
84
- .main-header::before {
85
- content: '';
86
- position: absolute;
87
- top: 0; left: 50%;
88
- transform: translateX(-50%);
89
- width: 600px; height: 2px;
90
- background: linear-gradient(90deg, transparent, var(--accent-cyan), var(--accent-blue), transparent);
91
- box-shadow: var(--glow-cyan);
92
- }
93
-
94
- /* ── Tab Navigation ── */
95
- .tab-nav {
96
- background: rgba(13, 20, 37, 0.8) !important;
97
- border: 1px solid rgba(0, 212, 255, 0.15) !important;
98
- border-radius: 16px !important;
99
- padding: 6px !important;
100
- backdrop-filter: blur(20px) !important;
101
- box-shadow: var(--shadow-3d) !important;
102
- }
103
-
104
- .tab-nav button {
105
- font-family: 'Rajdhani', sans-serif !important;
106
- font-weight: 600 !important;
107
- font-size: 14px !important;
108
- letter-spacing: 1.5px !important;
109
- text-transform: uppercase !important;
110
- color: var(--text-secondary) !important;
111
- background: transparent !important;
112
- border: none !important;
113
- border-radius: 10px !important;
114
- padding: 12px 24px !important;
115
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
116
- }
117
-
118
- .tab-nav button.selected {
119
- color: var(--accent-cyan) !important;
120
- background: linear-gradient(135deg, rgba(0, 212, 255, 0.1), rgba(0, 102, 255, 0.1)) !important;
121
- box-shadow: 0 0 20px rgba(0, 212, 255, 0.2), inset 0 1px 0 rgba(0, 212, 255, 0.3) !important;
122
- border: 1px solid rgba(0, 212, 255, 0.3) !important;
123
- }
124
-
125
- /* ── Cards / Blocks ── */
126
- .gradio-group, .gr-group {
127
- background: var(--bg-card) !important;
128
- border: 1px solid rgba(0, 212, 255, 0.1) !important;
129
- border-radius: 20px !important;
130
- box-shadow: var(--shadow-3d), inset 0 1px 0 rgba(255,255,255,0.03) !important;
131
- transition: all 0.4s ease !important;
132
- transform: perspective(1000px) rotateX(0deg);
133
- position: relative;
134
- overflow: hidden;
135
- }
136
-
137
- .gradio-group::before {
138
- content: '';
139
- position: absolute;
140
- top: 0; left: 0; right: 0;
141
- height: 1px;
142
- background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.5), transparent);
143
- }
144
-
145
- .gradio-group:hover {
146
- border-color: rgba(0, 212, 255, 0.25) !important;
147
- box-shadow: var(--shadow-3d), var(--glow-cyan) !important;
148
- transform: perspective(1000px) translateY(-4px) !important;
149
- }
150
-
151
- /* ── Labels ── */
152
- label span, .gr-label {
153
- font-family: 'Rajdhani', sans-serif !important;
154
- font-weight: 600 !important;
155
- letter-spacing: 1.5px !important;
156
- text-transform: uppercase !important;
157
- font-size: 11px !important;
158
- color: var(--accent-cyan) !important;
159
- opacity: 0.85;
160
- }
161
-
162
- /* ── Inputs ── */
163
- input, textarea, select, .gr-input {
164
- background: rgba(5, 8, 16, 0.8) !important;
165
- border: 1px solid rgba(0, 212, 255, 0.15) !important;
166
- border-radius: 12px !important;
167
- color: var(--text-primary) !important;
168
- font-family: 'Share Tech Mono', monospace !important;
169
- font-size: 13px !important;
170
- transition: all 0.3s ease !important;
171
- padding: 12px 16px !important;
172
- }
173
-
174
- input:focus, textarea:focus {
175
- border-color: var(--accent-cyan) !important;
176
- box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.1), var(--glow-cyan) !important;
177
- outline: none !important;
178
- background: rgba(0, 212, 255, 0.03) !important;
179
- }
180
-
181
- /* ── Dropdown ── */
182
- .gr-dropdown select, .gradio-dropdown {
183
- background: rgba(5, 8, 16, 0.9) !important;
184
- border: 1px solid rgba(0, 212, 255, 0.2) !important;
185
- border-radius: 12px !important;
186
- color: var(--accent-cyan) !important;
187
- font-family: 'Rajdhani', sans-serif !important;
188
- font-weight: 600 !important;
189
  }
190
-
191
- /* ── Primary Button ── */
192
- button.primary, .gr-button-primary, button[variant="primary"] {
193
- font-family: 'Rajdhani', sans-serif !important;
194
- font-weight: 700 !important;
195
- font-size: 15px !important;
196
- letter-spacing: 2px !important;
197
- text-transform: uppercase !important;
198
- background: linear-gradient(135deg, #0066ff 0%, #00d4ff 50%, #0066ff 100%) !important;
199
- background-size: 200% 200% !important;
200
- border: none !important;
201
- border-radius: 12px !important;
202
- padding: 14px 32px !important;
203
- color: #fff !important;
204
- box-shadow:
205
- 0 8px 32px rgba(0, 102, 255, 0.4),
206
- 0 2px 8px rgba(0, 0, 0, 0.5),
207
- inset 0 1px 0 rgba(255,255,255,0.2) !important;
208
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
209
- animation: gradientShift 3s ease infinite !important;
210
- position: relative !important;
211
- overflow: hidden !important;
212
- }
213
-
214
- button.primary::before {
215
- content: '';
216
- position: absolute;
217
- top: -50%; left: -60%;
218
- width: 40%; height: 200%;
219
- background: rgba(255,255,255,0.1);
220
- transform: skewX(-20deg);
221
- transition: left 0.6s ease;
222
- }
223
-
224
- button.primary:hover::before {
225
- left: 120%;
226
- }
227
-
228
- button.primary:hover {
229
- transform: translateY(-3px) scale(1.02) !important;
230
- box-shadow:
231
- 0 16px 48px rgba(0, 102, 255, 0.5),
232
- 0 0 30px rgba(0, 212, 255, 0.3),
233
- inset 0 1px 0 rgba(255,255,255,0.3) !important;
234
- }
235
-
236
- button.primary:active {
237
- transform: translateY(0px) scale(0.98) !important;
238
- }
239
-
240
- @keyframes gradientShift {
241
- 0%, 100% { background-position: 0% 50%; }
242
- 50% { background-position: 100% 50%; }
243
- }
244
-
245
- /* ── Output Textboxes β€” 3D Result Cards ── */
246
- .output-card input, .output-card textarea {
247
- background: linear-gradient(135deg, rgba(0, 212, 255, 0.05), rgba(0, 102, 255, 0.05)) !important;
248
- border: 1px solid rgba(0, 212, 255, 0.2) !important;
249
- border-radius: 14px !important;
250
- font-family: 'Share Tech Mono', monospace !important;
251
- font-size: 16px !important;
252
  font-weight: bold !important;
253
- color: var(--accent-cyan) !important;
254
- text-align: center !important;
255
- box-shadow: inset 0 2px 8px rgba(0,0,0,0.3), 0 0 20px rgba(0, 212, 255, 0.1) !important;
256
- }
257
-
258
- /* ── Table / DataFrame ── */
259
- table {
260
- border-collapse: separate !important;
261
- border-spacing: 0 4px !important;
262
- font-family: 'Share Tech Mono', monospace !important;
263
- font-size: 12px !important;
264
- }
265
-
266
- th {
267
- background: rgba(0, 102, 255, 0.2) !important;
268
- color: var(--accent-cyan) !important;
269
- font-family: 'Rajdhani', sans-serif !important;
270
- letter-spacing: 1.5px !important;
271
- text-transform: uppercase !important;
272
- font-size: 11px !important;
273
- padding: 10px 16px !important;
274
- border: none !important;
275
- }
276
-
277
- td {
278
- background: rgba(13, 20, 37, 0.6) !important;
279
- color: var(--text-secondary) !important;
280
- padding: 8px 16px !important;
281
- border: none !important;
282
- border-top: 1px solid rgba(0, 212, 255, 0.05) !important;
283
- transition: background 0.2s ease !important;
284
- }
285
-
286
- tr:hover td {
287
- background: rgba(0, 212, 255, 0.05) !important;
288
- color: var(--text-primary) !important;
289
- }
290
-
291
- /* ── Markdown ── */
292
- .prose, .markdown {
293
- color: var(--text-secondary) !important;
294
- font-family: 'Exo 2', sans-serif !important;
295
- }
296
-
297
- .prose h1, .markdown h1 {
298
- font-family: 'Rajdhani', sans-serif !important;
299
- font-size: 3rem !important;
300
- font-weight: 700 !important;
301
- letter-spacing: 3px !important;
302
- text-transform: uppercase !important;
303
- background: linear-gradient(135deg, #ffffff 0%, var(--accent-cyan) 40%, var(--accent-blue) 100%) !important;
304
- -webkit-background-clip: text !important;
305
- -webkit-text-fill-color: transparent !important;
306
- background-clip: text !important;
307
- filter: drop-shadow(0 0 30px rgba(0, 212, 255, 0.3)) !important;
308
- margin-bottom: 8px !important;
309
- }
310
-
311
- .prose h2, .markdown h2 {
312
- font-family: 'Rajdhani', sans-serif !important;
313
- font-size: 1.4rem !important;
314
- font-weight: 600 !important;
315
- letter-spacing: 2px !important;
316
- color: var(--accent-cyan) !important;
317
- text-transform: uppercase !important;
318
- border-bottom: 1px solid rgba(0, 212, 255, 0.2) !important;
319
- padding-bottom: 8px !important;
320
- }
321
-
322
- .prose p, .markdown p {
323
- color: var(--text-secondary) !important;
324
- line-height: 1.7 !important;
325
- font-size: 14px !important;
326
  }
327
-
328
- .prose strong, .markdown strong {
329
- color: var(--accent-cyan) !important;
330
- }
331
-
332
- /* ── Code blocks ── */
333
- code, pre {
334
- font-family: 'Share Tech Mono', monospace !important;
335
- background: rgba(0, 212, 255, 0.05) !important;
336
- border: 1px solid rgba(0, 212, 255, 0.15) !important;
337
- border-radius: 8px !important;
338
- color: var(--accent-cyan) !important;
339
- font-size: 12px !important;
340
- }
341
-
342
- /* ── Examples Table ── */
343
- .examples {
344
- background: var(--bg-card) !important;
345
- border: 1px solid rgba(0, 212, 255, 0.1) !important;
346
- border-radius: 14px !important;
347
- overflow: hidden !important;
348
- }
349
-
350
- .examples table th {
351
- background: rgba(0, 102, 255, 0.15) !important;
352
- }
353
-
354
- /* ── File Upload ── */
355
- .gr-file {
356
- background: rgba(5, 8, 16, 0.8) !important;
357
- border: 2px dashed rgba(0, 212, 255, 0.25) !important;
358
- border-radius: 16px !important;
359
- transition: all 0.3s ease !important;
360
- }
361
-
362
- .gr-file:hover {
363
- border-color: var(--accent-cyan) !important;
364
- background: rgba(0, 212, 255, 0.03) !important;
365
- box-shadow: var(--glow-cyan) !important;
366
- }
367
-
368
- /* ── Scrollbar ── */
369
- ::-webkit-scrollbar { width: 6px; height: 6px; }
370
- ::-webkit-scrollbar-track { background: var(--bg-secondary); }
371
- ::-webkit-scrollbar-thumb {
372
- background: linear-gradient(var(--accent-blue), var(--accent-cyan));
373
- border-radius: 3px;
374
- }
375
-
376
- /* ── Pulsing accent line ── */
377
- @keyframes pulse-glow {
378
- 0%, 100% { opacity: 0.4; box-shadow: 0 0 10px rgba(0,212,255,0.3); }
379
- 50% { opacity: 1; box-shadow: 0 0 30px rgba(0,212,255,0.8); }
380
- }
381
-
382
- /* ── Tier badge colors ── */
383
- .tier-regex { color: #00ff88 !important; }
384
- .tier-bert { color: #00d4ff !important; }
385
- .tier-llm { color: #ffd700 !important; }
386
  """
387
 
388
  # ── Functions ───────────────────────────────────────────────────────────────
 
389
  def classify_single(source: str, log_message: str):
 
390
  from processor_bert import _model_ready
391
- if not log_message.strip():
392
- return "β€”", "β€”", "β€”", "β€”"
 
 
393
  if not _model_ready:
394
- return "⏳ Model loading...", "Please wait ~60s", "β€”", "β€”"
395
- t0 = time.perf_counter()
396
- result = classify_log(source, log_message)
397
- latency_ms = (time.perf_counter() - t0) * 1000
398
- label = result["label"]
399
- tier = result["tier"]
400
- confidence = f"{result['confidence']:.1%}" if result["confidence"] is not None else "N/A"
401
- icon = TIER_COLORS.get(tier, "βšͺ")
402
- return label, f"{icon} {tier}", confidence, f"{latency_ms:.1f} ms"
403
-
 
 
 
 
 
404
 
405
- def classify_batch(file):
406
  if file is None:
407
  return None, "⚠️ Please upload a CSV file."
408
-
409
- t0 = time.perf_counter() # Start Total Timer
 
410
 
411
  try:
 
412
  output_path, df = classify_csv(file.name, "/tmp/classified_output.csv")
413
- except ValueError as e:
414
- return None, f"⚠️ {e}"
415
- except Exception as e:
416
- return None, f"❌ Error: {e}"
417
 
418
- total_time_sec = time.perf_counter() - t0 # End Total Timer
419
- total = len(df)
420
-
421
- tier_counts = df["tier_used"].value_counts().to_dict()
422
- label_counts = df["predicted_label"].value_counts().to_dict()
423
-
424
- tier_lines = "\n".join(f" {TIER_COLORS.get(k,'βšͺ')} {k}: {v} ({v/total:.0%})" for k, v in tier_counts.items())
425
- label_lines = "\n".join(f" β€’ {k}: {v}" for k, v in label_counts.items())
426
-
427
- # Calculate Latencies
428
- if "latency_ms" in df.columns and not df["latency_ms"].empty:
429
- latencies = df["latency_ms"].dropna()
430
- p50 = np.percentile(latencies, 50)
431
- p95 = np.percentile(latencies, 95)
432
- p99 = np.percentile(latencies, 99)
433
- latency_stats = (
434
- f"⏱️ Performance Metrics:\n"
435
- f" β€’ Total Time: {total_time_sec:.2f} s\n"
436
- f" β€’ P50 Latency: {p50:.1f} ms\n"
437
- f" β€’ P95 Latency: {p95:.1f} ms\n"
438
- f" β€’ P99 Latency: {p99:.1f} ms"
439
- )
440
- else:
441
- latency_stats = (
442
- f"⏱️ Performance Metrics:\n"
443
- f" β€’ Total Time: {total_time_sec:.2f} s\n"
444
- f" β€’ (Latency stats unavailable: 'latency_ms' not found in output)"
445
  )
446
-
447
- stats = (
448
- f"βœ… Classified {total} logs\n\n"
449
- f"πŸ“Š Tier breakdown:\n{tier_lines}\n\n"
450
- f"🏷️ Label distribution:\n{label_lines}\n\n"
451
- f"{latency_stats}"
452
- )
453
- return output_path, stats
454
 
 
 
 
 
455
 
456
- # ── UI ───────────────────────────────────────────────────────────────────────
457
  THEME = gr.themes.Base(
458
  primary_hue="blue",
459
- secondary_hue="cyan",
460
  neutral_hue="slate",
461
- font=[gr.themes.GoogleFont("Exo 2"), "sans-serif"],
462
- font_mono=[gr.themes.GoogleFont("Share Tech Mono"), "monospace"],
463
  ).set(
464
- body_background_fill="#050810",
465
- body_text_color="#e2e8f0",
466
  block_background_fill="#0d1425",
467
- block_border_color="rgba(0,212,255,0.15)",
468
  block_label_text_color="#00d4ff",
469
  input_background_fill="#050810",
470
- input_border_color="rgba(0,212,255,0.2)",
471
- button_primary_background_fill="linear-gradient(135deg, #0066ff, #00d4ff)",
472
- button_primary_text_color="#ffffff",
473
- border_color_accent="#00d4ff",
474
- color_accent_soft="rgba(0,212,255,0.1)",
475
  )
476
 
477
- with gr.Blocks(title="LOG CLASSIFICATION SYSTEM") as demo:
478
-
479
- gr.Markdown("""
480
- # πŸ” LOG CLASSIFICATION SYSTEM
481
- **3-tier hybrid pipeline** β€” 🟒 Regex Β· πŸ”΅ BERT + ML Β· 🟑 LLM
482
- *Enterprise-grade log monitoring at production scale*
483
- """)
484
-
485
  with gr.Tabs():
486
-
487
- # ── Tab 1: Single Log ─────────────────────────────────────────────
488
- with gr.Tab("⚑ SINGLE LOG"):
489
  with gr.Row():
490
  with gr.Column(scale=1):
491
- source_input = gr.Dropdown(
492
- choices=SOURCES,
493
- value="ModernCRM",
494
- label="SOURCE SYSTEM",
495
- )
496
  with gr.Column(scale=3):
497
- log_input = gr.Textbox(
498
- label="LOG MESSAGE",
499
- placeholder="Paste a log message here...",
500
- lines=3,
501
- )
502
-
503
- classify_btn = gr.Button("β–Ά CLASSIFY LOG", variant="primary", size="lg")
504
-
505
  with gr.Row():
506
- label_out = gr.Textbox(label="🏷️ PREDICTED LABEL", interactive=False)
507
- tier_out = gr.Textbox(label="βš™οΈ TIER USED", interactive=False)
508
- confidence_out = gr.Textbox(label="πŸ“ˆ CONFIDENCE", interactive=False)
509
- latency_out = gr.Textbox(label="⏱️ LATENCY", interactive=False)
510
-
511
- classify_btn.click(
512
- fn=classify_single,
513
- inputs=[source_input, log_input],
514
- outputs=[label_out, tier_out, confidence_out, latency_out],
515
- )
516
-
517
- gr.Examples(
518
- examples=EXAMPLE_LOGS,
519
- inputs=[source_input, log_input],
520
- label="πŸ“‹ EXAMPLE LOGS β€” click to try",
521
- )
522
-
523
- # ── Tab 2: Batch CSV ──────────────────────────────────────────────
524
- with gr.Tab("πŸ“¦ BATCH CSV"):
525
- gr.Markdown("""
526
- ### Bulk Classification
527
- Upload a CSV with columns: **`source`**, **`log_message`** Output includes: `predicted_label`, `tier_used`, `confidence`, `latency_ms`
528
- """)
529
  with gr.Row():
530
  with gr.Column():
531
- csv_input = gr.File(label="πŸ“‚ UPLOAD CSV", file_types=[".csv"])
532
- batch_btn = gr.Button("β–Ά CLASSIFY ALL", variant="primary")
533
  with gr.Column():
534
- csv_output = gr.File(label="πŸ“₯ DOWNLOAD RESULTS")
535
- # Increased lines to 16 to properly fit the latency metrics
536
- stats_out = gr.Textbox(label="πŸ“Š STATISTICS", lines=16, interactive=False)
537
-
538
- batch_btn.click(
539
- fn=classify_batch,
540
- inputs=[csv_input],
541
- outputs=[csv_output, stats_out],
542
- )
543
-
544
- gr.Markdown("""
545
- **Sample CSV format:**
546
- """)
547
-
548
- # ── Tab 3: Architecture ───────────────────────────────────────────
549
- with gr.Tab("πŸ—οΈ ARCHITECTURE"):
550
- gr.Markdown("""
551
- ## 3-Tier Hybrid Pipeline
552
-
553
- | Tier | Method | Coverage | Latency | Trigger |
554
- |------|--------|----------|---------|---------|
555
- | 🟒 **Regex** | Python `re` patterns | ~21% | < 1ms | Fixed patterns |
556
- | πŸ”΅ **BERT** | `all-MiniLM-L6-v2` + LogReg | ~79% | 20–80ms | High-volume categories |
557
- | 🟑 **LLM** | HuggingFace Inference API | ~0.3% | 500–2000ms | LegacyCRM + rare patterns |
558
-
559
- ## Model Performance
560
- - **Training data**: 2,410 synthetic enterprise logs
561
- - **Confidence threshold**: 0.5 (below β†’ escalate to LLM)
562
- - **Source-aware routing**: `LegacyCRM` β†’ LLM directly
563
-
564
- ## Environment Variables
565
- | Secret | Purpose |
566
- |--------|---------|
567
- | `HF_TOKEN` | LLM inference for LegacyCRM logs |
568
- """)
569
-
570
- # Seedha launch karein, bina if __name__ == "__main__": ke
571
- #demo.launch(server_name="0.0.0.0", server_port=7860, theme=THEME, css=CUSTOM_CSS)
572
- # .queue() is mandatory for production level responsiveness
573
- demo.queue(default_concurrency_limit=5).launch(
574
- server_name="0.0.0.0",
575
- server_port=7860,
576
- theme=THEME,
577
- css=CUSTOM_CSS
578
  )
 
1
  """
2
  Log Classification System β€” HuggingFace Spaces
3
+ Optimized for Stability & Responsiveness
4
  """
5
  from __future__ import annotations
6
  import io
7
  import time
8
  import pandas as pd
9
+ import numpy as np
10
  import gradio as gr
11
  from classify import classify_log, classify_csv
12
  from processor_bert import preload_models
13
 
14
+ # ── Preload models at startup ─────────────────
15
  preload_models()
16
 
17
  SOURCES = [
 
32
  ["BillingSystem", "GET /v2/servers/detail HTTP/1.1 status: 200 len: 1583 time: 0.19"],
33
  ["AnalyticsEngine", "System crashed due to disk I/O failure on node-3"],
34
  ["LegacyCRM", "Case escalation for ticket ID 7324 failed β€” support agent is no longer active."],
 
35
  ]
36
 
37
+ # ── CSS (Cleaned up for Performance) ──
38
  CUSTOM_CSS = """
39
+ @import url('https://fonts.googleapis.com/css2?family=Rajdhani:wght@600&family=Share+Tech+Mono&family=Exo+2:wght@400;600&display=swap');
 
40
  :root {
41
  --bg-primary: #050810;
 
 
 
42
  --accent-cyan: #00d4ff;
 
 
 
 
43
  --text-primary: #e2e8f0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  }
45
+ body, .gradio-container { background: var(--bg-primary) !important; font-family: 'Exo 2', sans-serif !important; }
46
+ .gradio-group { border: 1px solid rgba(0, 212, 255, 0.2) !important; border-radius: 15px !important; transition: 0.3s; }
47
+ .gradio-group:hover { border-color: var(--accent-cyan) !important; box-shadow: 0 0 15px rgba(0, 212, 255, 0.2); }
48
+ button.primary {
49
+ background: linear-gradient(135deg, #0066ff, #00d4ff) !important;
50
+ border: none !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  font-weight: bold !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  """
54
 
55
  # ── Functions ───────────────────────────────────────────────────────────────
56
+
57
  def classify_single(source: str, log_message: str):
58
+ # Dynamic import to check model status
59
  from processor_bert import _model_ready
60
+
61
+ if not log_message or not log_message.strip():
62
+ return "Empty Input", "β€”", "β€”", "0 ms"
63
+
64
  if not _model_ready:
65
+ return "⏳ Models Loading...", "Please wait ~30s", "0%", "β€”"
66
+
67
+ try:
68
+ t0 = time.perf_counter()
69
+ result = classify_log(source, log_message)
70
+ latency = (time.perf_counter() - t0) * 1000
71
+
72
+ label = result.get("label", "Unknown")
73
+ tier = result.get("tier", "N/A")
74
+ conf = f"{result.get('confidence', 0):.1%}"
75
+ icon = TIER_COLORS.get(tier, "βšͺ")
76
+
77
+ return label, f"{icon} {tier}", conf, f"{latency:.1f} ms"
78
+ except Exception as e:
79
+ return f"Error: {str(e)}", "❌ Fail", "0%", "0 ms"
80
 
81
+ def classify_batch(file, progress=gr.Progress(track_tqdm=True)):
82
  if file is None:
83
  return None, "⚠️ Please upload a CSV file."
84
+
85
+ progress(0, desc="Starting Classification...")
86
+ t0 = time.perf_counter()
87
 
88
  try:
89
+ # Note: If classify_csv is slow, we wrap it in progress feedback
90
  output_path, df = classify_csv(file.name, "/tmp/classified_output.csv")
 
 
 
 
91
 
92
+ progress(0.8, desc="Generating Statistics...")
93
+ total = len(df)
94
+ tier_counts = df["tier_used"].value_counts().to_dict()
95
+ label_counts = df["predicted_label"].value_counts().to_dict()
96
+
97
+ # Stats Formatting
98
+ tier_info = "\n".join([f" {TIER_COLORS.get(k,'βšͺ')} {k}: {v}" for k,v in tier_counts.items()])
99
+ label_info = "\n".join([f" β€’ {k}: {v}" for k,v in label_counts.items()])
100
+
101
+ total_time = time.perf_counter() - t0
102
+ stats = (
103
+ f"βœ… PROCESSED {total} LOGS\n"
104
+ f"⏱️ TOTAL TIME: {total_time:.2f}s\n\n"
105
+ f"πŸ“Š TIER BREAKDOWN:\n{tier_info}\n\n"
106
+ f"🏷️ LABEL DISTRIBUTION:\n{label_info}"
 
 
 
 
 
 
 
 
 
 
 
 
107
  )
108
+
109
+ progress(1.0, desc="Done!")
110
+ return output_path, stats
 
 
 
 
 
111
 
112
+ except Exception as e:
113
+ return None, f"❌ Critical Error: {str(e)}"
114
+
115
+ # ── UI Construction ──────────────────────────────────────────────────────────
116
 
 
117
  THEME = gr.themes.Base(
118
  primary_hue="blue",
 
119
  neutral_hue="slate",
120
+ font=[gr.themes.GoogleFont("Exo 2")],
 
121
  ).set(
 
 
122
  block_background_fill="#0d1425",
 
123
  block_label_text_color="#00d4ff",
124
  input_background_fill="#050810",
 
 
 
 
 
125
  )
126
 
127
+ with gr.Blocks(theme=THEME, css=CUSTOM_CSS, title="Log AI Engine") as demo:
128
+ gr.Markdown("# πŸ” LOG CLASSIFICATION ENGINE")
129
+
 
 
 
 
 
130
  with gr.Tabs():
131
+ # SINGLE LOG TAB
132
+ with gr.Tab("⚑ REAL-TIME ANALYZER"):
 
133
  with gr.Row():
134
  with gr.Column(scale=1):
135
+ src = gr.Dropdown(choices=SOURCES, value="ModernCRM", label="LOG SOURCE")
 
 
 
 
136
  with gr.Column(scale=3):
137
+ msg = gr.Textbox(label="LOG MESSAGE", placeholder="Enter raw log string...", lines=3)
138
+
139
+ run_btn = gr.Button("ANALYZE LOG", variant="primary")
140
+
 
 
 
 
141
  with gr.Row():
142
+ out_lbl = gr.Textbox(label="PREDICTED CATEGORY")
143
+ out_tier = gr.Textbox(label="TIER")
144
+ out_conf = gr.Textbox(label="CONFIDENCE")
145
+ out_lat = gr.Textbox(label="LATENCY")
146
+
147
+ run_btn.click(classify_single, [src, msg], [out_lbl, out_tier, out_conf, out_lat])
148
+ gr.Examples(examples=EXAMPLE_LOGS, inputs=[src, msg])
149
+
150
+ # BATCH TAB
151
+ with gr.Tab("πŸ“¦ BATCH PROCESSING"):
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  with gr.Row():
153
  with gr.Column():
154
+ file_in = gr.File(label="Upload CSV (source, log_message)")
155
+ batch_btn = gr.Button("START BATCH PROCESS", variant="primary")
156
  with gr.Column():
157
+ file_out = gr.File(label="Download Classified CSV")
158
+ stats_out = gr.Textbox(label="EXECUTION SUMMARY", lines=12)
159
+
160
+ batch_btn.click(classify_batch, inputs=[file_in], outputs=[file_out, stats_out])
161
+
162
+ gr.Markdown("--- \n *System Status: Active | Tiers: Regex -> BERT -> LLM*")
163
+
164
+ # ── Launch Logic ──
165
+ # Concurrency limit ko 2 par rakha hai taaki 2 log se zyada ek sath process na hon (stability)
166
+ demo.queue(default_concurrency_limit=2).launch(
167
+ server_name="0.0.0.0",
168
+ server_port=7860,
169
+ show_api=False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  )