Exemples d'utilisation avancée
Cette page présente des exemples avancés d'utilisation de l'API ParseMyFile pour des cas d'usage complexes.
Exemple 1 : Extraction de données de tableau
Configuration YAML pour tableau
yaml
# tableau-facturation.yaml
schemas:
data:
type: object
properties:
en_tete_tableau:
type: string
description: en-tête du tableau
lignes_produits:
type: array<object>
description: lignes de produits du tableau
items:
type: object
properties:
produit:
type: string
description: nom du produit
quantite:
type: integer
description: quantité du produit
prix_unitaire:
type: double
description: prix unitaire du produit en euros
total:
type: double
description: total de la ligne en euros
total_general:
type: double
description: total général de la facture en eurosCode Python pour traitement de tableau
python
import requests
import pandas as pd
from typing import List, Dict, Any
def process_table_document(file_path: str, yaml_path: str, api_key: str) -> pd.DataFrame:
"""
Traite un document contenant un tableau et retourne un DataFrame
"""
url = "https://api.parsemyfile.com/api/v1/generate"
headers = {"X-API-KEY": api_key}
with open(file_path, 'rb') as file, open(yaml_path, 'rb') as yaml_file:
files = {
'file': (file_path, file, 'application/pdf'),
'yaml_file': ('config.yaml', yaml_file, 'text/yaml')
}
response = requests.post(url, headers=headers, files=files)
if response.status_code == 200:
result = response.json()
data = result['data']['extracted_fields']
# Convertir les lignes de tableau en DataFrame
if 'lignes_produits' in data:
df = pd.DataFrame(data['lignes_produits'])
return df
else:
return pd.DataFrame()
else:
raise Exception(f"Erreur API: {response.text}")
# Utilisation
try:
df = process_table_document('facture_avec_tableau.pdf', 'tableau-facturation.yaml', 'votre_cle_api')
print("Tableau extrait:")
print(df)
# Calculer des statistiques
print(f"\nNombre de lignes: {len(df)}")
print(f"Total général: {df['total'].sum():.2f} EUR")
except Exception as e:
print(f"Erreur: {e}")Exemple 2 : Extraction de données multi-pages
Configuration YAML pour document multi-pages
yaml
# document-multipage.yaml
schemas:
data:
type: object
properties:
titre_document:
type: string
description: titre du document
resume_executif:
type: string
description: résumé exécutif du document
chapitres:
type: array<object>
description: chapitres du document
items:
type: object
properties:
titre_chapitre:
type: string
description: titre du chapitre
contenu_chapitre:
type: string
description: contenu du chapitre
conclusion:
type: string
description: conclusion du document
signatures:
type: array<string>
description: signatures détectéesCode JavaScript pour traitement multi-pages
javascript
class MultiPageProcessor {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.parsemyfile.com/api/v1/generate';
}
async processMultiPageDocument(file, yamlFile) {
try {
const formData = new FormData();
formData.append('file', file);
formData.append('yaml_file', yamlFile);
const response = await fetch(this.baseUrl, {
method: 'POST',
headers: {
'X-API-KEY': this.apiKey
},
body: formData
});
if (!response.ok) {
throw new Error(`Erreur ${response.status}: ${response.statusText}`);
}
const result = await response.json();
return this.organizeMultiPageData(result.data);
} catch (error) {
console.error('Erreur lors du traitement multi-pages:', error);
throw error;
}
}
organizeMultiPageData(data) {
const organized = {
metadata: data.metadata,
content: {
title: data.extracted_fields.titre_document,
executiveSummary: data.extracted_fields.resume_executif,
chapters: this.organizeChapters(data.extracted_fields.chapitres),
conclusion: data.extracted_fields.conclusion,
signatures: data.extracted_fields.signatures
}
};
return organized;
}
organizeChapters(chaptersData) {
if (!chaptersData || !Array.isArray(chaptersData)) {
return [];
}
return chaptersData.map((chapter, index) => ({
id: index + 1,
title: chapter.titre_chapitre,
content: chapter.contenu_chapitre
}));
}
}
// Utilisation
const processor = new MultiPageProcessor('votre_cle_api');
document.getElementById('processBtn').addEventListener('click', async () => {
const fileInput = document.getElementById('fileInput');
const yamlInput = document.getElementById('yamlInput');
if (fileInput.files.length === 0 || yamlInput.files.length === 0) {
alert('Veuillez sélectionner un fichier et une configuration YAML');
return;
}
try {
const result = await processor.processMultiPageDocument(
fileInput.files[0],
yamlInput.files[0]
);
console.log('Document multi-pages traité:', result);
displayResults(result);
} catch (error) {
console.error('Erreur:', error);
alert('Erreur lors du traitement: ' + error.message);
}
});
function displayResults(result) {
const output = document.getElementById('output');
output.innerHTML = `
<h3>Titre: ${result.content.title}</h3>
<h4>Résumé exécutif:</h4>
<p>${result.content.executiveSummary}</p>
<h4>Chapitres (${result.content.chapters.length}):</h4>
${result.content.chapters.map(ch => `
<div>
<strong>Chapitre ${ch.id}: ${ch.title}</strong>
<p>${ch.content}</p>
</div>
`).join('')}
<h4>Conclusion:</h4>
<p>${result.content.conclusion}</p>
`;
}Exemple 3 : Extraction avec validation avancée
Configuration YAML avec validation
yaml
# validation-avancee.yaml
schemas:
data:
type: object
properties:
numero_commande:
type: string
description: numéro de commande (format CMD-XXXXXX)
client_email:
type: string
description: email du client
montant_commande:
type: double
description: montant de la commande en euros
date_livraison:
type: string
description: date de livraison prévue (format YYYY-MM-DD)
produits:
type: array<object>
description: liste des produits commandés
items:
type: object
properties:
nom_produit:
type: string
description: nom du produit
quantite:
type: integer
description: quantité du produit
prix:
type: double
description: prix unitaire du produit en eurosCode Python avec validation
python
import requests
import re
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional
from dataclasses import dataclass
@dataclass
class ValidationError:
field: str
message: str
value: Any
class AdvancedValidator:
def __init__(self):
self.errors: List[ValidationError] = []
def validate_order_number(self, value: str) -> bool:
pattern = r"^CMD-[0-9]{6}$"
if not re.match(pattern, value):
self.errors.append(ValidationError(
"numero_commande",
"Le numéro de commande doit être au format CMD-XXXXXX",
value
))
return False
return True
def validate_email(self, value: str) -> bool:
pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
if not re.match(pattern, value):
self.errors.append(ValidationError(
"client_email",
"Format d'email invalide",
value
))
return False
return True
def validate_delivery_date(self, value: str) -> bool:
try:
date = datetime.strptime(value, "%d/%m/%Y")
today = datetime.now()
max_date = today + timedelta(days=365)
if date < today:
self.errors.append(ValidationError(
"date_livraison",
"La date de livraison ne peut pas être dans le passé",
value
))
return False
if date > max_date:
self.errors.append(ValidationError(
"date_livraison",
"La date de livraison ne peut pas dépasser un an",
value
))
return False
return True
except ValueError:
self.errors.append(ValidationError(
"date_livraison",
"Format de date invalide (DD/MM/YYYY attendu)",
value
))
return False
def validate_amount(self, value: float) -> bool:
if value < 0 or value > 10000:
self.errors.append(ValidationError(
"montant_commande",
"Le montant doit être entre 0 et 10000 EUR",
value
))
return False
return True
def validate_products(self, products: List[Dict]) -> bool:
if len(products) < 1 or len(products) > 10:
self.errors.append(ValidationError(
"produits",
"Le nombre de produits doit être entre 1 et 10",
len(products)
))
return False
for i, product in enumerate(products):
if not product.get('nom_produit'):
self.errors.append(ValidationError(
f"produits[{i}].nom_produit",
"Le nom du produit est requis",
product
))
return False
if not (1 <= product.get('quantite', 0) <= 100):
self.errors.append(ValidationError(
f"produits[{i}].quantite",
"La quantité doit être entre 1 et 100",
product.get('quantite')
))
return False
return True
def process_with_validation(file_path: str, yaml_path: str, api_key: str) -> Dict[str, Any]:
"""
Traite un document avec validation avancée
"""
# Appel API
url = "https://api.parsemyfile.com/api/v1/generate"
headers = {"X-API-KEY": api_key}
with open(file_path, 'rb') as file, open(yaml_path, 'rb') as yaml_file:
files = {
'file': (file_path, file, 'application/pdf'),
'yaml_file': ('config.yaml', yaml_file, 'text/yaml')
}
response = requests.post(url, headers=headers, files=files)
if response.status_code != 200:
raise Exception(f"Erreur API: {response.text}")
result = response.json()
data = result['data']['extracted_fields']
# Validation
validator = AdvancedValidator()
# Validation des champs individuels
validator.validate_order_number(data.get('numero_commande', ''))
validator.validate_email(data.get('client_email', ''))
validator.validate_delivery_date(data.get('date_livraison', ''))
validator.validate_amount(float(data.get('montant_commande', 0)))
validator.validate_products(data.get('produits', []))
return {
'data': data,
'valid': len(validator.errors) == 0,
'errors': validator.errors,
'metadata': result['data']['metadata']
}
# Utilisation
try:
result = process_with_validation('commande.pdf', 'validation-avancee.yaml', 'votre_cle_api')
if result['valid']:
print("✅ Document traité et validé avec succès")
print(f"Numéro de commande: {result['data']['numero_commande']}")
print(f"Client: {result['data']['client_email']}")
print(f"Montant: {result['data']['montant_commande']} EUR")
else:
print("❌ Erreurs de validation détectées:")
for error in result['errors']:
print(f" - {error.field}: {error.message} (valeur: {error.value})")
except Exception as e:
print(f"Erreur: {e}")Exemple 4 : Intégration avec une base de données
Code Python avec intégration BDD
python
import sqlite3
import requests
import json
from typing import Dict, Any
from datetime import datetime
class DocumentProcessor:
def __init__(self, api_key: str, db_path: str = "documents.db"):
self.api_key = api_key
self.db_path = db_path
self.init_database()
def init_database(self):
"""Initialise la base de données"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS documents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filename TEXT NOT NULL,
document_type TEXT NOT NULL,
processed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status TEXT NOT NULL,
confidence_score REAL,
extracted_data TEXT,
error_message TEXT
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS extracted_fields (
id INTEGER PRIMARY KEY AUTOINCREMENT,
document_id INTEGER,
field_name TEXT NOT NULL,
field_value TEXT,
field_type TEXT,
confidence REAL,
FOREIGN KEY (document_id) REFERENCES documents (id)
)
''')
conn.commit()
conn.close()
def process_document(self, file_path: str, yaml_path: str, document_type: str) -> Dict[str, Any]:
"""Traite un document et sauvegarde en base"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
try:
# Appel API
result = self.call_api(file_path, yaml_path)
if result['status'] == 'success':
# Sauvegarde du document
cursor.execute('''
INSERT INTO documents (filename, document_type, status, confidence_score, extracted_data)
VALUES (?, ?, ?, ?, ?)
''', (
file_path,
document_type,
'success',
result['data']['metadata']['confidence_score'],
json.dumps(result['data']['extracted_fields'])
))
document_id = cursor.lastrowid
# Sauvegarde des champs extraits
for field_name, field_value in result['data']['extracted_fields'].items():
cursor.execute('''
INSERT INTO extracted_fields (document_id, field_name, field_value, field_type, confidence)
VALUES (?, ?, ?, ?, ?)
''', (
document_id,
field_name,
str(field_value),
'text', # Type par défaut
result['data']['metadata']['confidence_score']
))
conn.commit()
return {
'success': True,
'document_id': document_id,
'data': result['data']
}
else:
# Sauvegarde de l'erreur
cursor.execute('''
INSERT INTO documents (filename, document_type, status, error_message)
VALUES (?, ?, ?, ?)
''', (file_path, document_type, 'error', str(result.get('error', 'Erreur inconnue'))))
conn.commit()
return {
'success': False,
'error': result.get('error', 'Erreur inconnue')
}
except Exception as e:
# Sauvegarde de l'exception
cursor.execute('''
INSERT INTO documents (filename, document_type, status, error_message)
VALUES (?, ?, ?, ?)
''', (file_path, document_type, 'error', str(e)))
conn.commit()
return {
'success': False,
'error': str(e)
}
finally:
conn.close()
def call_api(self, file_path: str, yaml_path: str) -> Dict[str, Any]:
"""Appel à l'API ParseMyFile"""
url = "https://api.parsemyfile.com/api/v1/generate"
headers = {"X-API-KEY": self.api_key}
with open(file_path, 'rb') as file, open(yaml_path, 'rb') as yaml_file:
files = {
'file': (file_path, file, 'application/pdf'),
'yaml_file': ('config.yaml', yaml_file, 'text/yaml')
}
response = requests.post(url, headers=headers, files=files)
if response.status_code == 200:
return response.json()
else:
return {
'status': 'error',
'error': f"Erreur API: {response.status_code} - {response.text}"
}
def get_document_stats(self) -> Dict[str, Any]:
"""Récupère les statistiques des documents traités"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# Statistiques générales
cursor.execute('''
SELECT
COUNT(*) as total,
SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as success,
SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END) as errors,
AVG(confidence_score) as avg_confidence
FROM documents
''')
stats = cursor.fetchone()
# Statistiques par type de document
cursor.execute('''
SELECT document_type, COUNT(*) as count
FROM documents
GROUP BY document_type
''')
by_type = dict(cursor.fetchall())
conn.close()
return {
'total_documents': stats[0],
'successful': stats[1],
'errors': stats[2],
'average_confidence': stats[3],
'by_type': by_type
}
def search_documents(self, field_name: str, field_value: str) -> List[Dict[str, Any]]:
"""Recherche des documents par valeur de champ"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
SELECT d.*, ef.field_value
FROM documents d
JOIN extracted_fields ef ON d.id = ef.document_id
WHERE ef.field_name = ? AND ef.field_value LIKE ?
''', (field_name, f"%{field_value}%"))
results = []
for row in cursor.fetchall():
results.append({
'id': row[0],
'filename': row[1],
'document_type': row[2],
'processed_at': row[3],
'status': row[4],
'confidence_score': row[5],
'field_value': row[7]
})
conn.close()
return results
# Utilisation
processor = DocumentProcessor('votre_cle_api')
# Traitement d'un document
result = processor.process_document('facture.pdf', 'facture.yaml', 'facture')
if result['success']:
print(f"✅ Document traité avec succès (ID: {result['document_id']})")
else:
print(f"❌ Erreur: {result['error']}")
# Statistiques
stats = processor.get_document_stats()
print(f"Statistiques: {stats['successful']}/{stats['total_documents']} documents traités avec succès")
# Recherche
results = processor.search_documents('client_email', 'jean@example.com')
print(f"Documents trouvés: {len(results)}")Exemple 5 : API REST personnalisée
Code Flask pour API REST
python
from flask import Flask, request, jsonify
import requests
import os
from werkzeug.utils import secure_filename
import json
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024 # 10 MB max
# Configuration
PARSE_MY_FILE_API_KEY = os.getenv('PARSE_MY_FILE_API_KEY')
PARSE_MY_FILE_BASE_URL = 'https://api.parsemyfile.com'
@app.route('/api/process', methods=['POST'])
def process_document():
"""Endpoint pour traiter un document"""
try:
# Vérification des fichiers
if 'file' not in request.files or 'yaml_file' not in request.files:
return jsonify({'error': 'Fichiers manquants'}), 400
file = request.files['file']
yaml_file = request.files['yaml_file']
if file.filename == '' or yaml_file.filename == '':
return jsonify({'error': 'Aucun fichier sélectionné'}), 400
# Appel à l'API ParseMyFile
files = {
'file': (secure_filename(file.filename), file, file.content_type),
'yaml_file': (secure_filename(yaml_file.filename), yaml_file, 'text/yaml')
}
headers = {'X-API-KEY': PARSE_MY_FILE_API_KEY}
response = requests.post(
f'{PARSE_MY_FILE_BASE_URL}/api/v1/generate',
headers=headers,
files=files
)
if response.status_code == 200:
result = response.json()
return jsonify({
'success': True,
'data': result['data'],
'processing_info': result.get('processing_info', {})
})
else:
return jsonify({
'success': False,
'error': f"Erreur API: {response.status_code}",
'details': response.text
}), response.status_code
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
@app.route('/api/health', methods=['GET'])
def health_check():
"""Vérification de la santé de l'API"""
try:
response = requests.get(f'{PARSE_MY_FILE_BASE_URL}/health')
if response.status_code == 200:
return jsonify({
'status': 'healthy',
'parse_my_file_api': response.json()
})
else:
return jsonify({
'status': 'unhealthy',
'parse_my_file_api': 'unavailable'
}), 503
except Exception as e:
return jsonify({
'status': 'unhealthy',
'error': str(e)
}), 503
@app.route('/api/templates', methods=['GET'])
def get_templates():
"""Récupère les modèles de configuration disponibles"""
templates = {
'facture': {
'name': 'Facture',
'description': 'Configuration pour traiter des factures',
'yaml': '''
fields:
- name: "numero_facture"
type: "text"
position: "top-right"
required: true
- name: "montant_total"
type: "currency"
position: "bottom-right"
currency: "EUR"
'''
},
'contrat': {
'name': 'Contrat',
'description': 'Configuration pour traiter des contrats',
'yaml': '''
fields:
- name: "titre_contrat"
type: "text"
position: "top-center"
- name: "parties_contractantes"
type: "text"
position: "center"
multiline: true
'''
}
}
return jsonify(templates)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)Code HTML pour l'interface utilisateur
html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ParseMyFile - Interface de traitement</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.container { max-width: 800px; margin: 0 auto; }
.form-group { margin-bottom: 20px; }
label { display: block; margin-bottom: 5px; font-weight: bold; }
input[type="file"] { width: 100%; padding: 10px; }
button { background: #007bff; color: white; padding: 10px 20px; border: none; cursor: pointer; }
button:hover { background: #0056b3; }
.result { margin-top: 20px; padding: 20px; background: #f8f9fa; border-radius: 5px; }
.error { background: #f8d7da; color: #721c24; }
.success { background: #d4edda; color: #155724; }
</style>
</head>
<body>
<div class="container">
<h1>ParseMyFile - Traitement de documents</h1>
<form id="processForm" enctype="multipart/form-data">
<div class="form-group">
<label for="file">Document à traiter :</label>
<input type="file" id="file" name="file" accept=".pdf,.jpg,.jpeg,.png,.tiff,.bmp" required>
</div>
<div class="form-group">
<label for="yaml_file">Configuration YAML :</label>
<input type="file" id="yaml_file" name="yaml_file" accept=".yaml,.yml" required>
</div>
<button type="submit">Traiter le document</button>
</form>
<div id="result" class="result" style="display: none;"></div>
</div>
<script>
document.getElementById('processForm').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData();
const fileInput = document.getElementById('file');
const yamlInput = document.getElementById('yaml_file');
const resultDiv = document.getElementById('result');
if (fileInput.files.length === 0 || yamlInput.files.length === 0) {
showResult('Veuillez sélectionner les deux fichiers', 'error');
return;
}
formData.append('file', fileInput.files[0]);
formData.append('yaml_file', yamlInput.files[0]);
try {
showResult('Traitement en cours...', 'info');
const response = await fetch('/api/process', {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.success) {
showResult(`
<h3>✅ Document traité avec succès</h3>
<h4>Données extraites :</h4>
<pre>${JSON.stringify(result.data.extracted_fields, null, 2)}</pre>
<h4>Métadonnées :</h4>
<pre>${JSON.stringify(result.data.metadata, null, 2)}</pre>
`, 'success');
} else {
showResult(`❌ Erreur : ${result.error}`, 'error');
}
} catch (error) {
showResult(`❌ Erreur : ${error.message}`, 'error');
}
});
function showResult(message, type) {
const resultDiv = document.getElementById('result');
resultDiv.innerHTML = message;
resultDiv.className = `result ${type}`;
resultDiv.style.display = 'block';
}
</script>
</body>
</html>Ces exemples avancés montrent comment utiliser l'API ParseMyFile dans des contextes complexes et professionnels, avec validation, intégration base de données, et création d'APIs REST personnalisées.