calebdevans commited on
Commit
75957dc
·
unverified ·
1 Parent(s): c1a6768

Add ZeroGPU support with model caching and monospace font

Browse files
Files changed (2) hide show
  1. app.py +54 -4
  2. requirements.txt +4 -1
app.py CHANGED
@@ -7,9 +7,43 @@ import tempfile
7
  from pathlib import Path
8
 
9
  import gradio as gr
 
10
 
11
  from cordon import AnalysisConfig, SemanticLogAnalyzer
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  # Load sample log file
14
  SAMPLE_LOG_PATH = Path(__file__).parent / "sample_apache.log"
15
  FALLBACK_LOG_PATH = Path(__file__).parent.parent / "examples" / "apache_sample.log"
@@ -29,7 +63,7 @@ def estimate_tokens(text: str) -> int:
29
  return len(text) // 4 if text else 0
30
 
31
 
32
- def analyze_logs(
33
  log_content: str,
34
  window_size: int,
35
  k_neighbors: int,
@@ -54,12 +88,14 @@ def analyze_logs(
54
  try:
55
  progress(0.1, desc="Configuring analyzer...")
56
 
 
 
57
  if mode == "Percentile":
58
  config = AnalysisConfig(
59
  window_size=window_size,
60
  k_neighbors=k_neighbors,
61
  anomaly_percentile=anomaly_percentile,
62
- device="cpu",
63
  )
64
  else:
65
  config = AnalysisConfig(
@@ -67,11 +103,11 @@ def analyze_logs(
67
  k_neighbors=k_neighbors,
68
  anomaly_range_min=range_min,
69
  anomaly_range_max=range_max,
70
- device="cpu",
71
  )
72
 
73
  progress(0.15, desc="Loading embedding model...")
74
- analyzer = SemanticLogAnalyzer(config)
75
 
76
  progress(0.25, desc="Segmenting log into windows...")
77
  # Small delay to show progress
@@ -105,6 +141,13 @@ def analyze_logs(
105
  temp_path.unlink(missing_ok=True)
106
 
107
 
 
 
 
 
 
 
 
108
  CUSTOM_CSS = """
109
  .main, .wrap, .contain, .gradio-container, .app {
110
  max-width: 100% !important;
@@ -112,6 +155,13 @@ CUSTOM_CSS = """
112
  padding-left: 2rem !important;
113
  padding-right: 2rem !important;
114
  }
 
 
 
 
 
 
 
115
  """
116
 
117
  THEME = gr.themes.Base(
 
7
  from pathlib import Path
8
 
9
  import gradio as gr
10
+ import torch
11
 
12
  from cordon import AnalysisConfig, SemanticLogAnalyzer
13
 
14
+ # ZeroGPU support with fallback for local development
15
+ try:
16
+ import spaces
17
+ ZEROGPU_AVAILABLE = True
18
+ except ImportError:
19
+ ZEROGPU_AVAILABLE = False
20
+
21
+ # Detect available device
22
+ def get_device() -> str:
23
+ """Detect best available device."""
24
+ if torch.cuda.is_available():
25
+ return "cuda"
26
+ elif torch.backends.mps.is_available():
27
+ return "mps"
28
+ return "cpu"
29
+
30
+ # Global model cache (keyed by model_name:device)
31
+ _analyzer_cache: dict[str, SemanticLogAnalyzer] = {}
32
+
33
+ def get_cached_analyzer(config: AnalysisConfig) -> SemanticLogAnalyzer:
34
+ """Get or create a cached analyzer instance.
35
+
36
+ Caches the analyzer to avoid repeated model loading.
37
+ The config is updated on the cached instance for each call.
38
+ """
39
+ cache_key = f"{config.model_name}:{config.device}"
40
+ if cache_key not in _analyzer_cache:
41
+ _analyzer_cache[cache_key] = SemanticLogAnalyzer(config)
42
+ else:
43
+ # Update config params (window_size, k_neighbors, etc.)
44
+ _analyzer_cache[cache_key].config = config
45
+ return _analyzer_cache[cache_key]
46
+
47
  # Load sample log file
48
  SAMPLE_LOG_PATH = Path(__file__).parent / "sample_apache.log"
49
  FALLBACK_LOG_PATH = Path(__file__).parent.parent / "examples" / "apache_sample.log"
 
63
  return len(text) // 4 if text else 0
64
 
65
 
66
+ def _analyze_logs_impl(
67
  log_content: str,
68
  window_size: int,
69
  k_neighbors: int,
 
88
  try:
89
  progress(0.1, desc="Configuring analyzer...")
90
 
91
+ device = get_device()
92
+
93
  if mode == "Percentile":
94
  config = AnalysisConfig(
95
  window_size=window_size,
96
  k_neighbors=k_neighbors,
97
  anomaly_percentile=anomaly_percentile,
98
+ device=device,
99
  )
100
  else:
101
  config = AnalysisConfig(
 
103
  k_neighbors=k_neighbors,
104
  anomaly_range_min=range_min,
105
  anomaly_range_max=range_max,
106
+ device=device,
107
  )
108
 
109
  progress(0.15, desc="Loading embedding model...")
110
+ analyzer = get_cached_analyzer(config)
111
 
112
  progress(0.25, desc="Segmenting log into windows...")
113
  # Small delay to show progress
 
141
  temp_path.unlink(missing_ok=True)
142
 
143
 
144
+ # Apply ZeroGPU decorator if available, otherwise use the function directly
145
+ if ZEROGPU_AVAILABLE:
146
+ analyze_logs = spaces.GPU(duration=120)(_analyze_logs_impl)
147
+ else:
148
+ analyze_logs = _analyze_logs_impl
149
+
150
+
151
  CUSTOM_CSS = """
152
  .main, .wrap, .contain, .gradio-container, .app {
153
  max-width: 100% !important;
 
155
  padding-left: 2rem !important;
156
  padding-right: 2rem !important;
157
  }
158
+
159
+ /* Monospace font for log input/output */
160
+ textarea {
161
+ font-family: "JetBrains Mono", "Fira Code", "SF Mono", "Cascadia Code", Menlo, Monaco, Consolas, "Liberation Mono", monospace !important;
162
+ font-size: 13px !important;
163
+ line-height: 1.5 !important;
164
+ }
165
  """
166
 
167
  THEME = gr.themes.Base(
requirements.txt CHANGED
@@ -1,5 +1,8 @@
1
  # Cordon package from PyPI
2
- cordon>=0.3.0
3
 
4
  # UI dependencies
5
  gradio>=4.0.0
 
 
 
 
1
  # Cordon package from PyPI
2
+ cordon>=0.3.1
3
 
4
  # UI dependencies
5
  gradio>=4.0.0
6
+
7
+ # HuggingFace Spaces (ZeroGPU support)
8
+ spaces