Spaces:
Sleeping
Sleeping
📱 API pour Modèle T5 Local sur Téléphone
🎯 Architecture
┌─────────────────────────────────────────────────┐
│ Application Mobile │
│ ┌──────────────────────────────────────────┐ │
│ │ Modèle T5-Small Finetuned (ONNX) │ │
│ │ • 60 MB quantifié INT8 │ │
│ │ • Génération de résumés locale │ │
│ └──────────────────────────────────────────┘ │
│ ↕ │
│ API Calls (données uniquement) │
└─────────────────────────────────────────────────┘
↕
┌─────────────────────────────────────────────────┐
│ Backend API (Hugging Face Spaces) │
│ • Stockage des documents (Supabase) │
│ • Fournit le contenu textuel extrait │
│ • Reçoit et stocke les résumés générés │
└─────────────────────────────────────────────────┘
📡 Nouvelles API Ajoutées
1️⃣ GET /documents/{document_id}/content
Récupérer le contenu textuel d'un document pour génération locale
Requête
curl https://k2mar-docuresume-backend.hf.space/documents/DOC_ID/content
Réponse
{
"document_id": "uuid-here",
"filename": "Mon Document.pdf",
"content": "Contenu textuel extrait du PDF avec OCR...",
"page_count": 5,
"file_size": 245678,
"content_length": 2847
}
Utilisation Mobile
// Flutter
Future<String> getDocumentContent(String documentId) async {
final response = await http.get(
Uri.parse('$baseUrl/documents/$documentId/content')
);
if (response.statusCode == 200) {
final data = json.decode(response.body);
return data['content']; // Texte à résumer
}
throw Exception('Failed to load content');
}
2️⃣ GET /documents/user/{user_id}/contents
Récupérer le contenu de tous les documents d'un utilisateur
Requête
curl "https://k2mar-docuresume-backend.hf.space/documents/user/USER_ID/contents?limit=100&include_content=true"
Paramètres
limit: nombre max de documents (défaut: 100)include_content: inclure le contenu texte (défaut: true)
Réponse
{
"user_id": "user-uuid",
"documents": [
{
"document_id": "doc-uuid-1",
"filename": "Document1.pdf",
"page_count": 5,
"file_size": 245678,
"uploaded_at": "2026-01-27T00:00:00",
"processing_status": "completed",
"content": "Texte du document 1...",
"content_length": 2847
},
{
"document_id": "doc-uuid-2",
"filename": "Document2.pdf",
"content": "Texte du document 2...",
"content_length": 4521
}
],
"count": 2,
"total_content_length": 7368
}
Utilisation Mobile
// Flutter - Télécharger tous les documents pour résumé batch
Future<List<Document>> getAllDocumentsContents(String userId) async {
final response = await http.get(
Uri.parse('$baseUrl/documents/user/$userId/contents?include_content=true')
);
if (response.statusCode == 200) {
final data = json.decode(response.body);
return (data['documents'] as List)
.map((doc) => Document.fromJson(doc))
.toList();
}
throw Exception('Failed to load documents');
}
3️⃣ POST /documents/{document_id}/summaries
Envoyer un résumé généré localement vers le serveur
Requête
curl -X POST https://k2mar-docuresume-backend.hf.space/documents/DOC_ID/summaries \
-H "Content-Type: application/json" \
-d '{
"summary_type": "abstractive",
"summary_level": "medium",
"content": "Résumé généré par T5-small...",
"model_name": "t5-small-finetuned",
"generation_time": 3.45,
"token_count": 150,
"rouge_1_score": 0.87,
"rouge_2_score": 0.73,
"rouge_l_score": 0.81
}'
Champs
content(requis): texte du résumé générésummary_type: "abstractive" | "extractive" | "hybrid" (défaut: "extractive")summary_level: "short" | "medium" | "long" (défaut: "medium")model_name: nom du modèle (défaut: "t5-small-finetuned")generation_time: temps de génération en secondes (optionnel)token_count: nombre de tokens générés (optionnel)rouge_1_score,rouge_2_score,rouge_l_score: métriques ROUGE (optionnel)
Réponse
{
"message": "Résumé créé avec succès",
"summary_id": "summary-uuid",
"document_id": "doc-uuid",
"summary_type": "abstractive",
"created_at": "2026-01-27T02:30:00"
}
Utilisation Mobile
// Flutter - Envoyer le résumé généré
Future<void> submitSummary(String documentId, String summaryText, double generationTime) async {
final response = await http.post(
Uri.parse('$baseUrl/documents/$documentId/summaries'),
headers: {'Content-Type': 'application/json'},
body: json.encode({
'summary_type': 'abstractive',
'summary_level': 'medium',
'content': summaryText,
'model_name': 't5-small-finetuned',
'generation_time': generationTime,
'token_count': summaryText.split(' ').length
})
);
if (response.statusCode != 200) {
throw Exception('Failed to submit summary');
}
}
4️⃣ POST /summaries/batch
Créer plusieurs résumés en batch (génération locale de plusieurs documents)
Requête
curl -X POST https://k2mar-docuresume-backend.hf.space/summaries/batch \
-H "Content-Type: application/json" \
-d '[
{
"document_id": "doc-uuid-1",
"content": "Résumé du document 1...",
"summary_type": "abstractive",
"generation_time": 2.5
},
{
"document_id": "doc-uuid-2",
"content": "Résumé du document 2...",
"summary_type": "abstractive",
"generation_time": 3.1
}
]'
Réponse
{
"message": "2 résumés créés avec succès",
"count": 2,
"summary_ids": ["summary-uuid-1", "summary-uuid-2"]
}
Utilisation Mobile
// Flutter - Soumettre plusieurs résumés d'un coup
Future<void> submitBatchSummaries(List<Summary> summaries) async {
final payload = summaries.map((s) => {
'document_id': s.documentId,
'content': s.content,
'summary_type': 'abstractive',
'summary_level': 'medium',
'model_name': 't5-small-finetuned',
'generation_time': s.generationTime
}).toList();
final response = await http.post(
Uri.parse('$baseUrl/summaries/batch'),
headers: {'Content-Type': 'application/json'},
body: json.encode(payload)
);
if (response.statusCode != 200) {
throw Exception('Failed to submit batch');
}
}
5️⃣ GET /summaries/user/{user_id}
Récupérer tous les résumés générés par un utilisateur
Requête
curl "https://k2mar-docuresume-backend.hf.space/summaries/user/USER_ID?limit=50&summary_type=abstractive"
Paramètres
limit: nombre max de résumés (défaut: 50)summary_type: filtrer par type (optionnel)
Réponse
{
"user_id": "user-uuid",
"summaries": [
{
"id": "summary-uuid",
"document_id": "doc-uuid",
"content": "Résumé...",
"summary_type": "abstractive",
"summary_level": "medium",
"model_name": "t5-small-finetuned",
"generation_time": 3.45,
"created_at": "2026-01-27T02:30:00",
"documents": {
"original_filename": "Document.pdf"
}
}
],
"count": 1
}
🔄 Workflow Complet
Scénario 1: Résumé d'un document
// 1. Récupérer le contenu du document
String content = await getDocumentContent(documentId);
// 2. Générer le résumé avec le modèle T5 local
String summary = await t5Model.generateSummary(content);
// 3. Envoyer le résumé au serveur
await submitSummary(documentId, summary, generationTime);
Scénario 2: Résumé de tous les documents
// 1. Récupérer tous les documents avec contenus
List<Document> docs = await getAllDocumentsContents(userId);
// 2. Générer les résumés en local (batch ou séquentiel)
List<Summary> summaries = [];
for (var doc in docs) {
String summary = await t5Model.generateSummary(doc.content);
summaries.add(Summary(
documentId: doc.id,
content: summary,
generationTime: ...
));
}
// 3. Envoyer tous les résumés d'un coup
await submitBatchSummaries(summaries);
📊 Intégration du Modèle T5 sur Mobile
Structure du package embarqué
assets/
models/
t5-small-finetuned-logits-int8.onnx (60 MB)
tokenizer/
config.json
tokenizer.json
tokenizer_config.json
Exemple Flutter avec ONNX Runtime
import 'package:onnxruntime/onnxruntime.dart';
class T5SummaryModel {
late OrtSession session;
late Tokenizer tokenizer;
Future<void> loadModel() async {
// Charger le modèle ONNX
final modelPath = 'assets/models/t5-small-finetuned-logits-int8.onnx';
session = await OrtSession.fromAsset(modelPath);
// Charger le tokenizer
tokenizer = Tokenizer.fromAsset('assets/models/tokenizer');
}
Future<String> generateSummary(String text, {int maxTokens = 150}) async {
final startTime = DateTime.now();
// 1. Tokeniser l'entrée
final inputIds = tokenizer.encode("summarize: $text", maxLength: 512);
// 2. Boucle autoregressive
List<int> outputIds = [tokenizer.padTokenId];
for (int i = 0; i < maxTokens; i++) {
// Forward pass ONNX
final inputs = {
'input_ids': inputIds,
'attention_mask': List.filled(inputIds.length, 1),
'decoder_input_ids': outputIds
};
final outputs = await session.run(inputs);
final logits = outputs[0];
// Argmax sur le dernier token
final nextToken = argmax(logits[-1]);
if (nextToken == tokenizer.eosTokenId) break;
outputIds.add(nextToken);
}
// 3. Décoder la sortie
final summary = tokenizer.decode(outputIds, skipSpecialTokens: true);
final duration = DateTime.now().difference(startTime);
print('Génération: ${duration.inSeconds}s');
return summary;
}
}
⚙️ Configuration Recommandée
Contraintes minimales
- RAM disponible: 1 GB libre (2 GB recommandé)
- Stockage: 100 MB (modèle + cache)
- Android: API 24+ (Android 7.0)
- iOS: iOS 12+
Optimisations
- Quantification INT8: déjà appliquée (60 MB)
- Chunking: découper les longs documents (>2000 tokens)
- Cache: stocker les résumés localement
- Background processing: générer en arrière-plan
- Batch processing: traiter plusieurs docs pendant la nuit
🧪 Test des Nouvelles API
# Test 1: Récupérer contenu d'un document
curl https://k2mar-docuresume-backend.hf.space/documents/DOC_ID/content | jq '.content_length'
# Test 2: Récupérer tous les contenus
curl "https://k2mar-docuresume-backend.hf.space/documents/user/USER_ID/contents?include_content=false" | jq '.count'
# Test 3: Soumettre un résumé test
curl -X POST https://k2mar-docuresume-backend.hf.space/documents/DOC_ID/summaries \
-H "Content-Type: application/json" \
-d '{
"content": "Ceci est un résumé test généré par T5-small",
"summary_type": "abstractive",
"model_name": "t5-small-finetuned",
"generation_time": 2.5
}' | jq
# Test 4: Récupérer résumés d'un user
curl https://k2mar-docuresume-backend.hf.space/summaries/user/USER_ID | jq '.count'
📈 Métriques à Tracker
Pour mesurer la performance du modèle local:
class SummaryMetrics {
double generationTime; // Temps de génération (secondes)
int inputTokens; // Nombre de tokens en entrée
int outputTokens; // Nombre de tokens générés
double batteryUsed; // Batterie consommée (%)
double memoryPeak; // RAM max utilisée (MB)
// Optionnel: scores ROUGE si vous avez un résumé de référence
double? rouge1;
double? rouge2;
double? rougeL;
}
Envoyez ces métriques au serveur lors de la soumission du résumé pour analyse.
🚀 Déploiement
Les nouvelles API sont déjà déployées sur:
https://k2mar-docuresume-backend.hf.space
✅ Commit: ba0c701
✅ Message: "Add APIs for local T5 model: content retrieval and summary submission"
✅ Status: En ligne sur Hugging Face Spaces
Vous pouvez maintenant intégrer le modèle T5 dans votre app mobile! 📱