Metadata-Version: 2.4
Name: aiforge-esprit
Version: 0.1.2
Summary: SDK Python officiel d'AI Forge ESPRIT — un enrobage fin du SDK OpenAI.
Author: Direction IA - ESPRIT
License-Expression: MIT
Project-URL: Homepage, https://aiforge.esprit.tn
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: openai>=1.40
Requires-Dist: pydantic>=2

# aiforge-esprit

*The official Python SDK for AI Forge ESPRIT — a thin wrapper around the OpenAI SDK.*

`aiforge-esprit` enrobe le SDK OpenAI officiel : il ne réimplémente jamais le
HTTP, il ajoute juste quatre macros et la facturation en TND.

## Installation

```bash
pip install aiforge-esprit
```

Le paquet s'installe sous **`aiforge-esprit`** mais s'importe sous **`aiforge`** :
`from aiforge import AIForge`. (Le nom `aiforge` seul était indisponible sur PyPI.)

## Démarrage rapide

```python
from aiforge import AIForge

af = AIForge()                       # clé depuis AIFORGE_API_KEY
print(af.chat("Explique les transformers en 2 phrases."))
print(af.code("Écris un quicksort en Python"))
print(af.balance())
```

La clé vient de l'argument `api_key=` ou de la variable `AIFORGE_API_KEY`.
L'URL vient de `base_url=` ou de `AIFORGE_BASE_URL` (défaut :
`https://aiforge.esprit.tn/api/v1`).

## Les trois niveaux de contrôle du modèle

| Niveau | Exemple | Coût de routage |
|---|---|---|
| **Nom exact** | `chat(..., model="Qwen3.6-27B")` | aucun |
| **Alias statique** | `chat(..., model="coder")` | aucun |
| **`auto`** (défaut) | `chat(...)` | un appel classifieur |

En `auto`, un classifieur choisit le spécialiste selon la demande (et route vers
le modèle vision si une image est présente). Le champ `model` de la réponse porte
toujours le **modèle réellement utilisé**.

### Alias

| Alias | Modèle |
|---|---|
| `fast` | SmolLM3-3B |
| `smart` | Qwen3.6-27B |
| `coder` | Qwen3.6-35B-A3B |
| `vision` | Qwen3.6-35B-A3B |

## Les 4 macros

```python
af.chat(prompt, model="auto", system=None, max_tokens=2000, stream=False)  # -> str (ou générateur si stream=True)
af.code(prompt)                        # chat model="coder", max_tokens=3000
af.extract(text, schema)               # schema = classe pydantic ou dict json-schema -> instance validée
af.vision(image, prompt)               # image = chemin local, bytes ou URL http(s)
af.balance()                           # -> {"balanceTND", "monthlyBudgetTND", "currency"}
```

Pour `extract`, le schéma garantit la forme ; le system prompt intégré impose la
concision (valeurs seules, sans phrases) ; pour des extractions complexes,
préférez `model="smart"`. `extract()` tourne à `temperature=0` par défaut
(déterminisme : même texte → même sortie structurée) ; passez `temperature=...`
pour introduire de la variance.

Avec `AIForge(verbose=True)`, chaque appel imprime une ligne :
`-> {modèle final} · {prompt}+{completion} tokens · {coût} TND`.

## Modèles à raisonnement (smart, coder)

`Qwen3.6-27B` et `Qwen3.6-35B-A3B` **réfléchissent avant de répondre** : la
réflexion arrive dans le champ `reasoning` de la réponse (nom vLLM 0.25). Un
`max_tokens` trop bas peut être entièrement consommé par la réflexion — le SDK
lève alors une erreur claire. **Utilisez `max_tokens >= 1500` pour `smart` et
`coder`.**

## Note de facturation

En mode `auto`, le coût du **classifieur** est imputé côté serveur (une ligne
d'usage distincte) mais **n'apparaît pas dans la réponse** — la ligne `verbose`
n'affiche donc que le coût du modèle final. Consultez la page Usage pour le
détail complet.

## Licence

MIT — Direction IA - ESPRIT.
