Skip to content

Bibliothèque Python

sh
pip install spavik            # avec pandas : pip install "spavik[pandas]"
python
from spavik import Spavik

spavik = Spavik()                                   # lit SPAVIK_API_KEY
model  = spavik.train("churn.csv", target="churn")  # gratuit
print(model.predict({"plan": "pro", "seats": 12}))

Deux choses à savoir avant le premier appel : votre clé, et le nom de la colonne à prédire. Le reste, la bibliothèque s'en occupe.

Les opérations

Celles qui portent un identifiant de modèle vivent sur l'objet Model, pour que personne n'ait à recopier un mdl_... à la main.

AppelCoût
spavik.validate(data, target=...)gratuit
spavik.train(data, target=...)gratuit
spavik.backtest(data, target=..., horizon=...)gratuit
spavik.forecast(data, target=..., horizon=...)horizon x séries
spavik.models()gratuit
spavik.usage()gratuit
model.predict(rows)les crédits du moteur par ligne, 1 sur le moteur par défaut
model.submit_outcomes(outcomes)gratuit
model.performance(days=30)gratuit
model.refresh()gratuit
model.predictions(limit=50)gratuit
model.archive(), spavik.archive(model_id)gratuit
spavik.restore(model_id)gratuit

models() est un itérateur : la pagination se fait toute seule. Un modèle connaît son engine, sa target et ses features, les colonnes que predict attend.

Vérifier avant d'entraîner, ou avant de payer

validate() rend ce que l'entraînement dirait d'une table, plus un essai du moteur qui ne conserve rien : un verdict et la première chose à corriger. backtest() fait de même pour une série, en rejouant son historique face à la simple répétition de la dernière période, sans rendre de prévision. Les deux sont gratuits.

python
rapport = spavik.validate("churn.csv", target="churn")
rapport["trial"]["verdict"]       # {'level': 'usable', 'message': 'Accuracy of 0.83, against 0.50 for the majority class.'}
rapport["hint"]                   # la première chose à corriger, ou None

essai = spavik.backtest("ventes.csv", target="ventes", horizon=7)
essai["backtest"]["verdict"]      # {'level': 'no_signal', 'message': '...'}
essai["backtest"]["by_window"]    # une note par période rejouée

weak sur une validation veut dire que la note est trop belle : une colonne est probablement remplie après l'événement que vous prédisez. Retirez-la plutôt que d'entraîner.

Archiver et restaurer

Les plans limitent le nombre de modèles actifs. archive() arrête un modèle et libère sa place ; tout est conservé, et spavik.restore(model_id) le remet en service. La restauration prend l'identifiant, pas le modèle : un modèle archivé ne se lit pas avec model(), l'API répond MODEL_ARCHIVED.

python
model.archive()
for m in spavik.models(status="archived"):
    print(m.id, m.name)
spavik.restore(model.id)

La suppression définitive n'est pas dans la bibliothèque.

Vos données, telles qu'elles sont

Vous n'avez rien à convertir. train, predict et forecast acceptent indifféremment :

python
spavik.train(df, target="churn")                  # un DataFrame pandas
spavik.train("data/churn.csv", target="churn")    # un chemin de fichier
spavik.train([{"plan": "pro", "churn": 0}], ...)  # une liste de dictionnaires

CSV ou JSON, séparé par des virgules ou des points-virgules, avec ou sans guillemets : la bibliothèque s'adapte, et rend aux nombres leur type au passage.

Ce qui est refusé avant d'être envoyé

La bibliothèque a vos données sous la main, l'API pas encore. Quatre refus sont donc prononcés sur votre machine, sans appel réseau et sans rien dépenser.

python
spavik.train(huit_lignes, target="churn")
# SpavikDataError: training needs at least 10 rows, 8 provided. Nothing was sent.

spavik.train(df, target="churn_90d")
# SpavikDataError: the target column 'churn_90d' is missing from the data.
#                  Columns found: plan, seats, tickets_90d, churn. Did you mean 'churn'?

spavik.forecast(trois_points, target="ventes", horizon=14)
# SpavikDataError: the series has 3 point(s) for a horizon of 14. A series shorter
#                  than its horizon yields nothing usable: provide at least 14 points,
#                  preferably several times more.

model.submit_outcomes([{"request_id": "...", "outcome": 1}])
# SpavikDataError: 1 outcome(s) out of 1 have no 'actual' field, the value actually
#                  observed. Fields found on the first: request_id, outcome.

Les messages sont en anglais, la langue de l'API, et identiques mot pour mot dans la bibliothèque JavaScript : une suite de conformité rejoue le même scénario sur les deux, et sur le serveur MCP.

Les erreurs

Une classe par famille, portant chacune le code machine, le détail renvoyé par l'API, le statut HTTP et le request_id. C'est ce dernier qu'il faut citer si vous ouvrez un ticket.

python
from spavik import SpavikCreditsExhausted

try:
    model.predict(rows)
except SpavikCreditsExhausted as exc:
    print(exc.code, exc.balance, exc.request_id)
ClasseDans quel cas
SpavikDataErrorrefus prononcé en local, rien n'a été envoyé
SpavikAuthErrorclé absente, invalide, ou insuffisante pour la route
SpavikCreditsExhaustedsolde trop bas, porte balance et required
SpavikValidationErrorl'API refuse la requête telle qu'elle est formée
SpavikNotFoundla ressource n'existe pas dans ce workspace
SpavikConflictrejeu, traitement déjà en cours, rien à intégrer
SpavikRateLimitedtrop d'appels sur une courte période
SpavikUnavailableune dépendance manque ou sort de veille
SpavikTransportErrorpanne réseau, ou réponse qui n'est pas du JSON

Des états normaux, pas des erreurs

model.refresh() renvoie None lorsqu'il n'y a rien à intégrer, et model.performance() renvoie None lorsque le journal analytique n'est pas en place. Ni l'un ni l'autre ne vous oblige à écrire un bloc try.

En asynchrone

Mêmes noms, mêmes refus, mêmes résultats.

python
from spavik import AsyncSpavik

async with AsyncSpavik() as spavik:
    model = await spavik.train("churn.csv", target="churn")
    print(await model.predict(rows))

Les tentatives suivantes

Uniquement sur les erreurs qui peuvent changer d'avis : 429, 5xx et pannes réseau. Jamais sur une 4xx. La clé d'idempotence est rejouée à l'identique, donc une nouvelle tentative ne facture pas une seconde fois.

python
Spavik(max_retries=1)                    # aucune nouvelle tentative
Spavik(backoff=lambda n: n * 1.0)        # attente linéaire

Webhooks

python
from spavik.webhooks import verifier

evenement = verifier(request.body, request.headers, secret)

Passez les octets reçus tels quels : un corps analysé puis réécrit ne produit plus la même signature.

Comprendre ce qui se passe

sh
SPAVIK_LOG=debug python mon_script.py
spavik POST /v1/models  idem=a3f1b2c4  15.81s  201  req_atZusk...  cle=sk-spv-api-bm7...Tr9x

La clé est masquée dans la trace.

Délais d'attente par défaut

OpérationDélai
train, refresh120 s
forecast60 s
backtest60 s
validate120 s
predict, submit_outcomes, performance30 s
models, usage, predictions15 s

Ces délais sont larges à dessein : un entraînement demande une quinzaine de secondes, et le moteur met une dizaine de secondes à répondre lorsqu'il sort de veille.

Documentation générée pour partie depuis le contrat OpenAPI.