Spaces:
Sleeping
Sleeping
| """ | |
| WaveGuard Demo Space -- Hugging Face | |
| ===================================== | |
| Showcases WaveGuard anomaly detection results. | |
| NO engine code included. All results pre-computed. | |
| For live detection, use the API: https://rapidapi.com/gpartin/api/waveguard | |
| """ | |
| import json | |
| import os | |
| import gradio as gr | |
| import matplotlib | |
| matplotlib.use("Agg") | |
| import matplotlib.pyplot as plt | |
| import matplotlib.gridspec as gridspec | |
| import numpy as np | |
| from matplotlib.patches import Patch | |
| # --------------------------------------------------------------------------- | |
| # Load pre-computed demo results (generated locally with full engine) | |
| # --------------------------------------------------------------------------- | |
| _HERE = os.path.dirname(os.path.abspath(__file__)) | |
| with open(os.path.join(_HERE, "demo_results.json")) as _f: | |
| DEMO_DATA = json.load(_f) | |
| # --------------------------------------------------------------------------- | |
| # Color palette | |
| # --------------------------------------------------------------------------- | |
| C_NORMAL = "#43a047" | |
| C_ANOMALY = "#e53935" | |
| C_ACCENT = "#1565c0" | |
| C_BG = "#fafafa" | |
| C_GRID = "#e0e0e0" | |
| C_WG = "#1565c0" | |
| C_IF = "#ff9800" | |
| C_LOF = "#7b1fa2" | |
| C_SVM = "#546e7a" | |
| def _score_color(is_anomaly): | |
| return C_ANOMALY if is_anomaly else C_NORMAL | |
| # --------------------------------------------------------------------------- | |
| # Benchmark comparison data (from validated benchmark suite) | |
| # --------------------------------------------------------------------------- | |
| BENCHMARKS = [ | |
| ("Credit Card Fraud*", 0.653, 0.607, 0.601, 0.472), | |
| ("Crypto Fraud", 1.000, 0.933, 0.946, 0.897), | |
| ("Network Security", 0.990, 0.962, 0.980, 0.952), | |
| ("Ad Click Fraud", 0.988, 0.952, 0.930, 0.889), | |
| ("Insurance Claims", 0.972, 0.921, 0.959, 0.833), | |
| ("API Monitoring", 0.959, 0.909, 0.933, 0.814), | |
| ] | |
| def build_benchmark_chart(): | |
| """Grouped bar chart: WaveGuard vs baselines on selected benchmarks.""" | |
| names = [b[0] for b in BENCHMARKS] | |
| wg = [b[1] for b in BENCHMARKS] | |
| iso_f = [b[2] for b in BENCHMARKS] | |
| lof = [b[3] for b in BENCHMARKS] | |
| svm = [b[4] for b in BENCHMARKS] | |
| fig, ax = plt.subplots(figsize=(12, 6)) | |
| fig.patch.set_facecolor(C_BG) | |
| ax.set_facecolor(C_BG) | |
| x = np.arange(len(names)) | |
| w = 0.19 | |
| ax.bar(x - 1.5 * w, wg, w, label="WaveGuard", color=C_WG, | |
| edgecolor="#333", linewidth=0.5) | |
| ax.bar(x - 0.5 * w, iso_f, w, label="IsolationForest", color=C_IF, | |
| edgecolor="#333", linewidth=0.5) | |
| ax.bar(x + 0.5 * w, lof, w, label="LOF", color=C_LOF, | |
| edgecolor="#333", linewidth=0.5) | |
| ax.bar(x + 1.5 * w, svm, w, label="OneClassSVM", color=C_SVM, | |
| edgecolor="#333", linewidth=0.5) | |
| for i, val in enumerate(wg): | |
| ax.text(i - 1.5 * w, val + 0.015, f"{val:.2f}", ha="center", | |
| va="bottom", fontsize=8, fontweight="bold", color=C_WG) | |
| ax.set_ylabel("F1 Score", fontsize=12) | |
| ax.set_title("WaveGuard vs Traditional Anomaly Detectors", | |
| fontsize=14, fontweight="bold", pad=15) | |
| ax.set_xticks(x) | |
| ax.set_xticklabels(names, rotation=25, ha="right", fontsize=10) | |
| ax.set_ylim(0, 1.15) | |
| ax.legend(loc="upper right", fontsize=9, framealpha=0.9) | |
| ax.grid(axis="y", alpha=0.3, color=C_GRID) | |
| plt.tight_layout() | |
| return fig | |
| # --------------------------------------------------------------------------- | |
| # Visualization builders | |
| # --------------------------------------------------------------------------- | |
| def build_score_chart(demo_key): | |
| """Bar chart of anomaly scores with ground truth annotations.""" | |
| d = DEMO_DATA[demo_key] | |
| labels = d["test_labels"] | |
| results = d["results"] | |
| expected = d["expected_anomaly"] | |
| n = len(labels) | |
| fig, ax = plt.subplots(figsize=(max(10, n * 1.2), 5)) | |
| fig.patch.set_facecolor(C_BG) | |
| ax.set_facecolor(C_BG) | |
| scores = [r["score"] for r in results] | |
| detected = [r["is_anomaly"] for r in results] | |
| colors = [_score_color(det) for det in detected] | |
| bars = ax.bar(range(n), scores, color=colors, edgecolor="#333", | |
| linewidth=0.6, alpha=0.85, width=0.7) | |
| for i, (bar, sc, det, exp) in enumerate(zip(bars, scores, detected, expected)): | |
| # Top label | |
| if det and exp: | |
| label = "CAUGHT" | |
| color = C_ANOMALY | |
| elif det and not exp: | |
| label = "FALSE POS" | |
| color = "#ff9800" | |
| elif not det and exp: | |
| label = "MISSED" | |
| color = "#9e9e9e" | |
| else: | |
| label = "OK" | |
| color = C_NORMAL | |
| y_pos = bar.get_height() + max(scores) * 0.03 | |
| ax.text(bar.get_x() + bar.get_width() / 2., y_pos, label, | |
| ha="center", va="bottom", fontsize=8, fontweight="bold", | |
| color=color) | |
| # Ground truth marker | |
| if exp: | |
| ax.plot(i, -max(scores) * 0.04, marker="^", color=C_ANOMALY, | |
| markersize=8, zorder=5) | |
| ax.set_xticks(range(n)) | |
| ax.set_xticklabels(labels, rotation=35, ha="right", fontsize=9) | |
| ax.set_ylabel("Anomaly Score", fontsize=11) | |
| ax.set_title(d["scenario"], fontsize=13, fontweight="bold", pad=15) | |
| ax.grid(axis="y", alpha=0.3, color=C_GRID) | |
| ax.legend(handles=[ | |
| Patch(color=C_NORMAL, label="Normal"), | |
| Patch(color=C_ANOMALY, label="Anomaly detected"), | |
| plt.Line2D([0], [0], marker="^", color=C_ANOMALY, linestyle="None", | |
| markersize=8, label="True anomaly"), | |
| ], loc="upper left", fontsize=8, framealpha=0.9) | |
| plt.tight_layout() | |
| return fig | |
| def build_timeseries_chart(): | |
| """Specialized time series visualization with signal preview.""" | |
| d = DEMO_DATA["timeseries"] | |
| results = d["results"] | |
| labels = d["test_labels"] | |
| expected = d["expected_anomaly"] | |
| test_data = d.get("test_preview", []) | |
| train_data = d.get("train_preview", []) | |
| fig = plt.figure(figsize=(14, 8)) | |
| fig.patch.set_facecolor(C_BG) | |
| gs = gridspec.GridSpec(2, 1, height_ratios=[2, 1], hspace=0.35) | |
| # Top: Signal traces | |
| ax1 = fig.add_subplot(gs[0]) | |
| ax1.set_facecolor(C_BG) | |
| if train_data: | |
| for i, win in enumerate(train_data[:3]): | |
| ax1.plot(win, color="#90caf9", alpha=0.4, linewidth=0.8, | |
| label="Training (normal)" if i == 0 else None) | |
| if test_data: | |
| for i, (win, r, lbl) in enumerate(zip(test_data, results, labels)): | |
| color = C_ANOMALY if r["is_anomaly"] else C_NORMAL | |
| style = "--" if expected[i] else "-" | |
| ax1.plot(win, color=color, linewidth=1.5, alpha=0.8, linestyle=style, | |
| label=f'{lbl} ({"ANOMALY" if r["is_anomaly"] else "ok"})') | |
| ax1.set_xlabel("Time Step", fontsize=10) | |
| ax1.set_ylabel("Value", fontsize=10) | |
| ax1.set_title("Time Series: Training vs Test Windows", fontsize=12, fontweight="bold") | |
| ax1.legend(fontsize=7, loc="upper right", ncol=2, framealpha=0.9) | |
| ax1.grid(True, alpha=0.3, color=C_GRID) | |
| # Bottom: Score bars | |
| ax2 = fig.add_subplot(gs[1]) | |
| ax2.set_facecolor(C_BG) | |
| scores = [r["score"] for r in results] | |
| detected = [r["is_anomaly"] for r in results] | |
| colors = [_score_color(det) for det in detected] | |
| ax2.bar(range(len(scores)), scores, color=colors, edgecolor="#333", | |
| linewidth=0.5, alpha=0.85, width=0.7) | |
| ax2.set_xticks(range(len(scores))) | |
| ax2.set_xticklabels(labels, rotation=30, ha="right", fontsize=8) | |
| ax2.set_ylabel("Anomaly Score", fontsize=10) | |
| ax2.set_title("Detection Results", fontsize=12, fontweight="bold") | |
| ax2.grid(axis="y", alpha=0.3, color=C_GRID) | |
| for i, exp_flag in enumerate(expected): | |
| if exp_flag: | |
| ax2.plot(i, -max(scores) * 0.04, marker="^", color=C_ANOMALY, | |
| markersize=8, zorder=5) | |
| plt.tight_layout() | |
| return fig | |
| def build_summary_text(demo_key): | |
| """Build a clean text summary for the demo results.""" | |
| d = DEMO_DATA[demo_key] | |
| results = d["results"] | |
| labels = d["test_labels"] | |
| expected = d["expected_anomaly"] | |
| n_true = sum(1 for e in expected if e) | |
| n_norm = sum(1 for e in expected if not e) | |
| n_caught = sum(1 for i, r in enumerate(results) if expected[i] and r["is_anomaly"]) | |
| n_fp = sum(1 for i, r in enumerate(results) if not expected[i] and r["is_anomaly"]) | |
| lines = [ | |
| d["scenario"].upper(), | |
| "=" * 55, | |
| f"Training samples: {d['training_count']}", | |
| f"Grid: {d['grid_size']}^3 ({d['grid_size']**3:,} cells)", | |
| f"Compute time: {d['elapsed_seconds']}s (pre-computed)", | |
| "", | |
| "PERFORMANCE:", | |
| f" Anomalies caught: {n_caught}/{n_true} ({n_caught/max(n_true,1):.0%})", | |
| f" False positives: {n_fp}/{n_norm} ({n_fp/max(n_norm,1):.0%})", | |
| "", | |
| "DETAIL:", | |
| ] | |
| for i, (r, lbl, exp) in enumerate(zip(results, labels, expected)): | |
| tag = "" | |
| if exp and r["is_anomaly"]: | |
| tag = " >> CAUGHT <<" | |
| elif exp and not r["is_anomaly"]: | |
| tag = " ** MISSED **" | |
| elif not exp and r["is_anomaly"]: | |
| tag = " [false positive]" | |
| lines.append( | |
| f" {lbl}: score={r['score']:.3f} " | |
| f"conf={r['confidence']:.3f}{tag}" | |
| ) | |
| if "note" in d: | |
| lines.extend(["", f"NOTE: {d['note']}"]) | |
| lines.extend([ | |
| "", | |
| "-" * 55, | |
| "Want to run on YOUR data? Use the WaveGuard API:", | |
| " https://rapidapi.com/gpartin/api/waveguard", | |
| " pip install WaveGuardClient", | |
| ]) | |
| return "\n".join(lines) | |
| # --------------------------------------------------------------------------- | |
| # Demo handler functions | |
| # --------------------------------------------------------------------------- | |
| def run_timeseries_demo(): | |
| fig = build_timeseries_chart() | |
| summary = build_summary_text("timeseries") | |
| return summary, fig | |
| def run_financial_demo(): | |
| fig = build_score_chart("financial") | |
| summary = build_summary_text("financial") | |
| return summary, fig | |
| def run_process_demo(): | |
| fig = build_score_chart("process_health") | |
| summary = build_summary_text("process_health") | |
| return summary, fig | |
| def run_network_demo(): | |
| fig = build_score_chart("network") | |
| summary = build_summary_text("network") | |
| return summary, fig | |
| # --------------------------------------------------------------------------- | |
| # Gradio UI -- Markdown content | |
| # --------------------------------------------------------------------------- | |
| HEADER_MD = """ | |
| # WaveGuard: Physics-Based Anomaly Detection | |
| **Zero-training anomaly detection powered by wave equation physics.** | |
| No neural networks. No gradient descent. No hyperparameter tuning. **Deterministic.** | |
| Your data enters a physics simulation where normal behavior creates smooth wave | |
| propagation. Anomalies disrupt the simulation in measurable ways -- catching threats | |
| that statistical methods miss. | |
| | | WaveGuard | Traditional ML | | |
| |---|---|---| | |
| | **Training data** | 2-15 samples | Hundreds to thousands | | |
| | **Hyperparameters** | Zero | Many | | |
| | **Deterministic** | Always | Rarely | | |
| | **Explainable** | Per-feature breakdown | Often opaque | | |
| **Ranked #1 in F1 score on all 12 benchmark datasets** vs. IsolationForest, LOF, | |
| and OneClassSVM. **See the Benchmarks tab below.** | |
| """ | |
| BENCHMARK_MD = """ | |
| ### WaveGuard vs Traditional Anomaly Detectors | |
| Head-to-head comparison using identical train/test splits. | |
| WaveGuard uses 2-15 training samples; baselines use the same data | |
| with default scikit-learn hyperparameters. | |
| **Result: Ranked #1 on all 12 benchmark datasets by F1 score.** | |
| | Dataset | WaveGuard | IsolationForest | LOF | OneClassSVM | Winner | | |
| |---------|:---------:|:---------------:|:---:|:-----------:|:------:| | |
| | Credit Card Fraud* | **0.653** | 0.607 | 0.601 | 0.472 | WaveGuard | | |
| | Crypto Fraud | **1.000** | 0.933 | 0.946 | 0.897 | WaveGuard | | |
| | Network Security | **0.990** | 0.962 | 0.980 | 0.952 | WaveGuard | | |
| | Ad Click Fraud | **0.988** | 0.952 | 0.930 | 0.889 | WaveGuard | | |
| | Insurance Claims | **0.972** | 0.921 | 0.959 | 0.833 | WaveGuard | | |
| | API Monitoring | **0.959** | 0.909 | 0.933 | 0.814 | WaveGuard | | |
| *\\*Real-world dataset. Others use domain-specific test suites. | |
| Full results: [waveguard-benchmarks](https://huggingface.co/datasets/emergentphysicslab/waveguard-benchmarks)* | |
| """ | |
| HOW_IT_WORKS_MD = """ | |
| ## How It Works | |
| WaveGuard replaces machine learning with **physics simulation**. | |
| ### Detection in 5 Steps | |
| 1. **Encode** -- Your data is mapped into a simulation environment | |
| 2. **Evolve** -- Wave equations run forward, adapting to your normal patterns | |
| 3. **Lock** -- The evolved state is frozen as your reference model | |
| 4. **Test** -- New data enters the simulation. Normal data propagates smoothly. | |
| Anomalies create measurable disruptions. | |
| 5. **Score** -- Disruption magnitude becomes the anomaly score. | |
| Per-feature breakdowns show exactly what triggered detection. | |
| ### Why Physics Instead of Statistics? | |
| Statistical methods draw boundaries around "normal" in feature space. | |
| This breaks down with small training sets, concept drift, or correlated | |
| multi-feature shifts. | |
| Wave equations model how information propagates through a system. | |
| Normal patterns create resonant, low-energy propagation. Anomalies | |
| break the resonance -- regardless of direction in feature space. | |
| **Result:** Robust detection from a handful of examples, zero tuning. | |
| ### Best For | |
| - **Multi-feature anomalies** -- several metrics shift simultaneously | |
| - **Pattern breaks** -- frequency shifts, level changes, structural discontinuities | |
| - **Extreme events** -- crashes, spikes, DDoS attacks, sensor failures | |
| - **Cold start** -- works with as few as 2 training samples | |
| ### Known Limitations | |
| - Subtle single-feature drift may not trigger detection | |
| - High-variance data can produce elevated false positive rates | |
| - Not designed for image classification, NLP, or structured prediction | |
| """ | |
| FOOTER_MD = """ | |
| --- | |
| **WaveGuard v3.3.0** by [Emergent Physics Lab](https://huggingface.co/emergentphysicslab) | | |
| [RapidAPI](https://rapidapi.com/gpartin/api/waveguard) | | |
| [GitHub](https://github.com/gpartin/WaveGuardClient) | | |
| [PyPI](https://pypi.org/project/WaveGuardClient/) | | |
| [MCP Registry](https://glama.ai/mcp/connectors/com.emergentphysicslab/waveguard) | | |
| MIT License | |
| """ | |
| # --------------------------------------------------------------------------- | |
| # Gradio app layout | |
| # --------------------------------------------------------------------------- | |
| with gr.Blocks( | |
| title="WaveGuard - Physics-Based Anomaly Detection", | |
| theme=gr.themes.Soft(), | |
| css=""" | |
| .demo-btn { min-height: 80px !important; font-size: 14px !important; } | |
| .results-text { font-family: 'Consolas', 'Monaco', monospace; font-size: 12px; } | |
| """ | |
| ) as demo: | |
| gr.Markdown(HEADER_MD) | |
| with gr.Tabs(): | |
| # ============================================================== | |
| # Tab 1: Interactive Demos | |
| # ============================================================== | |
| with gr.TabItem("Live Demos", id="demos"): | |
| gr.Markdown("Click any scenario to see pre-computed detection results.") | |
| with gr.Row(): | |
| btn_ts = gr.Button( | |
| "Time Series\nSpikes, shifts, flatlines", | |
| variant="primary", elem_classes=["demo-btn"]) | |
| btn_fin = gr.Button( | |
| "Financial Fraud\nCard testing, structuring", | |
| variant="primary", elem_classes=["demo-btn"]) | |
| btn_proc = gr.Button( | |
| "Process Health\nMemory leaks, crashes", | |
| variant="secondary", elem_classes=["demo-btn"]) | |
| btn_net = gr.Button( | |
| "Network Intrusion\nSYN floods, port scans", | |
| variant="secondary", elem_classes=["demo-btn"]) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| demo_summary = gr.Textbox( | |
| label="Results Summary", lines=22, max_lines=30, | |
| elem_classes=["results-text"], | |
| value="Click a demo button above to see results.") | |
| with gr.Column(scale=2): | |
| demo_plot = gr.Plot(label="Visualization") | |
| gr.Markdown(""" | |
| --- | |
| **Ready to analyze your own data?** | |
| [Subscribe on RapidAPI](https://rapidapi.com/gpartin/api/waveguard) (free tier available) | |
| | `pip install WaveGuardClient` | [MCP Server](https://glama.ai/mcp/connectors/com.emergentphysicslab/waveguard) | |
| """) | |
| btn_ts.click(fn=run_timeseries_demo, outputs=[demo_summary, demo_plot]) | |
| btn_fin.click(fn=run_financial_demo, outputs=[demo_summary, demo_plot]) | |
| btn_proc.click(fn=run_process_demo, outputs=[demo_summary, demo_plot]) | |
| btn_net.click(fn=run_network_demo, outputs=[demo_summary, demo_plot]) | |
| # ============================================================== | |
| # Tab 2: Benchmarks | |
| # ============================================================== | |
| with gr.TabItem("Benchmarks", id="benchmarks"): | |
| gr.Markdown(BENCHMARK_MD) | |
| benchmark_plot = gr.Plot(label="F1 Score Comparison") | |
| demo.load(fn=build_benchmark_chart, outputs=benchmark_plot) | |
| # ============================================================== | |
| # Tab 3: How It Works | |
| # ============================================================== | |
| with gr.TabItem("How It Works", id="howto"): | |
| gr.Markdown(HOW_IT_WORKS_MD) | |
| # ============================================================== | |
| # Tab 4: Get Started | |
| # ============================================================== | |
| with gr.TabItem("Get Started", id="api"): | |
| gr.Markdown(""" | |
| ## Start Using WaveGuard | |
| ### Option 1: RapidAPI -- Hosted, No Setup | |
| Subscribe and start making API calls immediately. | |
| | Plan | Price | Rate Limit | Best For | | |
| |------|-------|-----------|----------| | |
| | **Free** | $0 | 10 req/month | Try it out | | |
| | **Pro** | $0.005/req | 60/min | Production apps | | |
| | **Ultra** | $0.003/req | 300/min | High volume | | |
| | **Mega** | $0.001/req | 1000/min | Enterprise scale | | |
| **[Subscribe on RapidAPI ->](https://rapidapi.com/gpartin/api/waveguard)** | |
| --- | |
| ### Option 2: MCP Server -- AI Agent Integration | |
| Connect WaveGuard to Claude, Cursor, or any MCP-compatible AI agent. | |
| | Directory | Status | | |
| |-----------|--------| | |
| | [Glama](https://glama.ai/mcp/connectors/com.emergentphysicslab/waveguard) | Live | | |
| | [Smithery](https://smithery.ai/servers/emergentphysicslab/waveguard) | Live -- 100/100 quality score | | |
| | [awesome-mcp-servers](https://github.com/punkpeye/awesome-mcp-servers) | Listed | | |
| --- | |
| ### Option 3: Python SDK -- Full Control | |
| ```bash | |
| pip install WaveGuardClient | |
| ``` | |
| ```python | |
| from waveguard import WaveGuard | |
| wg = WaveGuard(api_key="YOUR_RAPIDAPI_KEY") | |
| # Detect a compromised server | |
| result = wg.scan( | |
| training=[ | |
| {"cpu": 45, "memory": 62, "disk_io": 120, "errors": 0}, | |
| {"cpu": 48, "memory": 63, "disk_io": 115, "errors": 0}, | |
| {"cpu": 42, "memory": 61, "disk_io": 125, "errors": 1}, | |
| ], | |
| test=[ | |
| {"cpu": 46, "memory": 62, "disk_io": 119, "errors": 0}, | |
| {"cpu": 99, "memory": 95, "disk_io": 800, "errors": 150}, | |
| ], | |
| ) | |
| for r in result.results: | |
| status = "ANOMALY" if r.is_anomaly else "normal" | |
| print(f"{status} score={r.score:.1f} confidence={r.confidence:.0%}") | |
| ``` | |
| Get your free API key at [RapidAPI](https://rapidapi.com/gpartin/api/waveguard). | |
| ### Time Series Mode | |
| ```python | |
| result = wg.scan( | |
| training=[ | |
| [1.0, 1.1, 0.9, 1.0, 1.05, 0.95], | |
| [0.95, 1.0, 1.1, 0.98, 1.02, 1.0], | |
| ], | |
| test=[ | |
| [1.0, 1.0, 1.0, 8.0, 1.0, 1.0], # spike | |
| ], | |
| encoder_type="timeseries", | |
| ) | |
| ``` | |
| --- | |
| | Resource | URL | | |
| |----------|-----| | |
| | **RapidAPI** | [rapidapi.com/gpartin/api/waveguard](https://rapidapi.com/gpartin/api/waveguard) | | |
| | **PyPI** | [pypi.org/project/WaveGuardClient](https://pypi.org/project/WaveGuardClient/) | | |
| | **GitHub** | [github.com/gpartin/WaveGuardClient](https://github.com/gpartin/WaveGuardClient) | | |
| | **MCP** | [glama.ai/mcp/connectors](https://glama.ai/mcp/connectors/com.emergentphysicslab/waveguard) | | |
| | **Model Card** | [huggingface.co/emergentphysicslab/waveguard-anomaly-detector](https://huggingface.co/emergentphysicslab/waveguard-anomaly-detector) | | |
| | **Benchmarks** | [huggingface.co/datasets/emergentphysicslab/waveguard-benchmarks](https://huggingface.co/datasets/emergentphysicslab/waveguard-benchmarks) | | |
| """) | |
| gr.Markdown(FOOTER_MD) | |
| if __name__ == "__main__": | |
| demo.launch() | |