calebdevans commited on
Commit
06bb07f
·
unverified ·
1 Parent(s): f4c86fd

Fix ZeroGPU: use direct decorator pattern per HF docs

Browse files
Files changed (2) hide show
  1. README.md +0 -1
  2. app.py +13 -59
README.md CHANGED
@@ -8,7 +8,6 @@ sdk_version: 6.2.0
8
  app_file: app.py
9
  pinned: false
10
  license: apache-2.0
11
- hardware: zero-a10g
12
  short_description: Find anomalies in logs using AI. Paste logs, get insights.
13
  tags:
14
  - log-analysis
 
8
  app_file: app.py
9
  pinned: false
10
  license: apache-2.0
 
11
  short_description: Find anomalies in logs using AI. Paste logs, get insights.
12
  tags:
13
  - log-analysis
app.py CHANGED
@@ -1,49 +1,17 @@
1
  """
2
  Cordon - Semantic Anomaly Detection for Log Files
3
- HuggingFace Space Demo
4
  """
5
 
6
  import tempfile
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,7 +31,8 @@ def estimate_tokens(text: str) -> int:
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,
@@ -73,7 +42,11 @@ def _analyze_logs_impl(
73
  range_max: float,
74
  progress: gr.Progress = gr.Progress(),
75
  ) -> tuple[str, str]:
76
- """Analyze log content and return results."""
 
 
 
 
77
 
78
  if not log_content.strip():
79
  return "", "Anomalous Sections"
@@ -88,7 +61,8 @@ def _analyze_logs_impl(
88
  try:
89
  progress(0.1, desc="Configuring analyzer...")
90
 
91
- device = get_device()
 
92
  # Use larger batch size on GPU for better throughput
93
  batch_size = 128 if device == "cuda" else 32
94
 
@@ -111,25 +85,12 @@ def _analyze_logs_impl(
111
  )
112
 
113
  progress(0.15, desc="Loading embedding model...")
114
- analyzer = get_cached_analyzer(config)
115
-
116
- progress(0.25, desc="Segmenting log into windows...")
117
- # Small delay to show progress
118
- import time
119
- time.sleep(0.1)
120
 
121
- progress(0.4, desc="Generating embeddings...")
122
- time.sleep(0.1)
123
-
124
- progress(0.6, desc="Scoring anomalies...")
125
- time.sleep(0.1)
126
-
127
- progress(0.75, desc="Analyzing patterns...")
128
  result = analyzer.analyze_file_detailed(temp_path)
129
 
130
  progress(0.9, desc="Formatting output...")
131
- time.sleep(0.05)
132
-
133
  progress(1.0, desc="Complete!")
134
 
135
  # Calculate token counts
@@ -145,13 +106,6 @@ def _analyze_logs_impl(
145
  temp_path.unlink(missing_ok=True)
146
 
147
 
148
- # Apply ZeroGPU decorator if available, otherwise use the function directly
149
- if ZEROGPU_AVAILABLE:
150
- analyze_logs = spaces.GPU(duration=120)(_analyze_logs_impl)
151
- else:
152
- analyze_logs = _analyze_logs_impl
153
-
154
-
155
  CUSTOM_CSS = """
156
  .main, .wrap, .contain, .gradio-container, .app {
157
  max-width: 100% !important;
 
1
  """
2
  Cordon - Semantic Anomaly Detection for Log Files
3
+ HuggingFace Space Demo (ZeroGPU)
4
  """
5
 
6
  import tempfile
7
  from pathlib import Path
8
 
9
  import gradio as gr
10
+ import spaces
11
  import torch
12
 
13
  from cordon import AnalysisConfig, SemanticLogAnalyzer
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  # Load sample log file
16
  SAMPLE_LOG_PATH = Path(__file__).parent / "sample_apache.log"
17
  FALLBACK_LOG_PATH = Path(__file__).parent.parent / "examples" / "apache_sample.log"
 
31
  return len(text) // 4 if text else 0
32
 
33
 
34
+ @spaces.GPU(duration=120)
35
+ def analyze_logs(
36
  log_content: str,
37
  window_size: int,
38
  k_neighbors: int,
 
42
  range_max: float,
43
  progress: gr.Progress = gr.Progress(),
44
  ) -> tuple[str, str]:
45
+ """Analyze log content and return results.
46
+
47
+ This function is decorated with @spaces.GPU to run on ZeroGPU.
48
+ The GPU is allocated when this function is called.
49
+ """
50
 
51
  if not log_content.strip():
52
  return "", "Anomalous Sections"
 
61
  try:
62
  progress(0.1, desc="Configuring analyzer...")
63
 
64
+ # Check if CUDA is available (should be True on ZeroGPU)
65
+ device = "cuda" if torch.cuda.is_available() else "cpu"
66
  # Use larger batch size on GPU for better throughput
67
  batch_size = 128 if device == "cuda" else 32
68
 
 
85
  )
86
 
87
  progress(0.15, desc="Loading embedding model...")
88
+ analyzer = SemanticLogAnalyzer(config)
 
 
 
 
 
89
 
90
+ progress(0.4, desc="Analyzing patterns...")
 
 
 
 
 
 
91
  result = analyzer.analyze_file_detailed(temp_path)
92
 
93
  progress(0.9, desc="Formatting output...")
 
 
94
  progress(1.0, desc="Complete!")
95
 
96
  # Calculate token counts
 
106
  temp_path.unlink(missing_ok=True)
107
 
108
 
 
 
 
 
 
 
 
109
  CUSTOM_CSS = """
110
  .main, .wrap, .contain, .gradio-container, .app {
111
  max-width: 100% !important;