PowerForecast Developer Guide
Architecture Overview
PowerForecast consists of three main components:
```┌─────────────────────────────────────────────────────────────────────┐
│ PowerForecast Architecture │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Frontend Layer │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ Forecast Wizard │ │ Admin Console │ │ │
│ │ │ (Vanilla JS) │ │ (Vanilla JS) │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Backend Layer │ │
│ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │
│ │ │ Forecast Engine API │ │ SQLite API │ │ │
│ │ │ (Python/FastAPI) │ │ (Python/FastAPI) │ │ │
│ │ │ - Forecasting pipeline │ │ - Data management │ │ │
│ │ │ - Model execution │ │ - AI integration │ │ │
│ │ │ - Diagnostics │ │ - User management │ │ │
│ │ └─────────────────────────┘ └─────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Data & Engine Layer │ │
│ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │
│ │ │ SQLite Database │ │ StatsForecast Engine │ │ │
│ │ │ (Specs, Runs, Results) │ │ (AutoARIMA, ETS, etc.) │ │ │
│ │ └─────────────────────────┘ └─────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
```Project Structure
```PowerForecast/
├── forecast-api/ # Forecast Engine API (port 8020)
│ ├── app/
│ │ ├── main.py # FastAPI application
│ │ ├── config.py # Configuration
│ │ ├── models.py # Pydantic models
│ │ ├── routers/ # API endpoints
│ │ │ ├── forecast.py # Forecast pipeline
│ │ │ └── health.py # Health checks
│ │ └── pipeline/ # Forecasting pipeline
│ │ ├── profiler.py # Statistical profiling
│ │ ├── model_selector.py # Model selection
│ │ ├── engine.py # StatsForecast execution
│ │ └── diagnostics.py # Quality diagnostics
│ └── requirements.txt
│
├── forecast-sqlite-api/ # Data Management API (port 8021)
│ ├── app/
│ │ ├── main.py # FastAPI application
│ │ ├── database.py # Database operations
│ │ ├── models.py # Pydantic models
│ │ ├── routers/ # API endpoints
│ │ │ ├── specifications.py # Spec CRUD
│ │ │ ├── runs.py # Run management
│ │ │ ├── results.py # Results storage
│ │ │ ├── ai.py # AI integration
│ │ │ └── ...
│ │ └── ai/ # AI orchestrator
│ │ ├── orchestrator.py # AI coordination
│ │ └── llm_client.py # LLM client
│ └── schema.sql
│
├── forecast-wizard/ # Forecasting Wizard UI
│ ├── index.html # Main wizard interface
│ ├── js/
│ │ └── wizard-app.js # Wizard logic
│ └── styles.css
│
├── forecast-admin/ # Admin Console UI
│ ├── index.html
│ └── js/
│
└── documentation/ # Documentation
└── ...
```Setting Up Development Environment
Prerequisites
```bashPython 3.11+
pyenv install 3.11.0
pyenv local 3.11.0
Docker and Docker Compose (optional, for containerized development)
```Clone and Setup
```bashNavigate to project
cd D:\PowerForecast
Setup Forecast Engine API
cd forecast-api
python -m venv venv
source venv/bin/activate # or venv\Scripts\activate on Windows
pip install -r requirements.txt
Setup SQLite API
cd ../forecast-sqlite-api
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Initialize database
sqlite3 forecast.db < schema.sql
```Running Locally
Terminal 1 - Forecast Engine API:
```bashcd forecast-api
uvicorn app.main:app --reload --port 8020
```Terminal 2 - SQLite API:
```bashcd forecast-sqlite-api
uvicorn app.main:app --reload --port 8021
```Terminal 3 - Frontend (optional, for development server):
```bashcd forecast-wizard
python -m http.server 8080
```Forecast Engine API (Python/FastAPI)
Key Files
Main Application
```pythonapp/main.py
from fastapi import FastAPI
from app.routers import forecast, health
app = FastAPI(title="PowerForecast Engine API")
app.include_router(health.router)
app.include_router(forecast.router, prefix="/api/powerforecast/v1")
```Forecast Router
```pythonapp/routers/forecast.py
from fastapi import APIRouter, HTTPException
from app.models import ForecastRequest, ForecastResponse
from app.pipeline.engine import ForecastEngine
router = APIRouter(tags=["Forecast"])
@router.post("/forecast", response_model=ForecastResponse)
async def run_forecast(request: ForecastRequest):
engine = ForecastEngine()
result = await engine.run_forecast(request)
return result
```Pipeline Engine
```pythonapp/pipeline/engine.py
from statsforecast import StatsForecast
from app.pipeline.profiler import StatisticalProfiler
from app.pipeline.model_selector import ModelSelector
class ForecastEngine:
def __init__(self):
self.profiler = StatisticalProfiler()
self.model_selector = ModelSelector()
self.statsforecast = StatsForecast()
async def run_forecast(self, request: ForecastRequest):
# 1. Profile data
profile = await self.profiler.profile(request.data)
# 2. Select models
models = self.model_selector.select(profile, request.models)
# 3. Run forecast
forecasts = await self.statsforecast.forecast(
data=request.data,
models=models,
h=request.horizon
)
# 4. Generate diagnostics
diagnostics = await self.generate_diagnostics(forecasts, profile)
return ForecastResponse(
forecasts=forecasts,
profiling=profile,
diagnostics=diagnostics
)
```Adding a New Model
1. Add model to StatsForecast:
```pythonapp/pipeline/engine.py
from statsforecast.models import YourNewModel
models = [
AutoARIMA(),
ETS(),
YourNewModel() # Add new model
]
```2. Update model selector (if needed):
```pythonapp/pipeline/model_selector.py
def select(self, profile, requested_models):
if 'YourNewModel' in requested_models:
# Add selection logic
pass
```3. Update API models:
```pythonapp/models.py
class ForecastRequest(BaseModel):
models: List[str] = Field(default=['Auto'], description="Models to use")
# Add 'YourNewModel' to allowed values
```SQLite API (Python/FastAPI)
Key Files
Database Operations
```pythonapp/database.py
import sqlite3
from typing import Optional, List, Dict
async def get_db():
conn = sqlite3.connect('forecast.db')
conn.row_factory = sqlite3.Row
yield conn
conn.close()
async def execute_query(conn, query: str, params: tuple = ()):
cursor = conn.execute(query, params)
return cursor.fetchall()
```Specifications Router
```pythonapp/routers/specifications.py
from fastapi import APIRouter, Depends
from app.database import get_db
from app.models import Specification
router = APIRouter(prefix="/api/forecast/specifications", tags=["Specifications"])
@router.get("")
async def list_specifications(db = Depends(get_db)):
rows = await execute_query(db, "SELECT * FROM specifications")
return [Specification(**row) for row in rows]
@router.post("")
async def create_specification(spec: Specification, db = Depends(get_db)):
# Insert logic
pass
```Adding a New Endpoint
1. Create router file app/routers/myfeature.py:
from fastapi import APIRouter, Depends
from app.database import get_db
router = APIRouter(prefix="/api/forecast/myfeature", tags=["My Feature"])
@router.get("")
async def list_items(db = Depends(get_db)):
# Your logic
pass
```2. Register in main.py:
from app.routers import myfeature
app.include_router(myfeature.router)
```Frontend (Forecast Wizard)
Architecture
```forecast-wizard/
├── index.html # Main wizard interface
├── js/
│ └── wizard-app.js # Wizard state and logic
├── profiling.html # Profiling visualization
├── results.html # Results visualization
└── diagnostics.html # Diagnostics view
```State Management
```javascript// js/wizard-app.js
const state = {
currentStep: 1,
spec: {
business_target: '',
frequency: 'M',
horizon: 12,
confidence_level: 0.95,
models: ['Auto'],
handle_missing: true,
handle_outliers: true
},
data: null,
parsedData: [],
modelMode: 'auto',
lastResult: null
};
```Adding a New Wizard Step
1. Add HTML modal in index.html:
2. Add step handler in wizard-app.js:
function handleStep6() {
// Step 6 logic
}
document.getElementById('step6Next').addEventListener('click', handleStep6);
```3. Update step indicator:
```javascriptconst stepIndicator = `
`;
```Testing
Forecast Engine Tests
```bashcd forecast-api
pytest tests/
```SQLite API Tests
```bashcd forecast-sqlite-api
pytest tests/
```Writing Tests
```pythontests/test_forecast.py
import pytest
from app.pipeline.engine import ForecastEngine
@pytest.mark.asyncio
async def test_forecast_basic():
engine = ForecastEngine()
request = ForecastRequest(
business_target="demand",
frequency="M",
horizon=12,
data=[...]
)
result = await engine.run_forecast(request)
assert result.status == "completed"
assert len(result.forecasts) > 0
```Code Style
Python
async def run_forecast(
self,
request: ForecastRequest
) -> ForecastResponse:
"""
Run forecasting pipeline.
Args:
request: Forecast specification
Returns:
Forecast results with diagnostics
"""
pass
```JavaScript
/**
*/
async function runForecast() {
// Implementation
}
```Git Workflow
```bashFeature branch
git checkout -b feature/my-feature
Make changes
git add .
git commit -m "feat: add new forecasting model"
Push and create PR
git push origin feature/my-feature
```Commit Message Format
```type(scope): description
Types:
Extending PowerForecast
Adding a New Business Target
1. Update frontend (forecast-wizard/index.html):
New Target
Description
2. Update backend models (forecast-api/app/models.py):
class BusinessTarget(str, Enum):
demand = "demand"
workload = "workload"
new_target = "new_target" # Add new target
```Adding AI Capabilities
1. Create AI prompt in database:
```sqlINSERT INTO ai_prompts (name, system_prompt, ...)
VALUES ('forecast_explainer', 'You are a forecasting expert...', ...);
```2. Add AI endpoint (forecast-sqlite-api/app/routers/ai.py):
@router.post("/explain")
async def explain_forecast(forecast_id: str):
# AI explanation logic
pass
```3. Integrate in frontend (forecast-wizard/js/wizard-app.js):
async function getAIExplanation(forecastId) {
const response = await fetch(${SQLITE_API_URL}/api/forecast/ai/explain, {
method: 'POST',
body: JSON.stringify({ forecast_id: forecastId })
});
return await response.json();
}
```Performance Optimization
Forecast Engine
SQLite API
Frontend
Debugging
Forecast Engine Debugging
```pythonEnable debug logging
import logging
logging.basicConfig(level=logging.DEBUG)
Add debug prints
logger.debug(f"Profiling result: {profile}")
```SQLite API Debugging
```bashEnable debug mode
uvicorn app.main:app --reload --log-level debug
```Frontend Debugging
```javascript// Enable debug mode
window.DEBUG = true;
console.log('[Debug]', state);
```Deployment
Docker Deployment
```bashBuild images
cd forecast-api
docker build -t powerforecast-engine .
cd ../forecast-sqlite-api
docker build -t powerforecast-sqlite .
Run containers
docker-compose up -d
```Environment Variables
```bashforecast-api/.env
FORECAST_ENGINE_PORT=8020
LOG_LEVEL=INFO
forecast-sqlite-api/.env
SQLITE_API_PORT=8021
DATABASE_PATH=./forecast.db
AI_PROVIDER=deepseek
AI_API_KEY=your_key_here
```Resources
Remember: PowerForecast is designed to be extensible. Follow the patterns above when adding new features, and maintain consistency with existing code style.