docuresume-backend / API_ENDPOINTS_CLOUD.md
K2MAR's picture
docs: Update API documentation v2.0 - FAISS + Gemini
4929780
# 📡 API DocuResume Pro - Endpoints Cloud (Hugging Face)
**Base URL:** `https://k2mar-docuresume-backend.hf.space`
**Version:** 2.0.0
**Déployé sur:** Hugging Face Spaces
**Status:** ✅ Production
**Mis à jour:** 27 janvier 2026
**Nouvelles fonctionnalités:**
- ✅ FAISS activé (recherche sémantique)
- ✅ Gemini API intégrée (résumés et Q&A intelligents)
- ✅ 22 endpoints disponibles
---
## 📚 Table des matières
1. [Authentification](#-authentification) - Register, Login
2. [Gestion des Documents](#-gestion-des-documents) - Upload, Liste, Contenu
3. [Résumés](#-résumés) - Sauvegarde et historique
4. [Recherche FAISS](#-recherche-sémantique-faiss) - Recherche sémantique
5. [IA Générative (Gemini)](#-ia-générative-gemini-api) - Résumés et Q&A
6. [Analytics](#-analytics--stats) - Statistiques utilisateur
7. [Système](#-système) - Health check
---
## 🔐 Authentification
### 1. **POST** `/users/register`
Créer un nouveau compte utilisateur.
**Request Body:**
```json
{
"email": "user@example.com",
"username": "johndoe",
"password": "securepassword123"
}
```
**Response 200:**
```json
{
"message": "Utilisateur créé avec succès",
"user_id": "uuid-v4",
"email": "user@example.com",
"username": "johndoe"
}
```
**Errors:**
- `400`: Email ou username déjà utilisé
- `500`: Erreur serveur
**Exemple cURL:**
```bash
curl -X POST https://k2mar-docuresume-backend.hf.space/users/register \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","username":"testuser","password":"test123"}'
```
---
### 2. **POST** `/users/login`
Connexion utilisateur existant.
**Request Body:**
```json
{
"email": "user@example.com",
"password": "securepassword123"
}
```
**Response 200:**
```json
{
"message": "Connexion réussie",
"user_id": "uuid-v4",
"email": "user@example.com",
"username": "johndoe"
}
```
**Errors:**
- `401`: Email ou mot de passe incorrect
- `500`: Erreur serveur
**Exemple cURL:**
```bash
curl -X POST https://k2mar-docuresume-backend.hf.space/users/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"test123"}'
```
---
## 📄 Gestion des Documents
### 3. **POST** `/documents/upload`
Upload un document PDF avec extraction OCR automatique.
**Content-Type:** `multipart/form-data`
**Form Fields:**
- `file`: PDF file (required)
- `user_id`: UUID de l'utilisateur (required)
- `tags`: JSON array de tags (optional, default: `[]`)
- `document_type`: Type de document (optional)
**Response 200:**
```json
{
"message": "Document uploadé avec succès",
"document_id": "uuid-v4",
"filename": "uuid_original.pdf",
"status": "completed",
"pages": 5,
"text_length": 3450,
"faiss_indexed": false,
"chunks": 0
}
```
**Exemple cURL:**
```bash
curl -X POST https://k2mar-docuresume-backend.hf.space/documents/upload \
-F "file=@document.pdf" \
-F "user_id=your-user-id" \
-F "tags=[]"
```
**Exemple JavaScript (Fetch):**
```javascript
const formData = new FormData()
formData.append('file', pdfFile)
formData.append('user_id', userId)
formData.append('tags', JSON.stringify(['important', 'work']))
const response = await fetch('https://k2mar-docuresume-backend.hf.space/documents/upload', {
method: 'POST',
body: formData
})
const data = await response.json()
```
**Exemple Kotlin (Android):**
```kotlin
val file = File(filePath)
val requestFile = file.asRequestBody("application/pdf".toMediaType())
val filePart = MultipartBody.Part.createFormData("file", file.name, requestFile)
val userIdBody = user_id.toRequestBody("text/plain".toMediaType())
val response = apiService.uploadDocument(userIdBody, filePart)
```
---
### 4. **GET** `/documents/user/{user_id}`
Récupérer tous les documents d'un utilisateur.
**Query Parameters:**
- `limit`: Nombre max de documents (default: 100)
- `archived`: Inclure archives (default: false)
**Response 200:**
```json
{
"documents": [
{
"id": "uuid-v4",
"user_id": "uuid-v4",
"filename": "uuid_document.pdf",
"original_filename": "Mon Document.pdf",
"file_size": 245780,
"page_count": 5,
"processing_status": "completed",
"uploaded_at": "2026-01-27T10:30:00",
"mime_type": "application/pdf",
"tags": ["important"],
"is_archived": false
}
],
"count": 1
}
```
**Exemple cURL:**
```bash
curl https://k2mar-docuresume-backend.hf.space/documents/user/YOUR_USER_ID?limit=50
```
---
### 5. **GET** `/documents/{document_id}`
Récupérer les détails d'un document spécifique.
**Response 200:**
```json
{
"id": "uuid-v4",
"user_id": "uuid-v4",
"filename": "uuid_document.pdf",
"original_filename": "Mon Document.pdf",
"file_path": "user_id/uuid_document.pdf",
"file_size": 245780,
"page_count": 5,
"processing_status": "completed",
"contenu": "Texte extrait du PDF...",
"uploaded_at": "2026-01-27T10:30:00",
"mime_type": "application/pdf",
"tags": ["important"]
}
```
**Exemple cURL:**
```bash
curl https://k2mar-docuresume-backend.hf.space/documents/DOCUMENT_ID
```
---
### 6. **GET** `/documents/{document_id}/content`
Récupérer le contenu textuel extrait d'un document (pour résumé local).
**Response 200:**
```json
{
"document_id": "uuid-v4",
"filename": "Mon Document.pdf",
"content": "Texte extrait complet du document...",
"page_count": 5,
"file_size": 245780,
"content_length": 3450
}
```
**Usage:**
- **Option 1 (Recommandé):** Utiliser `/generate/summary/gemini` pour un résumé cloud avec Gemini API
- **Option 2:** Récupérer le contenu et générer un résumé localement sur le device avec TinyLlama (si implémenté)
**Exemple cURL:**
```bash
curl https://k2mar-docuresume-backend.hf.space/documents/DOCUMENT_ID/content
```
---
### 7. **GET** `/documents/user/{user_id}/contents`
Récupérer le contenu de TOUS les documents d'un utilisateur (pour résumé global).
**Query Parameters:**
- `limit`: Nombre max de documents (default: 100)
- `include_content`: Inclure le contenu textuel (default: true)
**Response 200:**
```json
{
"user_id": "uuid-v4",
"documents": [
{
"document_id": "uuid-v4",
"filename": "Document1.pdf",
"content": "Texte du document 1...",
"content_length": 2340,
"page_count": 3,
"file_size": 156000,
"uploaded_at": "2026-01-27T10:30:00",
"processing_status": "completed"
},
{
"document_id": "uuid-v4-2",
"filename": "Document2.pdf",
"content": "Texte du document 2...",
"content_length": 3450,
"page_count": 5,
"file_size": 245780,
"uploaded_at": "2026-01-27T11:00:00",
"processing_status": "completed"
}
],
"count": 2,
"total_content_length": 5790
}
```
**Usage:** Utiliser ce endpoint pour générer un **résumé global on-device** de tous les documents.
**Exemple cURL:**
```bash
curl https://k2mar-docuresume-backend.hf.space/documents/user/YOUR_USER_ID/contents
```
---
### 8. **GET** `/documents/{document_id}/download`
Télécharger le fichier PDF original.
**Response:** Binary PDF file with `Content-Disposition: attachment`
**Exemple cURL:**
```bash
curl -O https://k2mar-docuresume-backend.hf.space/documents/DOCUMENT_ID/download
```
---
### 9. **PATCH** `/documents/{document_id}`
Mettre à jour un document (tags, archived, etc.).
**Request Body:**
```json
{
"tags": ["nouveau", "tag"],
"is_archived": true
}
```
**Response 200:**
```json
{
"message": "Document mis à jour",
"document_id": "uuid-v4"
}
```
---
### 10. **DELETE** `/documents/{document_id}`
Supprimer un document (cascade: chunks, embeddings, summaries).
**Response 200:**
```json
{
"message": "Document supprimé",
"document_id": "uuid-v4"
}
```
---
## 📝 Résumés
### 11. **POST** `/documents/{document_id}/summaries`
Sauvegarder un résumé généré **localement sur le device**.
**Request Body:**
```json
{
"content": "Résumé généré par TinyLlama...",
"summary_type": "abstractive",
"summary_level": "medium",
"model_name": "TinyLlama-1.1B",
"model_version": "Q4_K_M",
"compression_ratio": 0.15,
"rouge_1_score": 0.42,
"rouge_2_score": 0.28,
"rouge_l_score": 0.35
}
```
**Response 200:**
```json
{
"message": "Résumé créé avec succès",
"summary_id": "uuid-v4",
"document_id": "uuid-v4",
"summary_type": "abstractive",
"created_at": "2026-01-27T12:00:00"
}
```
---
### 12. **POST** `/summaries/batch`
Créer plusieurs résumés en batch (après génération locale multi-documents).
**Request Body:**
```json
[
{
"document_id": "uuid-v4-1",
"content": "Résumé document 1...",
"summary_type": "abstractive",
"model_name": "TinyLlama-1.1B"
},
{
"document_id": "uuid-v4-2",
"content": "Résumé document 2...",
"summary_type": "abstractive",
"model_name": "TinyLlama-1.1B"
}
]
```
**Response 200:**
```json
{
"message": "2 résumés créés avec succès",
"count": 2,
"summary_ids": ["uuid-v4-a", "uuid-v4-b"]
}
```
---
### 13. **GET** `/documents/{document_id}/summaries`
Récupérer les résumés d'un document.
**Query Parameters:**
- `summary_type`: Filtrer par type (optional: `extractive`, `abstractive`)
**Response 200:**
```json
{
"document_id": "uuid-v4",
"summaries": [
{
"id": "uuid-v4",
"document_id": "uuid-v4",
"content": "Résumé du document...",
"summary_type": "abstractive",
"summary_level": "medium",
"model_name": "TinyLlama-1.1B",
"created_at": "2026-01-27T12:00:00",
"compression_ratio": 0.15
}
],
"count": 1
}
```
---
### 14. **GET** `/summaries/user/{user_id}`
Récupérer tous les résumés d'un utilisateur.
**Query Parameters:**
- `limit`: Nombre max de résumés (default: 50)
- `summary_type`: Filtrer par type (optional)
**Response 200:**
```json
{
"user_id": "uuid-v4",
"summaries": [
{
"id": "uuid-v4",
"document_id": "uuid-v4",
"content": "Résumé...",
"summary_type": "abstractive",
"documents": {
"original_filename": "Document.pdf"
},
"created_at": "2026-01-27T12:00:00"
}
],
"count": 1
}
```
---
## 🔍 Recherche Sémantique (FAISS)
**FAISS activé sur le cloud** (`ENABLE_FAISS=true`)
### 15. **POST** `/search/semantic`
Recherche sémantique dans un document avec FAISS.
**Query Parameters:**
- `document_id` (string, required): UUID du document
- `query` (string, required): Texte de recherche
- `k` (int, optional): Nombre de résultats (défaut: 5)
**Response 200:**
```json
{
"document_id": "555eb078-b49b-4cea-bb8a-2139358b5f42",
"query": "invoice date",
"results": [
{
"text": "Due: Dec 16, 2025...",
"score": 0.44012526606025987,
"chunk_id": 1
},
{
"text": "GitHub Student Organization...",
"score": 0.41195771365111133,
"chunk_id": 0
}
],
"count": 2
}
```
**Exemple cURL:**
```bash
curl -X POST "https://k2mar-docuresume-backend.hf.space/search/semantic?document_id=555eb078-b49b-4cea-bb8a-2139358b5f42&query=invoice%20date&k=3"
```
---
### 16. **POST** `/search/semantic/multi`
Recherche dans tous les documents d'un utilisateur avec FAISS.
**Query Parameters:**
- `user_id` (string, required): UUID de l'utilisateur
- `query` (string, required): Texte de recherche
- `k` (int, optional): Nombre de résultats (défaut: 5)
**Response 200:**
```json
{
"user_id": "07b83616-a528-4720-9fd4-dab8b2cdc4a1",
"query": "data science",
"results": [
{
"text": "Document excerpt...",
"score": 0.35305043899364014,
"chunk_id": 0,
"document_id": "555eb078-b49b-4cea-bb8a-2139358b5f42"
}
],
"count": 2,
"searched_documents": 3
}
```
**Exemple cURL:**
```bash
curl -X POST "https://k2mar-docuresume-backend.hf.space/search/semantic/multi?user_id=07b83616-a528-4720-9fd4-dab8b2cdc4a1&query=data%20science&k=5"
```
---
## 📊 Analytics & Stats
### 17. **GET** `/analytics/user/{user_id}`
Récupérer les analytics d'un utilisateur.
**Response 200:**
```json
{
"user_id": "uuid-v4",
"analytics": {
"user_id": "uuid-v4",
"total_documents": 15,
"total_queries": 42,
"total_summaries": 12,
"storage_used_mb": 25.5,
"last_activity": "2026-01-27T12:00:00"
}
}
```
---
### 18. **GET** `/stats/global`
Statistiques globales de la plateforme.
**Response 200:**
```json
{
"total_users": 127,
"total_documents": 543,
"total_queries": 1845,
"timestamp": "2026-01-27T12:00:00"
}
```
---
## 🩺 Système
### 19. **GET** `/`
Point d'entrée de l'API.
**Response 200:**
```json
{
"service": "DocuResume Pro API",
"version": "1.0.0",
"status": "running",
"supabase_connected": true
}
```
**Exemple cURL:**
```bash
curl https://k2mar-docuresume-backend.hf.space/
```
---
### 20. **GET** `/health`
Health check de l'API et de la base de données.
**Response 200:**
```json
{
"status": "healthy",
"database": "connected",
"timestamp": "2026-01-27T12:00:00"
}
```
**Exemple cURL:**
```bash
curl https://k2mar-docuresume-backend.hf.space/health
```
---
## 🚀 Workflow Complet (Exemple Android/Mobile)
### Étape 1: Inscription
```kotlin
POST /users/register
Body: { email, username, password }
→ Obtenir user_id
```
### Étape 2: Upload de documents
```kotlin
POST /documents/upload
Form-data: { file, user_id }
→ Obtenir document_id
```
### Étape 3: Récupérer le contenu
```kotlin
GET /documents/{document_id}/content
→ Obtenir content (texte extrait)
```
### Étape 4: Générer résumé avec Gemini (Cloud)
```kotlin
POST /generate/summary/gemini?document_id={id}&max_length=100
→ Obtenir summary généré par IA
```
### Étape 5: Poser une question sur le document
```kotlin
POST /query/gemini?document_id={id}&question=Quel%20est%20le%20sujet%3F
→ Obtenir answer contextuelle
```
### Étape 6: Recherche sémantique (FAISS)
```kotlin
POST /search/semantic?document_id={id}&query=montant&k=5
→ Trouver passages pertinents
```
---
---
## 🤖 IA Générative (Gemini API)
### 21. **POST** `/generate/summary/gemini`
Génère un résumé intelligent avec Google Gemini.
**Query Parameters:**
- `document_id` (string, required): UUID du document
- `max_length` (int, optional): Longueur max en mots (défaut: 150)
**Response 200:**
```json
{
"document_id": "555eb078-b49b-4cea-bb8a-2139358b5f42",
"summary": "Cette facture d'Appwrite confirme un montant de 0,00 $ pour le forfait GitHub Student Pack...",
"length": 47,
"method": "gemini-pro"
}
```
**Errors:**
- `404`: Document non trouvé
- `400`: Document vide
- `429`: Quota Gemini dépassé
- `500`: Erreur API Gemini
**Exemple cURL:**
```bash
curl -X POST "https://k2mar-docuresume-backend.hf.space/generate/summary/gemini?document_id=555eb078-b49b-4cea-bb8a-2139358b5f42&max_length=60"
```
**Exemple Kotlin:**
```kotlin
@POST("generate/summary/gemini")
suspend fun generateSummaryGemini(
@Query("document_id") documentId: String,
@Query("max_length") maxLength: Int = 150
): Response<GeminiSummaryResponse>
data class GeminiSummaryResponse(
val document_id: String,
val summary: String,
val length: Int,
val method: String
)
```
---
### 22. **POST** `/query/gemini`
Répond à une question sur un document avec Gemini.
**Query Parameters:**
- `document_id` (string, required): UUID du document
- `question` (string, required): Question à poser
- `use_context` (bool, optional): Utiliser FAISS pour le contexte (défaut: true)
**Response 200:**
```json
{
"document_id": "555eb078-b49b-4cea-bb8a-2139358b5f42",
"question": "Quel est le montant total?",
"answer": "Le montant total de cette facture est de 0,00 $ car il s'agit d'un forfait gratuit pour étudiants.",
"method": "gemini-pro",
"context_used": true
}
```
**Errors:**
- `404`: Document non trouvé
- `400`: Document vide
- `429`: Quota Gemini dépassé
- `500`: Erreur API Gemini
**Exemple cURL:**
```bash
curl -X POST "https://k2mar-docuresume-backend.hf.space/query/gemini?document_id=555eb078-b49b-4cea-bb8a-2139358b5f42&question=Quel%20est%20le%20montant%20total%3F&use_context=true"
```
**Exemple Kotlin:**
```kotlin
@POST("query/gemini")
suspend fun queryDocumentGemini(
@Query("document_id") documentId: String,
@Query("question") question: String,
@Query("use_context") useContext: Boolean = true
): Response<GeminiQueryResponse>
data class GeminiQueryResponse(
val document_id: String,
val question: String,
val answer: String,
val method: String,
val context_used: Boolean
)
```
---
## ⚙️ Fonctionnalités Cloud
### ✅ Activées
- **FAISS** (`ENABLE_FAISS=true`) - ✅ Recherche sémantique opérationnelle
- **Gemini API** - ✅ Résumés et Q&A intelligents (gemini-3-flash-preview)
- **Stockage** - Supabase Storage (1GB free tier)
- **OCR** - Tesseract pour extraction de texte des PDFs
### ⚠️ Limitations
- **T5 désactivé** (`ENABLE_T5=false`) - Utilisez Gemini à la place
- **Quota Gemini** - 15 requêtes/minute gratuit (créer votre clé API sur https://aistudio.google.com/apikey)
- **Rate limiting** - HuggingFace peut limiter les requêtes
---
## 🛠️ Configuration Client
### JavaScript/TypeScript (React, Vue, etc.)
```javascript
const API_URL = 'https://k2mar-docuresume-backend.hf.space'
const headers = {
'Content-Type': 'application/json'
}
// Exemple: Login
const response = await fetch(`${API_URL}/users/login`, {
method: 'POST',
headers,
body: JSON.stringify({ email, password })
})
const data = await response.json()
```
### Kotlin/Android
```kotlin
object ApiClient {
private const val BASE_URL = "https://k2mar-docuresume-backend.hf.space/"
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(OkHttpClient.Builder()
.addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
.build())
.build()
val apiService: ApiService = retrofit.create(ApiService::class.java)
}
interface ApiService {
@POST("users/login")
suspend fun login(@Body credentials: LoginRequest): Response<LoginResponse>
@GET("documents/user/{userId}")
suspend fun getDocuments(@Path("userId") userId: String): Response<DocumentsResponse>
@Multipart
@POST("documents/upload")
suspend fun uploadDocument(
@Part("user_id") userId: RequestBody,
@Part file: MultipartBody.Part
): Response<UploadResponse>
}
```
---
## 📞 Support
- **GitHub:** [votre-repo](https://github.com/...)
- **Email:** support@docuresume.com
- **Documentation:** https://k2mar-docuresume-backend.hf.space/docs (Swagger UI)
---
---
## 📚 Guide d'Utilisation Complet
### ✅ Tests Validés (27 janvier 2026)
**Compte de test:**
- Email: `visiteur@gmail.com`
- Password: `123456789`
- User ID: `07b83616-a528-4720-9fd4-dab8b2cdc4a1`
### 🔄 Workflow Complet Testé
#### 1. **Connexion**
```bash
curl -X POST https://k2mar-docuresume-backend.hf.space/users/login \
-H "Content-Type: application/json" \
-d '{"email":"visiteur@gmail.com","password":"123456789"}'
```
**Résultat:**
```json
{
"message": "Connexion réussie",
"user_id": "07b83616-a528-4720-9fd4-dab8b2cdc4a1",
"email": "visiteur@gmail.com",
"username": "visiteur"
}
```
---
#### 2. **Récupérer les documents**
```bash
USER_ID="07b83616-a528-4720-9fd4-dab8b2cdc4a1"
curl "https://k2mar-docuresume-backend.hf.space/documents/user/$USER_ID?limit=10"
```
**Résultat (3 documents):**
```json
{
"count": 3,
"documents": [
{
"id": "555eb078-b49b-4cea-bb8a-2139358b5f42",
"filename": "invoice_a78624a8799919b509beb8a76742e74f.pdf",
"pages": 1,
"size_kb": 57,
"status": "completed"
},
{
"id": "74e50d0d-80ac-44f4-be6e-7517bd95e3e2",
"filename": "Data_science_avec_Python_Seance_3.pdf",
"pages": 17,
"size_kb": 242,
"status": "completed"
},
{
"id": "f00acf10-a5d0-471f-8165-90017b980141",
"filename": "Projet_data_analystics_SPARK (1).pdf",
"pages": 4,
"size_kb": 136,
"status": "completed"
}
]
}
```
---
#### 3. **Récupérer le contenu d'un document**
```bash
DOC_ID="555eb078-b49b-4cea-bb8a-2139358b5f42"
curl "https://k2mar-docuresume-backend.hf.space/documents/$DOC_ID/content"
```
**Résultat:**
```json
{
"document_id": "555eb078-b49b-4cea-bb8a-2139358b5f42",
"filename": "invoice_a78624a8799919b509beb8a76742e74f.pdf",
"content": "© 2025 Appwrite Code, Inc. All rights reserved...",
"content_length": 608,
"page_count": 1,
"file_size": 58432
}
```
**💡 Usage:** Ce contenu peut être utilisé pour générer un résumé **localement sur le device** avec TinyLlama ou T5.
---
#### 4. **Récupérer tous les contenus (pour résumé global)**
```bash
curl "https://k2mar-docuresume-backend.hf.space/documents/user/$USER_ID/contents?include_content=true&limit=50"
```
**Résultat:** Liste de tous les documents avec leur contenu complet.
**💡 Usage:** Idéal pour générer un **résumé global** de tous les documents en une seule fois.
---
#### 5. **Générer un résumé localement (sur device)**
```kotlin
// Kotlin/Android - Exemple avec TinyLlama
val response = apiService.getDocumentContent(documentId)
val content = response.content
// Générer résumé avec TinyLlama on-device
val summary = tinyLlamaSummarizer.summarize(listOf(
Pair(response.filename, content)
))
```
---
#### 6. **Sauvegarder le résumé généré**
```bash
curl -X POST "https://k2mar-docuresume-backend.hf.space/documents/$DOC_ID/summaries" \
-H "Content-Type: application/json" \
-d '{
"content": "Résumé généré par TinyLlama: Ce document est une facture...",
"summary_type": "abstractive",
"summary_level": "medium",
"model_name": "TinyLlama-1.1B",
"model_version": "Q4_K_M",
"compression_ratio": 0.15
}'
```
**Résultat:**
```json
{
"message": "Résumé créé avec succès",
"summary_id": "new-uuid",
"document_id": "555eb078-b49b-4cea-bb8a-2139358b5f42"
}
```
---
#### 7. **Récupérer les analytics**
```bash
curl "https://k2mar-docuresume-backend.hf.space/analytics/user/$USER_ID"
```
**Résultat:**
```json
{
"user_id": "07b83616-a528-4720-9fd4-dab8b2cdc4a1",
"analytics": {
"total_documents": 3,
"total_queries": 0,
"total_summaries": 0,
"last_active": "2026-01-27T05:03:04Z"
}
}
```
---
### 🧪 Script de Test Complet
```bash
#!/bin/bash
API="https://k2mar-docuresume-backend.hf.space"
echo "🔍 Test 1: Health Check"
curl -s "$API/health" | jq .status
echo -e "\n🔐 Test 2: Login"
LOGIN=$(curl -s -X POST "$API/users/login" \
-H "Content-Type: application/json" \
-d '{"email":"visiteur@gmail.com","password":"123456789"}')
USER_ID=$(echo $LOGIN | jq -r .user_id)
echo "User ID: $USER_ID"
echo -e "\n📄 Test 3: Documents"
DOCS=$(curl -s "$API/documents/user/$USER_ID?limit=5")
DOC_COUNT=$(echo $DOCS | jq '.count')
echo "Documents trouvés: $DOC_COUNT"
echo -e "\n📖 Test 4: Premier document"
DOC_ID=$(echo $DOCS | jq -r '.documents[0].id')
DOC_NAME=$(echo $DOCS | jq -r '.documents[0].original_filename')
echo "Document: $DOC_NAME (ID: $DOC_ID)"
echo -e "\n📝 Test 5: Contenu du document"
CONTENT=$(curl -s "$API/documents/$DOC_ID/content")
CONTENT_LENGTH=$(echo $CONTENT | jq .content_length)
echo "Contenu extrait: $CONTENT_LENGTH caractères"
echo -e "\n📊 Test 6: Analytics"
curl -s "$API/analytics/user/$USER_ID" | jq '.analytics | {total_documents, total_summaries, last_active}'
echo -e "\n✅ Tous les tests passés!"
```
**Sauvegarder dans:** `test_api.sh`
**Exécuter:**
```bash
chmod +x test_api.sh
./test_api.sh
```
---
### 📱 Exemple Mobile (Kotlin/Android)
```kotlin
// 1. Configuration du client
object ApiClient {
private const val BASE_URL = "https://k2mar-docuresume-backend.hf.space/"
val apiService: ApiService = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
// 2. Interface API
interface ApiService {
@POST("users/login")
suspend fun login(@Body credentials: LoginRequest): LoginResponse
@GET("documents/user/{userId}")
suspend fun getDocuments(@Path("userId") userId: String): DocumentsResponse
@GET("documents/{docId}/content")
suspend fun getDocumentContent(@Path("docId") docId: String): ContentResponse
@POST("documents/{docId}/summaries")
suspend fun saveSummary(
@Path("docId") docId: String,
@Body summary: SummaryRequest
): SummaryResponse
}
// 3. Workflow complet
class SummaryViewModel : ViewModel() {
suspend fun generateAndSaveSummary(documentId: String) {
// Étape 1: Récupérer le contenu
val contentResponse = ApiClient.apiService.getDocumentContent(documentId)
val content = contentResponse.content
// Étape 2: Générer résumé localement avec TinyLlama
val summary = tinyLlamaSummarizer.summarize(listOf(
Pair(contentResponse.filename, content)
))
// Étape 3: Sauvegarder le résumé dans le cloud
val summaryRequest = SummaryRequest(
content = summary,
summary_type = "abstractive",
summary_level = "medium",
model_name = "TinyLlama-1.1B",
compression_ratio = calculateCompression(content, summary)
)
val result = ApiClient.apiService.saveSummary(documentId, summaryRequest)
Log.d("Summary", "✓ Résumé sauvegardé: ${result.summary_id}")
}
}
```
---
### 🌐 Exemple Web (JavaScript/React)
```javascript
// Configuration
const API_URL = 'https://k2mar-docuresume-backend.hf.space'
// 1. Login
const login = async (email, password) => {
const response = await fetch(`${API_URL}/users/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
})
const data = await response.json()
localStorage.setItem('user_id', data.user_id)
return data
}
// 2. Récupérer documents
const getDocuments = async () => {
const userId = localStorage.getItem('user_id')
const response = await fetch(`${API_URL}/documents/user/${userId}`)
return await response.json()
}
// 3. Récupérer contenu
const getContent = async (documentId) => {
const response = await fetch(`${API_URL}/documents/${documentId}/content`)
return await response.json()
}
// 4. Upload document
const uploadDocument = async (file) => {
const userId = localStorage.getItem('user_id')
const formData = new FormData()
formData.append('file', file)
formData.append('user_id', userId)
const response = await fetch(`${API_URL}/documents/upload`, {
method: 'POST',
body: formData
})
return await response.json()
}
// 5. Workflow complet
const processDocument = async (file) => {
// Upload
console.log('📤 Upload...')
const uploadResult = await uploadDocument(file)
// Récupérer contenu
console.log('📖 Extraction du texte...')
const content = await getContent(uploadResult.document_id)
// Note: Génération de résumé se fait sur le device mobile
// Pour web, utiliser une instance locale avec T5 activé
console.log(`✅ Document traité: ${content.content_length} caractères`)
}
```
---
### 🐛 Troubleshooting
#### ❌ Erreur 401: "Email ou mot de passe incorrect"
**Solution:** Vérifier les credentials. Compte test disponible:
- Email: `visiteur@gmail.com`
- Password: `123456789`
#### ❌ Erreur 503: "FAISS non disponible"
**Solution (OBSOLÈTE):** FAISS est maintenant **activé** sur Hugging Face! Les endpoints `/search/semantic` et `/search/semantic/multi` fonctionnent.
#### ❌ Erreur 503: "T5 non disponible"
**Solution:** T5 est désactivé sur le cloud. Utilisez les endpoints Gemini `/generate/summary/gemini` et `/query/gemini` pour les résumés et Q&A.
#### ❌ Erreur 429: "Quota Gemini dépassé"
**Solution:** La clé API Gemini gratuite a une limite de 15 req/min. Créez votre propre clé sur https://aistudio.google.com/apikey ou attendez 1 minute.
#### ❌ Document upload timeout
**Solution:** Le backend utilise Tesseract OCR qui peut prendre 10-30s pour les gros PDFs. Augmenter le timeout client à 60s.
#### ❌ CORS Error (Web)
**Solution:** CORS est activé avec `allow_origins=["*"]`. Vérifier que le navigateur envoie bien les headers.
---
### 📊 Limites & Quotas
| Ressource | Limite | Notes |
|-----------|--------|-------|
| **Taille fichier** | 10MB | Limité par Hugging Face Spaces |
| **Documents/user** | Illimité | Limité par Supabase storage (1GB free) |
| **Requests/minute** | ~60 | Rate limiting HF Spaces |
| **OCR Processing** | 30s timeout | Tesseract peut être lent |
| **Gemini API** | 15 req/min | Quota gratuit (créer votre clé) |
| **FAISS** | ✅ Activé | sentence-transformers (384 dimensions) |
---
## 🎉 Résumé des fonctionnalités
### ✅ Actif sur le cloud
- **Authentification** - Register, Login
- **Upload PDF** - Avec OCR Tesseract automatique
- **Stockage** - Supabase PostgreSQL + Storage
- **FAISS** - Recherche sémantique vectorielle
- **Gemini API** - Résumés et Q&A intelligents (gemini-3-flash-preview)
- **Analytics** - Statistiques utilisateur et globales
### ⚠️ Désactivé sur le cloud
- **T5 local** - Utilisez Gemini API à la place
- **TinyLlama** - Difficile à déployer sur HF (600MB)
| **FAISS** | ❌ Désactivé | Cloud uniquement |
| **T5 Generation** | ❌ Désactivé | Cloud uniquement |
---
### 🔗 Liens Utiles
- **API Swagger/OpenAPI:** `https://k2mar-docuresume-backend.hf.space/docs`
- **Redoc:** `https://k2mar-docuresume-backend.hf.space/redoc`
- **Health Check:** `https://k2mar-docuresume-backend.hf.space/health`
- **Stats:** `https://k2mar-docuresume-backend.hf.space/stats/global`
---
**Dernière mise à jour:** 27 janvier 2026
**Version API:** 1.0.0
**Tests validés:** ✅ 27 janvier 2026