use-case complet “voix → CRM Odoo
Parfait. Voici un use-case complet “voix → CRM Odoo” avec les endpoints, payloads, et un exemple React.
1) Scénario utilisateur (Hello World)
- L’utilisateur dicte : « Je m’appelle Lina Andrianina, mon email lina@exemple.com, mon téléphone +261 32 12 34 567. »
- La WebApp React enregistre la voix (WebRTC) → envoie l’audio à Whisper (STT) → récupère le texte.
- Un prompt/outil d’extraction (OpenAI “function-calling” ou petit parseur) produit un JSON propre :
{ "firstname": "Lina", "lastname": "Andrianina", "email": "lina@exemple.com", "phone": "+261321234567" }
- La WebApp fait un PUT (create) vers Odoo CRM pour créer le contact (res.partner) et/ou un lead (crm.lead).
- L’utilisateur demande : « Liste les contacts » → la WebApp fait un GET (search_read) et affiche.
2) Odoo (v16/v17+) – JSON-RPC standard
Base URL (exemple) : https://votre-odoo.com
2.1 Authentification
Endpoint: /web/session/authenticate
Méthode: POST (JSON)
Payload:
{ "jsonrpc": "2.0", "method": "call", "params": { "db": "NOM_DE_LA_BASE", "login": "API_USER", "password": "API_PASSWORD" }, "id": 1 }
Réponse: contient session_id + uid. Conservez le cookie session_id pour les appels suivants.
2.2 CREATE contact (res.partner)
Endpoint: /web/dataset/call_kw
Méthode: POST (JSON)
Payload:
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "res.partner", "method": "create", "args": [{ "name": "Lina Andrianina", "email": "lina@exemple.com", "phone": "+261321234567", "mobile": "+261321234567", "type": "contact", "is_company": false }], "kwargs": {} }, "id": 2 }
Retour: l’id du partenaire créé (ex. 45).
2.3 CREATE lead (crm.lead) – optionnel
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "crm.lead", "method": "create", "args": [{ "name": "Nouveau prospect via voix", "partner_id": 45, // id du res.partner créé "contact_name": "Lina Andrianina", "email_from": "lina@exemple.com", "phone": "+261321234567", "description": "Capté par interface vocale" }], "kwargs": {} }, "id": 3 }
2.4 GET – lister des contacts (search_read)
{ "jsonrpc": "2.0", "method": "call", "params": { "model": "res.partner", "method": "search_read", "args": [ [["active","=",true]], ["id","name","email","phone","mobile"] ], "kwargs": {"limit": 20, "order": "id desc"} }, "id": 4 }
Même principe pour crm.lead si vous voulez lister les leads.
3) Whisper STT (exemple minimal)
Upload audio → texte (pseudo-cURL) :
curl -X POST https://api.openai.com/v1/audio/transcriptions \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-Type: multipart/form-data" \ -F "file=@enregistrement.webm" \ -F "model=whisper-1"
Réponse: { "text": "Je m’appelle Lina Andrianina, mon email ..." }
4) Extraction structurée (RAG / LLM function-calling)
Objectif: transformer le texte brut en JSON propre (nom, email, téléphone).
Ex. schéma de fonction :
{ "name": "capture_contact", "parameters": { "type": "object", "properties": { "firstname": {"type": "string"}, "lastname": {"type": "string"}, "email": {"type": "string"}, "phone": {"type": "string"} }, "required": ["firstname","lastname"] } }
Le modèle renvoie l’objet à poster vers Odoo.
5) Extrait de code (React/TypeScript, ultra-simple)
// util/jsonrpc.ts export async function odooCall<T>( endpoint: string, payload: any, sessionCookie?: string ): Promise<T> { const res = await fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json", ...(sessionCookie ? { "Cookie": sessionCookie } : {}) }, body: JSON.stringify(payload), credentials: "include" }); const data = await res.json(); if (data.error) throw new Error(JSON.stringify(data.error)); return data.result; }
// api/odoo.ts const BASE = "https://votre-odoo.com"; export async function odooLogin(db: string, login: string, password: string) { return odooCall(`${BASE}/web/session/authenticate`, { jsonrpc: "2.0", method: "call", params: { db, login, password }, id: 1 }); } export async function createPartner(p: { name: string; email?: string; phone?: string; mobile?: string; }) { return odooCall(`${BASE}/web/dataset/call_kw`, { jsonrpc: "2.0", method: "call", params: { model: "res.partner", method: "create", args: [p], kwargs: {} }, id: 2 }); } export async function listPartners(limit = 20) { return odooCall(`${BASE}/web/dataset/call_kw`, { jsonrpc: "2.0", method: "call", params: { model: "res.partner", method: "search_read", args: [[["active","=",true]], ["id","name","email","phone","mobile"]], kwargs: { limit, order: "id desc" } }, id: 3 }); }
// usage (après STT + extraction JSON) const contact = { name: `${firstname} ${lastname}`, email, phone, mobile: phone }; await odooLogin("NOM_DE_LA_BASE","API_USER","API_PASSWORD"); const partnerId = await createPartner(contact); // PUT const partners = await listPartners(10); // GET
6) Mappage de données recommandé
- name → firstname + " " + lastname
- email → email
- phone → numéro principal (fixe ou mobile)
- mobile → dupliquez phone si mobile
- Option : créer d’abord res.partner, puis lier crm.lead.partner_id.
7) Contrôles & erreurs à prévoir
- Déduplication : cherchez d’abord un partner par email/phone (search) pour éviter les doublons.
- Validation email/téléphone côté front avant le POST.
- RGPD : loguer le consentement WhatsApp/SMS si vous l’ajoutez.
- Timeout/réessais : réseau mobile, latence STT.
Souhaitez-vous que je vous génère un petit module Odoo (XML + Python) ajoutant un champ “Consentement WhatsApp” côté res.partner + un exemple de vue et les appels JSON-RPC correspondants ?