Spaces:
Sleeping
Sleeping
| # 📡 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 | |