feat(api): alignement back/front + support functionalType/mimeType + modes simple/complete (VITE_BACKEND_MODE)
This commit is contained in:
parent
013a6dda0a
commit
6600308d61
161
docs/API.md
161
docs/API.md
@ -13,174 +13,80 @@ d'analyse de documents notariaux.
|
|||||||
http://localhost:8000 (développement)
|
http://localhost:8000 (développement)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Modes d'API pris en charge
|
||||||
|
|
||||||
|
- **Mode simple** (`VITE_BACKEND_MODE=simple`) : endpoints sous `/api/notary/...`
|
||||||
|
- **Mode complet** (`VITE_BACKEND_MODE=complete`) : endpoints sous `/api/documents/...`
|
||||||
|
|
||||||
|
La variable d'environnement `VITE_BACKEND_MODE` pilote dynamiquement le choix des endpoints côté front.
|
||||||
|
|
||||||
### Endpoints
|
### Endpoints
|
||||||
|
|
||||||
#### Upload de document
|
#### Upload de document
|
||||||
|
|
||||||
```http
|
```http
|
||||||
POST /api/documents/upload
|
POST /api/notary/upload # mode simple
|
||||||
|
POST /api/documents/upload # mode complet
|
||||||
Content-Type: multipart/form-data
|
Content-Type: multipart/form-data
|
||||||
|
|
||||||
Body: FormData avec le fichier
|
Body: FormData avec le fichier
|
||||||
```
|
```
|
||||||
|
|
||||||
**Réponse :**
|
**Réponse (champs attendus et utilisés par le front) :**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"document_id": "doc_123456", // ou "id"
|
||||||
|
"mime_type": "application/pdf", // ou "mimeType"
|
||||||
|
"functional_type": "CNI" // ou "functionalType" (type fonctionnel métier)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Le front mappe en `Document`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"id": "doc_123456",
|
"id": "doc_123456",
|
||||||
"name": "acte_vente.pdf",
|
"name": "acte_vente.pdf",
|
||||||
"type": "application/pdf",
|
"mimeType": "application/pdf",
|
||||||
|
"functionalType": "CNI",
|
||||||
"size": 1024000,
|
"size": 1024000,
|
||||||
"uploadDate": "2024-01-15T10:30:00Z",
|
"uploadDate": "<date locale>",
|
||||||
"status": "completed"
|
"status": "completed",
|
||||||
|
"previewUrl": "blob:..."
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Extraction de données
|
#### Extraction de données
|
||||||
|
|
||||||
```http
|
```http
|
||||||
GET /api/documents/{documentId}/extract
|
GET /api/notary/documents/{documentId} # mode simple (détails document + résultats)
|
||||||
```
|
GET /api/documents/{documentId}/extract # mode complet
|
||||||
|
|
||||||
**Réponse :**
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"documentId": "doc_123456",
|
|
||||||
"text": "Texte extrait du document...",
|
|
||||||
"language": "fr",
|
|
||||||
"documentType": "Acte de vente",
|
|
||||||
"identities": [
|
|
||||||
{
|
|
||||||
"id": "1",
|
|
||||||
"type": "person",
|
|
||||||
"firstName": "Jean",
|
|
||||||
"lastName": "Dupont",
|
|
||||||
"birthDate": "1980-05-15",
|
|
||||||
"nationality": "Française",
|
|
||||||
"confidence": 0.95
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"addresses": [
|
|
||||||
{
|
|
||||||
"street": "123 Rue de la Paix",
|
|
||||||
"city": "Paris",
|
|
||||||
"postalCode": "75001",
|
|
||||||
"country": "France"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": [
|
|
||||||
{
|
|
||||||
"id": "1",
|
|
||||||
"type": "apartment",
|
|
||||||
"address": {
|
|
||||||
"street": "123 Rue de la Paix",
|
|
||||||
"city": "Paris",
|
|
||||||
"postalCode": "75001",
|
|
||||||
"country": "France"
|
|
||||||
},
|
|
||||||
"surface": 75,
|
|
||||||
"cadastralReference": "1234567890AB",
|
|
||||||
"value": 250000
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"contracts": [
|
|
||||||
{
|
|
||||||
"id": "1",
|
|
||||||
"type": "sale",
|
|
||||||
"parties": [],
|
|
||||||
"amount": 250000,
|
|
||||||
"date": "2024-01-15",
|
|
||||||
"clauses": ["Clause de garantie", "Clause de condition suspensive"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"signatures": ["Jean Dupont", "Marie Martin"],
|
|
||||||
"confidence": 0.92
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Analyse du document
|
#### Analyse du document
|
||||||
|
|
||||||
```http
|
```http
|
||||||
GET /api/documents/{documentId}/analyze
|
GET /api/documents/{documentId}/analyze # mode complet
|
||||||
```
|
```
|
||||||
|
|
||||||
**Réponse :**
|
(mode simple: synthèse construite côté front à partir de `/api/notary/documents/{documentId}`)
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"documentId": "doc_123456",
|
|
||||||
"documentType": "Acte de vente",
|
|
||||||
"isCNI": false,
|
|
||||||
"credibilityScore": 0.88,
|
|
||||||
"summary": "Document analysé avec succès. Toutes les informations semblent cohérentes.",
|
|
||||||
"recommendations": [
|
|
||||||
"Vérifier l'identité des parties auprès des autorités compétentes",
|
|
||||||
"Contrôler la validité des documents cadastraux"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Données contextuelles
|
#### Données contextuelles
|
||||||
|
|
||||||
```http
|
```http
|
||||||
GET /api/documents/{documentId}/context
|
GET /api/documents/{documentId}/context # mode complet
|
||||||
```
|
```
|
||||||
|
|
||||||
**Réponse :**
|
(mode simple: non disponible — fallback de démonstration)
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"documentId": "doc_123456",
|
|
||||||
"cadastreData": {
|
|
||||||
"status": "disponible",
|
|
||||||
"reference": "1234567890AB"
|
|
||||||
},
|
|
||||||
"georisquesData": {
|
|
||||||
"status": "aucun risque identifié"
|
|
||||||
},
|
|
||||||
"geofoncierData": {
|
|
||||||
"status": "données disponibles"
|
|
||||||
},
|
|
||||||
"bodaccData": {
|
|
||||||
"status": "aucune procédure en cours"
|
|
||||||
},
|
|
||||||
"infogreffeData": {
|
|
||||||
"status": "entreprise en règle"
|
|
||||||
},
|
|
||||||
"lastUpdated": "2024-01-15T10:30:00Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Conseil IA
|
#### Conseil IA
|
||||||
|
|
||||||
```http
|
```http
|
||||||
GET /api/documents/{documentId}/conseil
|
GET /api/documents/{documentId}/conseil # mode complet
|
||||||
```
|
```
|
||||||
|
|
||||||
**Réponse :**
|
(mode simple: non disponible — fallback de démonstration)
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"documentId": "doc_123456",
|
|
||||||
"analysis": "Ce document présente toutes les caractéristiques d'un acte notarial standard.",
|
|
||||||
"recommendations": [
|
|
||||||
"Procéder à la vérification d'identité des parties",
|
|
||||||
"Contrôler la validité des documents fournis"
|
|
||||||
],
|
|
||||||
"risks": [
|
|
||||||
"Risque faible : Vérification d'identité recommandée",
|
|
||||||
"Risque moyen : Contrôle cadastral nécessaire"
|
|
||||||
],
|
|
||||||
"nextSteps": [
|
|
||||||
"Collecter les pièces d'identité des parties",
|
|
||||||
"Vérifier les documents cadastraux",
|
|
||||||
"Préparer l'acte final"
|
|
||||||
],
|
|
||||||
"generatedAt": "2024-01-15T10:30:00Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## APIs Externes
|
## APIs Externes
|
||||||
|
|
||||||
@ -235,6 +141,7 @@ En cas d'erreur, l'application bascule automatiquement vers des données de dém
|
|||||||
|
|
||||||
```env
|
```env
|
||||||
VITE_API_URL=http://localhost:8000
|
VITE_API_URL=http://localhost:8000
|
||||||
|
VITE_BACKEND_MODE=simple
|
||||||
VITE_CADASTRE_API_URL=https://api.cadastre.gouv.fr
|
VITE_CADASTRE_API_URL=https://api.cadastre.gouv.fr
|
||||||
VITE_GEORISQUES_API_URL=https://www.georisques.gouv.fr/api
|
VITE_GEORISQUES_API_URL=https://www.georisques.gouv.fr/api
|
||||||
VITE_GEOFONCIER_API_URL=https://api.geofoncier.fr
|
VITE_GEOFONCIER_API_URL=https://api.geofoncier.fr
|
||||||
|
@ -59,7 +59,7 @@ export const FilePreview: React.FC<FilePreviewProps> = ({ document, onClose }) =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPDF = document.type.includes('pdf') || document.name.toLowerCase().endsWith('.pdf')
|
const isPDF = document.mimeType.includes('pdf') || document.name.toLowerCase().endsWith('.pdf')
|
||||||
|
|
||||||
if (!isPDF) {
|
if (!isPDF) {
|
||||||
return (
|
return (
|
||||||
@ -71,7 +71,7 @@ export const FilePreview: React.FC<FilePreviewProps> = ({ document, onClose }) =
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
<Alert severity="info">
|
<Alert severity="info">
|
||||||
Aperçu non disponible pour ce type de fichier ({document.type})
|
Aperçu non disponible pour ce type de fichier ({document.functionalType || document.mimeType})
|
||||||
</Alert>
|
</Alert>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,7 @@ import axios from 'axios'
|
|||||||
import type { Document, ExtractionResult, AnalysisResult, ContextResult, ConseilResult } from '../types'
|
import type { Document, ExtractionResult, AnalysisResult, ContextResult, ConseilResult } from '../types'
|
||||||
|
|
||||||
const BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
|
const BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
|
||||||
|
const BACKEND_MODE = (import.meta.env.VITE_BACKEND_MODE || 'simple').toLowerCase() as 'simple' | 'complete'
|
||||||
|
|
||||||
export const apiClient = axios.create({
|
export const apiClient = axios.create({
|
||||||
baseURL: BASE_URL,
|
baseURL: BASE_URL,
|
||||||
@ -54,7 +55,8 @@ export const documentApi = {
|
|||||||
return {
|
return {
|
||||||
id: data.document_id || data.id || 'upload-' + Date.now(),
|
id: data.document_id || data.id || 'upload-' + Date.now(),
|
||||||
name: file.name,
|
name: file.name,
|
||||||
type: file.type || 'application/pdf',
|
mimeType: data.mime_type || data.mimeType || file.type || 'application/pdf',
|
||||||
|
functionalType: data.functional_type || data.functionalType || undefined,
|
||||||
size: file.size,
|
size: file.size,
|
||||||
uploadDate: new Date(),
|
uploadDate: new Date(),
|
||||||
status: 'completed',
|
status: 'completed',
|
||||||
@ -69,7 +71,8 @@ export const documentApi = {
|
|||||||
return {
|
return {
|
||||||
id: 'demo-' + Date.now(),
|
id: 'demo-' + Date.now(),
|
||||||
name: file.name,
|
name: file.name,
|
||||||
type: file.type || 'application/pdf',
|
mimeType: file.type || 'application/pdf',
|
||||||
|
functionalType: undefined,
|
||||||
size: file.size,
|
size: file.size,
|
||||||
uploadDate: new Date(),
|
uploadDate: new Date(),
|
||||||
status: 'completed',
|
status: 'completed',
|
||||||
@ -189,8 +192,24 @@ export const documentApi = {
|
|||||||
// Analyse du document
|
// Analyse du document
|
||||||
analyze: async (documentId: string): Promise<AnalysisResult> => {
|
analyze: async (documentId: string): Promise<AnalysisResult> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await apiClient.get<AnalysisResult>(`/api/documents/${documentId}/analyze`)
|
if (BACKEND_MODE === 'complete') {
|
||||||
return data
|
const { data } = await apiClient.get<AnalysisResult>(`/api/documents/${documentId}/analyze`)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
// Mode simple: pas d'endpoint d'analyse dédié -> utiliser le détail et synthétiser
|
||||||
|
const { data } = await apiClient.get(`/api/notary/documents/${documentId}`)
|
||||||
|
return {
|
||||||
|
documentId,
|
||||||
|
documentType: data?.results?.document_type || 'Document',
|
||||||
|
isCNI: (data?.results?.document_type || '').toLowerCase().includes('cni'),
|
||||||
|
credibilityScore: data?.results?.verification_score ?? 0.85,
|
||||||
|
summary: 'Analyse synthétique basée sur les métadonnées documentaires disponibles.',
|
||||||
|
recommendations: [
|
||||||
|
"Vérifier l'identité des parties",
|
||||||
|
"Contrôler la validité des documents cadastraux",
|
||||||
|
"S'assurer de la conformité des clauses contractuelles",
|
||||||
|
],
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Données de démonstration
|
// Données de démonstration
|
||||||
return {
|
return {
|
||||||
@ -211,8 +230,20 @@ export const documentApi = {
|
|||||||
// Données contextuelles
|
// Données contextuelles
|
||||||
getContext: async (documentId: string): Promise<ContextResult> => {
|
getContext: async (documentId: string): Promise<ContextResult> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await apiClient.get<ContextResult>(`/api/documents/${documentId}/context`)
|
if (BACKEND_MODE === 'complete') {
|
||||||
return data
|
const { data } = await apiClient.get<ContextResult>(`/api/documents/${documentId}/context`)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
// Mode simple: pas d'endpoint context -> démo
|
||||||
|
return {
|
||||||
|
documentId,
|
||||||
|
cadastreData: { status: "disponible", reference: "1234567890AB" },
|
||||||
|
georisquesData: { status: "aucun risque identifié" },
|
||||||
|
geofoncierData: { status: "données disponibles" },
|
||||||
|
bodaccData: { status: "aucune procédure en cours" },
|
||||||
|
infogreffeData: { status: "entreprise en règle" },
|
||||||
|
lastUpdated: new Date()
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Données de démonstration
|
// Données de démonstration
|
||||||
return {
|
return {
|
||||||
@ -230,8 +261,30 @@ export const documentApi = {
|
|||||||
// Conseil LLM
|
// Conseil LLM
|
||||||
getConseil: async (documentId: string): Promise<ConseilResult> => {
|
getConseil: async (documentId: string): Promise<ConseilResult> => {
|
||||||
try {
|
try {
|
||||||
const { data } = await apiClient.get<ConseilResult>(`/api/documents/${documentId}/conseil`)
|
if (BACKEND_MODE === 'complete') {
|
||||||
return data
|
const { data } = await apiClient.get<ConseilResult>(`/api/documents/${documentId}/conseil`)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
// Mode simple: pas d'endpoint conseil -> démo
|
||||||
|
return {
|
||||||
|
documentId,
|
||||||
|
analysis: "Ce document présente toutes les caractéristiques d'un acte notarial standard. Les informations sont cohérentes et les parties semblent légitimes. Aucun élément suspect n'a été détecté.",
|
||||||
|
recommendations: [
|
||||||
|
"Procéder à la vérification d'identité des parties",
|
||||||
|
"Contrôler la validité des documents fournis",
|
||||||
|
"S'assurer de la conformité réglementaire"
|
||||||
|
],
|
||||||
|
risks: [
|
||||||
|
"Risque faible : Vérification d'identité recommandée",
|
||||||
|
"Risque moyen : Contrôle cadastral nécessaire"
|
||||||
|
],
|
||||||
|
nextSteps: [
|
||||||
|
"Collecter les pièces d'identité des parties",
|
||||||
|
"Vérifier les documents cadastraux",
|
||||||
|
"Préparer l'acte final"
|
||||||
|
],
|
||||||
|
generatedAt: new Date()
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Données de démonstration
|
// Données de démonstration
|
||||||
return {
|
return {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
export interface Document {
|
export interface Document {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
type: string
|
mimeType: string
|
||||||
|
functionalType?: string
|
||||||
size: number
|
size: number
|
||||||
uploadDate: Date
|
uploadDate: Date
|
||||||
status: 'uploading' | 'processing' | 'completed' | 'error'
|
status: 'uploading' | 'processing' | 'completed' | 'error'
|
||||||
|
@ -136,7 +136,7 @@ export default function UploadView() {
|
|||||||
|
|
||||||
<Box display="flex" gap={1} flexWrap="wrap">
|
<Box display="flex" gap={1} flexWrap="wrap">
|
||||||
<Chip
|
<Chip
|
||||||
label={doc.type}
|
label={doc.functionalType || doc.mimeType}
|
||||||
size="small"
|
size="small"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user