PowerForecast Docs
Back to Wizard

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

```bash

Python 3.11+

pyenv install 3.11.0

pyenv local 3.11.0

Docker and Docker Compose (optional, for containerized development)

```

Clone and Setup

```bash

Navigate 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:

```bash

cd forecast-api

uvicorn app.main:app --reload --port 8020

```

Terminal 2 - SQLite API:

```bash

cd forecast-sqlite-api

uvicorn app.main:app --reload --port 8021

```

Terminal 3 - Frontend (optional, for development server):

```bash

cd forecast-wizard

python -m http.server 8080

```

Forecast Engine API (Python/FastAPI)

Key Files

Main Application

```python

app/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

```python

app/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

```python

app/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:

```python

app/pipeline/engine.py

from statsforecast.models import YourNewModel

models = [

AutoARIMA(),

ETS(),

YourNewModel() # Add new model

]

```

2. Update model selector (if needed):

```python

app/pipeline/model_selector.py

def select(self, profile, requested_models):

if 'YourNewModel' in requested_models:

# Add selection logic

pass

```

3. Update API models:

```python

app/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

```python

app/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

```python

app/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:

```python

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:

```python

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:

```html

```

2. Add step handler in wizard-app.js:

```javascript

function handleStep6() {

// Step 6 logic

}

document.getElementById('step6Next').addEventListener('click', handleStep6);

```

3. Update step indicator:

```javascript

const stepIndicator = `

6. New Step

`;

```

Testing

Forecast Engine Tests

```bash

cd forecast-api

pytest tests/

```

SQLite API Tests

```bash

cd forecast-sqlite-api

pytest tests/

```

Writing Tests

```python

tests/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

  • Follow PEP 8
  • Use type hints
  • Document with docstrings
  • Use async/await for I/O operations
  • ```python

    async def run_forecast(

    self,

    request: ForecastRequest

    ) -> ForecastResponse:

    """

    Run forecasting pipeline.

    Args:

    request: Forecast specification

    Returns:

    Forecast results with diagnostics

    """

    pass

    ```

    JavaScript

  • Use ES6+ features
  • Prefer `const` over `let`
  • Document with JSDoc
  • ```javascript

    /**

  • Run forecast with current specification
  • @returns {Promise} Forecast results

    */

    async function runForecast() {

    // Implementation

    }

    ```

    Git Workflow

    ```bash

    Feature 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:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation
  • style: Formatting
  • refactor: Code restructuring
  • test: Adding tests
  • chore: Maintenance
  • ```

    Extending PowerForecast

    Adding a New Business Target

    1. Update frontend (forecast-wizard/index.html):

    ```html

    🎯

    New Target

    Description

    ```

    2. Update backend models (forecast-api/app/models.py):

    ```python

    class BusinessTarget(str, Enum):

    demand = "demand"

    workload = "workload"

    new_target = "new_target" # Add new target

    ```

    Adding AI Capabilities

    1. Create AI prompt in database:

    ```sql

    INSERT 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):

    ```python

    @router.post("/explain")

    async def explain_forecast(forecast_id: str):

    # AI explanation logic

    pass

    ```

    3. Integrate in frontend (forecast-wizard/js/wizard-app.js):

    ```javascript

    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

  • Use async/await for I/O operations
  • Cache model selections when possible
  • Batch process multiple series
  • Optimize StatsForecast configuration
  • SQLite API

  • Use connection pooling
  • Implement caching for frequently accessed data
  • Optimize database queries
  • Use indexes for common queries
  • Frontend

  • Lazy load heavy components
  • Minimize API calls
  • Cache specification data
  • Use virtual scrolling for large datasets
  • Debugging

    Forecast Engine Debugging

    ```python

    Enable debug logging

    import logging

    logging.basicConfig(level=logging.DEBUG)

    Add debug prints

    logger.debug(f"Profiling result: {profile}")

    ```

    SQLite API Debugging

    ```bash

    Enable 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

    ```bash

    Build 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

    ```bash

    forecast-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

  • [StatsForecast Documentation](https://nixtla.github.io/statsforecast/)
  • [FastAPI Documentation](https://fastapi.tiangolo.com)
  • [SQLite Documentation](https://www.sqlite.org/docs.html)

  • Remember: PowerForecast is designed to be extensible. Follow the patterns above when adding new features, and maintain consistency with existing code style.