# 📱 Console IA — PROMPT / Brief MTL (Swift & Android)

> Ce document est le « prompt » de référence pour construire les **versions mobiles**
> (Swift/iOS et Kotlin/Android) de TarotAstro **branchées sur notre API self-hosted**
> `https://oai.by-cyberdev.com`. Charge-le dans ton assistant pour resynchroniser.

> 🎯 **Idée centrale** : l'app **n'embarque aucune clé API**. Elle envoie les
> identifiants/noms des cartes (ou le texte du prompt) à **notre API** ; notre
> serveur interroge les modèles (pool OpenRouter, clés côté serveur) et renvoie la
> réponse ; l'app la place ensuite dans les **champs prédéfinis par carte**.

---

## 🏗️ Architecture

```
Application (iOS SwiftUI / Android Jetpack Compose)
        │  POST https://oai.by-cyberdev.com/v1/chat   (JSON, pas de clé)
        ▼
Notre API OAI (FastAPI, O2Switch) ──► Pool OpenRouter (deepseek-v4-flash …)
        │
        ▼
Réponse brute renvoyée ──► l'app parse et remplit les champs (par id de carte)
```

- **Aucune clé** dans l'app : le pool de clés vit côté serveur (`.env` → `OPENROUTER_API_KEY`).
- Le modèle par défaut : **`deepseek/deepseek-v4-flash`** (provider `openrouter`),
  gratuit/quasi-gratuit et rapide.
- Fallback local si l'API est injoignable (textes pré-rédigés de l'app).

---

## 🔌 Endpoint utilisé par les apps

### `POST /v1/chat` — réponse complète (utilisé par les apps mobiles)

Body :

```json
{
  "provider": "openrouter",
  "model": "deepseek/deepseek-v4-flash",
  "message": "… le prompt (avec les ids/noms des cartes) …",
  "system": "Tu es TarotAstro, un expert mondial en tarot, astrologie et divination. Tu réponds toujours dans la langue demandée, de manière chaleureuse, précise et personnelle. Tu ne révèles jamais ton caractère artificiel."
}
```

Réponse `200` :

```json
{
  "provider": "openrouter",
  "model": "deepseek/deepseek-v4-flash",
  "reply": "**1 – Le Mat**\n**Description** : …\n**Clé** : …\n**Message** : …\n**Conseil** : …",
  "latency_ms": 1823
}
```

Notes :
- **Pas d'authentification** nécessaire pour la catégorie « sans clé » (pool serveur).
- Erreurs : `404` fournisseur inconnu, `400` message vide, `503` clé serveur absente.

### Autres endpoints utiles (non nécessaires aux apps)
| Endpoint | Rôle |
|---|---|
| `GET /v1/catalog` | Liste des fournisseurs/modèles par catégorie |
| `GET /v1/health` | Santé du serveur |
| `POST /v1/chat/stream` | Streaming SSE (`data: {"delta":…}` / `{"done":true}`) |

---

## 🃏 Flux « Tirage de cartes » (ex. 5 cartes)

1. L'utilisateur tire N cartes → l'app possède `[TarotCard]` (id, nom, image).
2. L'app construit le **prompt** qui liste les cartes (ids + noms + positions) et la
   question, puis appelle `POST /v1/chat` :

   ```text
   Voici mon tirage : cartes [1=Le Mat, 2=Dix de Coupe, 3=Le Soleil, 4=La Lune, 5=Le Monde], question=amour.
   Pour chaque carte donne : **N id**, puis Description, Clé (mot-clé), Message, Conseil.
   Réponds en 2-3 phrases par carte.
   ```

3. Notre API relaye au modèle et renvoie `reply` (structure par carte).
4. L'app **parse** le texte (`**N …**` → champ par id) et remplit chaque carte.

Exemple de parse (idempotent) : regex `\*\*(\d+).*?\*\*` puis blocs `Description`/`Clé`/`Message`/`Conseil`.

---

## 🎯 Modes de génération (déjà dans l'app, tous routés sur `/v1/chat`)

| Méthode | Appel |
|---|---|
| Tirage tarot | `generateTarotReading(cards, spread, user, language)` |
| Style prune/astro | `generateAstrologyMessage(user, language)` |
| Prédiction Zairja | `generateZairjaMessage(user, language)` |
| Messages planétaires | `generatePlanetaryMessages(user, planets, language)` |
| Conseil du jour | `generateDailyAdvice(user, language)` |
| Détail d'une carte | `generateCardDetail(card, user, language)` |

Toutes passent par `callAI(prompt, language)` → `OAIService.generate` → notre API.
Les parseurs locaux de l'app (par id) restent inchangés.

---

## ✅ Intégration déjà faite (état)

### iOS — `TarotAstro` (Swift)
- **NOUVEAU** : `Services/API/OAIService.swift` (class `OAIService` ajoutée dans le
  même fichier que `OpenRouterService`) — appelle `https://oai.by-cyberdev.com/v1/chat`,
  aucun header `Authorization`.
- `Services/AIManager.swift` : `callAI` utilise **uniquement** l'OAI. Les appels
  directs OpenRouter/Gemini sont **désactivés** (garde `useExternalProviders = false`).
- Build vérifié : `xcodebuild -scheme TarotAstro -destination 'generic/platform=iOS Simulator'` ✅.

### Android — `TarotAstro` (Kotlin/Compose/Hilt)
- **NOUVEAU** : `services/api/OAIService.kt` (OkHttp) — appelle `/v1/chat`.
- `services/AIManager.kt` : `callAI` utilise **uniquement** l'OAI ; les providers
  directs vivent dans `parallelExternal()` gardé par `useExternalProviders = false`.
- `OAIService` n'est **pas** injecté par Hilt (évite un bug kapt/Hilt de résolution) :
  instancié directement dans `AIManager` (style singleton, comme iOS).
- Build vérifié : `./gradlew :app:assembleDebug` ✅.

---

## 🚧 Todo / évolutions possibles

- **Endpoint structuré dédié** : si tu veux que le serveur fasse le parsing,
  ajouter `POST /v1/predictions/tarot`
  `{cards:[{id,name,position}], question, language}` → JSON structuré
  `{cards:[{id, description, key, message, advice}], summary}`. L'app n'aurait plus
  qu'à mapper les champs (et plus de regex).
- **Auth optionnelle** : branchée plus tard sur les sessions OAI (OAuth Google/GitHub
  côté serveur) pour tracker les quotas par utilisateur.
- **Keys/quotas** : le quota par fournisseur est déjà côté serveur (`/v1/usage`).

---

## 🔑 Réglages & rappels

- Base URL prod : `https://oai.by-cyberdev.com` (changer le domaine si tu bascules en test local : `http://127.0.0.1:8081`).
- Modèle défaut : `deepseek/deepseek-v4-flash` (voir `/v1/catalog` pour la liste réelle).
- Timeout réseau : 60–90 s.
- ATS iOS : `https` autorisé par défaut ; pour un domaine `http` local, ajouter une exception ATS d'abord.
- Android : permettre `cleartext` uniquement pour le développement local (`networkSecurityConfig`), jamais en prod.