build(agent): new-agents-2#7e3bbc iteration

This commit is contained in:
agent-7e3bbc424e07835b 2026-04-23 23:14:37 +02:00
parent 98c925e3ae
commit ce837c2ac8
14 changed files with 271 additions and 2 deletions

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
node_modules/
.npmrc
.env
.env.*
__tests__/
coverage/
.nyc_output/
dist/
build/
.cache/
*.log
.DS_Store
tmp/
.tmp/
__pycache__/
*.pyc
.venv/
venv/
*.egg-info/
.pytest_cache/
READY_TO_PUBLISH

28
AGENTS.md Normal file
View File

@ -0,0 +1,28 @@
# Architecture and Contributor Guide
Overview
- This repository hosts a production-ready MVP for SolarPulse Viz Real, an open-source framework for real-time visualization and anomaly insights across distributed solar, wind, and storage assets.
Tech Stack
- Backend: Python 3.9+ with FastAPI for REST APIs
- ML: Scikit-learn (IsolationForest) for unsupervised anomaly detection
- Data: SQLite (via SQLAlchemy) for lightweight persistence in the MVP
- Adapters: Lightweight Python modules for telemetry gateway and inverter fault detector
- Packaging: PyProject.toml with setuptools-based build
Key Modules
- src/idea46_solarpulse_viz_real/main.py: FastAPI app with endpoints for health and telemetry intake
- src/idea46_solarpulse_viz_real/anomaly.py: IsolationForest-based detector (embedded in app for MVP)
- adapters/telemetry_gateway.py: Starter adapter to parse telemetry payloads
- adapters/inverter_fault_detector.py: Starter adapter for fault detection logic
- tests/: Basic test suite to verify API and anomaly scoring
Testing & Running
- test.sh: Script to run tests and build (see file for details)
- Tests use pytest; you can extend tests to cover more endpoints and adapters
Publishing
- When youre ready to publish, ensure READY_TO_PUBLISH exists at repo root and that tests pass locally.
Notes
- This MVP emphasizes minimal, correct changes with clean interfaces. Iterate with the swarm by adding more adapters, data contracts, and dashboards in subsequent sprint turns.

View File

@ -1,3 +1,17 @@
# idea46-solarpulse-viz-real # SolarPulse Viz Real
Source logic for Idea #46 SolarPulse Viz is a production-focused framework for real-time visualization and actionable anomaly insights across distributed solar, wind, and storage assets.
- Mobile-first dashboards with real-time and historical time-series views across multiple sites
- Standardized data contracts and a lightweight interoperability bridge
- Lightweight ML-based anomaly detector (unsupervised models)
- AR maintenance overlays and cross-domain storytelling templates
- Offline-friendly data caching with delta-sync when connectivity returns
This repository implements a solid, production-grade chunk of that vision as a Python FastAPI service, suitable for extension by agents in sprint-based workflows.
How to run locally
- Install dependencies: python -m pip install -e .
- Run: uvicorn idea46_solarpulse_viz_real.main:app --reload --port 8000
This is a scaffold and MVP focused on the core server and anomaly-detection workflow. See AGENTS.md for architecture and contribution details.

24
pyproject.toml Normal file
View File

@ -0,0 +1,24 @@
# Project metadata and build system for a production-grade Python package
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "idea46-solarpulse-viz-real"
version = "0.1.0"
description = "SolarPulse Viz: Real-time Visualization & Anomaly Insights for Distributed Solar, Wind, and Storage"
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
"fastapi>=0.82.0",
"uvicorn[standard]>=0.18.0",
"pydantic>=1.10.2",
"sqlalchemy>=1.4",
"scikit-learn>=1.3",
"pandas>=1.5",
"numpy>=1.23",
"httpx>=0.24.0",
]
[tool.setuptools.packages.find]
where = ["src"]

1
src/__init__.py Normal file
View File

@ -0,0 +1 @@
"""Topology marker for src package."""

View File

@ -0,0 +1 @@
"""Idea46 SolarPulse Viz Real package init."""

View File

@ -0,0 +1 @@
# Adapters package initializer

View File

@ -0,0 +1,17 @@
from typing import Dict
def detect_fault(telemetry: Dict) -> bool:
"""Simple, starter fault-detection heuristic for an inverter.
This is intentionally lightweight and pluggable for later refinement
with ML models or rule-based checks.
"""
temp = telemetry.get("temp", 0.0)
vcur = telemetry.get("v_current", 0.0)
# Heuristic: flag fault if temperature is out of typical range or current spike
if temp > 80.0 or temp < -10.0:
return True
if vcur > 100.0:
return True
return False

View File

@ -0,0 +1,21 @@
from typing import Dict
from ..models import TelemetryEvent
def parse_telemetry(payload: Dict) -> TelemetryEvent:
"""Parse a raw telemetry payload into a TelemetryEvent model.
This is a lightweight starter adapter; real deployments would include
robust validation, TLS mutual authentication, and schema versioning.
"""
# Minimal mapping with defaults
return TelemetryEvent(
site_id=payload.get("site_id", "unknown_site"),
asset_id=payload.get("asset_id", "unknown_asset"),
timestamp=payload.get("timestamp", "1970-01-01T00:00:00Z"),
v_current=float(payload.get("v_current", 0.0)),
temp=float(payload.get("temp", 0.0)),
# Support optional vibration data; default to 0.0 if missing
vibration=float(payload.get("vibration", 0.0)),
status=payload.get("status"),
)

View File

@ -0,0 +1,20 @@
from typing import Dict
import numpy as np
from sklearn.ensemble import IsolationForest
class AnomalyEngine:
def __init__(self, seed: int = 42):
# Lightweight seedable model trained on synthetic data representing normal operation
rng = np.random.RandomState(seed)
# Features: [v_current, temp, vibration]
X = rng.normal(loc=[12.0, 35.0, 0.5], scale=[2.0, 5.0, 0.2], size=(1000, 3))
self.model = IsolationForest(contamination=0.05, random_state=seed)
self.model.fit(X)
def score(self, sample: Dict[str, float]) -> float:
# Build feature vector in the expected order
x = np.array([[sample.get("v_current", 0.0), sample.get("temp", 0.0), sample.get("vibration", 0.0)]], dtype=float)
# IsolationForest.decision_function is higher for normal instances; we invert to get an anomaly score
score_norm = self.model.decision_function(x)[0]
return float(-score_norm)

View File

@ -0,0 +1,46 @@
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from .anomaly import AnomalyEngine
from .models import TelemetryEvent
from .adapters.telemetry_gateway import parse_telemetry
import threading
app = FastAPI(title="SolarPulse Viz Real MVP")
# Initialize anomaly engine once
anomaly_engine = AnomalyEngine()
_lock = threading.Lock()
@app.get("/")
async def root():
return {"status": "SolarPulse Viz Real MVP is running"}
@app.get("/health")
async def health():
return {"status": "ok"}
@app.post("/telemetry")
async def telemetry(payload: TelemetryEvent):
# Compute a lightweight anomaly score for the incoming payload
with _lock:
score = anomaly_engine.score({
"v_current": payload.v_current,
"temp": payload.temp,
# Use actual vibration value if provided (default 0.0)
"vibration": payload.vibration,
})
# In a real system we'd persist to a DB and route to dashboards/alerts
return {
"site_id": payload.site_id,
"asset_id": payload.asset_id,
"timestamp": payload.timestamp,
"anomaly_score": score,
"status": payload.status or "OK",
}

View File

@ -0,0 +1,26 @@
from pydantic import BaseModel
from typing import Optional
class TelemetryEvent(BaseModel):
site_id: str
asset_id: str
timestamp: str
v_current: float
temp: float
# Optional vibration metric; default to 0.0 if not provided
vibration: float = 0.0
status: Optional[str] = None
class AlarmEvent(BaseModel):
alarm_id: str
site_id: str
severity: str
timestamp: str
class AggregatedSignal(BaseModel):
site_id: str
score: float
version: int

14
test.sh Normal file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
echo "==> Installing package and dependencies (editable install) before tests"
python -m pip install --upgrade pip setuptools wheel
pip install -e .
echo "==> Running Python package tests (pytest) and build verification"
pytest -q
echo "==> Building Python package (python -m build) to verify packaging module"
python3 -m build
echo "All tests and build steps completed successfully."

35
tests/test_api.py Normal file
View File

@ -0,0 +1,35 @@
import sys
import os
from fastapi.testclient import TestClient
# Ensure the local src layout is on PYTHONPATH for tests
SRC_PATH = os.path.join(os.path.dirname(__file__), os.pardir, 'src')
SYS_PATH = os.path.abspath(SRC_PATH)
if SYS_PATH not in sys.path:
sys.path.insert(0, SYS_PATH)
from idea46_solarpulse_viz_real.main import app
def test_health_endpoint():
client = TestClient(app)
resp = client.get("/health")
assert resp.status_code == 200
assert resp.json() == {"status": "ok"}
def test_telemetry_endpoint_basic():
client = TestClient(app)
payload = {
"site_id": "site-A",
"asset_id": "inverter-1",
"timestamp": "2026-04-23T12:00:00Z",
"v_current": 10.5,
"temp": 34.2,
"status": "OK",
}
resp = client.post("/telemetry", json=payload)
assert resp.status_code == 200
data = resp.json()
assert data["site_id"] == "site-A"
assert "anomaly_score" in data