Skip to content

Commit 80f3f8b

Browse files
committed
beta launch
1 parent 2490610 commit 80f3f8b

23 files changed

Lines changed: 545 additions & 108 deletions

.github/workflows/lint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: Lint
22

33
on:
44
push:
5-
branches: [main, develop, feat/**]
5+
branches: [main]
66
pull_request:
7-
branches: [main, develop]
7+
branches: [main]
88

99
jobs:
1010
ruff:

.github/workflows/test.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ name: Test
22

33
on:
44
push:
5-
branches: [main, develop, feat/**]
5+
branches: [main]
66
pull_request:
7-
branches: [main, develop]
7+
branches: [main]
88

99
jobs:
1010
test:
1111
name: Test Python ${{ matrix.python-version }}
1212
runs-on: ubuntu-latest
13+
if: false # Tests temporarily disabled
1314
strategy:
1415
fail-fast: false
1516
matrix:
@@ -49,6 +50,7 @@ jobs:
4950
test-examples:
5051
name: Test Examples
5152
runs-on: ubuntu-latest
53+
if: false # Tests temporarily disabled
5254
steps:
5355
- name: Checkout code
5456
uses: actions/checkout@v4
@@ -72,6 +74,7 @@ jobs:
7274
run: |
7375
python -c "import nbformat; nbformat.read('examples/flowstate_simple_example.ipynb', as_version=4)"
7476
python -c "import nbformat; nbformat.read('examples/model_comparison_example.ipynb', as_version=4)"
77+
python -c "import nbformat; nbformat.read('examples/model_comparison_simple.ipynb', as_version=4)"
7578
7679
- name: Verify eval package imports
7780
run: |

README.md

Lines changed: 74 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,25 @@ Production-ready Python SDK for FAIM (Foundation AI Models) - a high-performance
2323
pip install faim-sdk
2424
```
2525

26+
## Authentication
27+
28+
Get your free API key at **[https://faim.it.com/](https://faim.it.com/)**
29+
30+
```python
31+
from faim_sdk import ForecastClient
32+
33+
# Initialize client with your API key
34+
client = ForecastClient(api_key="your-api-key")
35+
```
36+
2637
## Quick Start
2738

2839
```python
2940
import numpy as np
3041
from faim_sdk import ForecastClient, Chronos2ForecastRequest
3142

32-
# Initialize client with your API endpoint
33-
client = ForecastClient(
34-
base_url="https://api.faim.example.com",
35-
api_key="your-api-key", # Optional: for authenticated endpoints
36-
timeout=120.0
37-
)
43+
# Initialize client
44+
client = ForecastClient(api_key="your-api-key")
3845

3946
# Prepare your time-series data
4047
# Shape: (batch_size, sequence_length, features)
@@ -52,16 +59,70 @@ request = Chronos2ForecastRequest(
5259
response = client.forecast(request)
5360

5461
# Access predictions
55-
print(response.quantiles.shape) # (32, 24, 3)
62+
print(response.quantiles.shape) # (32, 24, 3, 1)
5663
print(response.metadata) # Model version, inference time, etc.
5764
```
5865

66+
## Input/Output Format
67+
68+
### Input Data Format
69+
70+
**All models require 3D input arrays:**
71+
72+
```python
73+
# Shape: (batch_size, sequence_length, features)
74+
x = np.array([
75+
[[1.0], [2.0], [3.0]], # Series 1
76+
[[4.0], [5.0], [6.0]] # Series 2
77+
]) # Shape: (2, 3, 1)
78+
```
79+
80+
- **batch_size**: Number of independent time series
81+
- **sequence_length**: Historical data points (context window)
82+
- **features**: Number of variables per time step (use 1 for univariate)
83+
84+
**Important**: 2D input will raise a validation error. Always provide 3D arrays.
85+
86+
### Output Data Format
87+
88+
**Point Forecasts** (3D):
89+
```python
90+
response.point # Shape: (batch_size, horizon, features)
91+
```
92+
93+
**Quantile Forecasts** (4D):
94+
```python
95+
response.quantiles # Shape: (batch_size, horizon, num_quantiles, features)
96+
# Example: (32, 24, 5, 1) = 32 series, 24 steps ahead, 5 quantiles, 1 feature
97+
```
98+
99+
### Univariate vs Multivariate
100+
101+
- **Chronos2**: ✅ Supports multivariate forecasting (multiple features)
102+
- **FlowState**: ⚠️ Univariate only - automatically transforms multivariate input
103+
- **TiRex**: ⚠️ Univariate only - automatically transforms multivariate input
104+
105+
When you provide multivariate input (features > 1) to FlowState or TiRex, the SDK automatically:
106+
1. Issues a warning
107+
2. Forecasts each feature independently
108+
3. Reshapes the output back to your original structure
109+
110+
```python
111+
# Multivariate input to FlowState
112+
data = np.random.randn(2, 100, 3) # 2 series, 3 features
113+
request = FlowStateForecastRequest(x=data, horizon=24, prediction_type="mean")
114+
115+
# Warning: "FlowState model only supports univariate forecasting..."
116+
response = client.forecast(request)
117+
118+
# Output is automatically reshaped
119+
print(response.point.shape) # (2, 24, 3) - original structure preserved
120+
```
121+
59122
## Available Models
60123

61124
### FlowState
62125

63-
Optimized for **deterministic point forecasts** with optional scaling and normalization.
64-
65126
```python
66127
from faim_sdk import FlowStateForecastRequest
67128

@@ -70,7 +131,7 @@ request = FlowStateForecastRequest(
70131
horizon=24,
71132
model_version="latest",
72133
output_type="point",
73-
scale_factor=1.0, # Optional: normalization factor
134+
scale_factor=1.0, # Optional: normalization factor, for details check: https://huggingface.co/ibm-granite/granite-timeseries-flowstate-r1
74135
prediction_type="mean" # Options: "mean", "median"
75136
)
76137

@@ -80,8 +141,6 @@ print(response.point.shape) # (batch_size, 24, features)
80141

81142
### Chronos 2.0
82143

83-
Amazon's **large language model for time series** - ideal for probabilistic forecasting with quantiles.
84-
85144
```python
86145
from faim_sdk import Chronos2ForecastRequest
87146

@@ -99,8 +158,6 @@ print(response.quantiles.shape) # (batch_size, 24, 5)
99158

100159
### TiRex
101160

102-
**Transformer-based forecasting** model for efficient and accurate predictions.
103-
104161
```python
105162
from faim_sdk import TiRexForecastRequest
106163

@@ -253,7 +310,7 @@ from faim_sdk import ForecastClient, Chronos2ForecastRequest
253310
from faim_sdk.eval import mse, mase, crps_from_quantiles, plot_forecast
254311

255312
# Initialize client
256-
client = ForecastClient(base_url="https://api.faim.example.com")
313+
client = ForecastClient()
257314

258315
# Prepare data splits
259316
train_data = np.random.randn(32, 100, 1)
@@ -378,7 +435,6 @@ from faim_sdk import ForecastClient, Chronos2ForecastRequest
378435

379436
async def forecast_multiple_series():
380437
client = ForecastClient(
381-
base_url="https://api.faim.example.com",
382438
api_key="your-api-key"
383439
)
384440

@@ -412,14 +468,12 @@ from faim_sdk import ForecastClient
412468

413469
# Basic configuration
414470
client = ForecastClient(
415-
base_url="https://api.faim.example.com",
416471
timeout=120.0, # Request timeout in seconds (default: 120)
417472
verify_ssl=True, # SSL certificate verification (default: True)
418473
)
419474

420475
# With API key authentication
421476
client = ForecastClient(
422-
base_url="https://api.faim.example.com",
423477
api_key="your-secret-api-key",
424478
timeout=120.0
425479
)
@@ -428,7 +482,6 @@ client = ForecastClient(
428482
import httpx
429483

430484
client = ForecastClient(
431-
base_url="https://api.faim.example.com",
432485
api_key="your-api-key",
433486
timeout=120.0,
434487
limits=httpx.Limits(max_connections=10), # Connection pooling
@@ -460,14 +513,14 @@ Use context managers for automatic resource cleanup:
460513

461514
```python
462515
# Sync context manager
463-
with ForecastClient(base_url="https://api.faim.example.com") as client:
516+
with ForecastClient() as client:
464517
request = Chronos2ForecastRequest(x=data, horizon=24, quantiles=[0.1, 0.5, 0.9])
465518
response = client.forecast(request)
466519
print(response.quantiles)
467520
# Client automatically closed
468521

469522
# Async context manager
470-
async with ForecastClient(base_url="https://api.faim.example.com") as client:
523+
async with ForecastClient() as client:
471524
request = Chronos2ForecastRequest(x=data, horizon=24, quantiles=[0.1, 0.9])
472525
response = await client.forecast_async(request)
473526
print(response.quantiles)

examples/generate_data.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
for testing and demonstrating forecasting capabilities.
66
"""
77

8+
89
import numpy as np
9-
from typing import Tuple
1010

1111

1212
def generate_linear_trend_series(
@@ -243,21 +243,21 @@ def generate_test_suite(seed: int = 42) -> dict[str, np.ndarray]:
243243
# Test linear trend series
244244
linear_data = generate_linear_trend_series(batch_size=5, context_length=100, seed=42)
245245
print(f"Linear trend series shape: {linear_data.shape}")
246-
print(f" Expected: (5, 100, 1)")
246+
print(" Expected: (5, 100, 1)")
247247
print(f" Min: {linear_data.min():.2f}, Max: {linear_data.max():.2f}, Mean: {linear_data.mean():.2f}\n")
248248

249249
# Test correlated multi-series
250250
multi_data = generate_correlated_multi_series(batch_size=3, context_length=100, seed=42)
251251
print(f"Correlated multi-series shape: {multi_data.shape}")
252-
print(f" Expected: (3, 100, 2)")
252+
print(" Expected: (3, 100, 2)")
253253
# Calculate correlation between the two series
254254
corr = np.corrcoef(multi_data[0, :, 0], multi_data[0, :, 1])[0, 1]
255255
print(f" Correlation between series: {corr:.2f}\n")
256256

257257
# Test heavy payload
258258
heavy_data = generate_heavy_payload(batch_size=100, context_length=2048, seed=42)
259259
print(f"Heavy payload shape: {heavy_data.shape}")
260-
print(f" Expected: (100, 2048, 1)")
260+
print(" Expected: (100, 2048, 1)")
261261
print(f" Memory size: {heavy_data.nbytes / 1024 / 1024:.2f} MB\n")
262262

263263
# Generate full test suite

0 commit comments

Comments
 (0)