File size: 5,670 Bytes
2d3985c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5814eba
 
 
 
 
 
 
 
 
 
 
 
 
 
2d3985c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import React, { useState, useEffect } from 'react';
import DocumentUpload from './components/DocumentUpload';
import DocumentList from './components/DocumentList';
import ChatInterface from './components/ChatInterface';
import DebugConsole from './components/DebugConsole';
import './App.css';

function App() {
  const [documents, setDocuments] = useState([]);
  const [selectedDocument, setSelectedDocument] = useState(null);
  const [isBackendReady, setIsBackendReady] = useState(false);
  const [ws, setWs] = useState(null);

  // Initialisation du WebSocket
  useEffect(() => {
      const connectWebSocket = () => {
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    
    // Détection automatique de l'environnement
    let wsUrl;
    if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
      // Développement local : frontend port 3000, backend port 8000
      wsUrl = `${protocol}//localhost:8000/ws`;
    } else {
      // Production (HF Spaces) : même domaine, port 7860
      wsUrl = `${protocol}//${window.location.host}/ws`;
    }
    
    console.log('Tentative de connexion WebSocket:', wsUrl);
      
      const websocket = new WebSocket(wsUrl);
      
      websocket.onopen = () => {
        console.log('WebSocket connecté sur:', wsUrl);
        setWs(websocket);
      };
      
      websocket.onmessage = (event) => {
        console.log('Message WebSocket reçu dans App.js:', event.data);
        try {
          const data = JSON.parse(event.data);
          console.log('Message parsé:', data);
        } catch (e) {
          console.log('Message brut (non-JSON):', event.data);
        }
      };
      
      websocket.onclose = () => {
        console.log('WebSocket fermé, tentative de reconnexion...');
        setWs(null);
        setTimeout(connectWebSocket, 3000);
      };
      
      websocket.onerror = (error) => {
        console.error('Erreur WebSocket:', error);
      };
    };

    connectWebSocket();
    
    return () => {
      if (ws) {
        ws.close();
      }
    };
  }, []); // Ne pas inclure ws dans les dépendances pour éviter les reconnexions

  // Vérification de l'état du backend
  useEffect(() => {
    const checkBackendHealth = async () => {
      try {
        const response = await fetch('/api/health');
        setIsBackendReady(response.ok);
      } catch (error) {
        console.error('Backend non disponible:', error);
        setIsBackendReady(false);
      }
    };

    checkBackendHealth();
    const interval = setInterval(checkBackendHealth, 10000);
    return () => clearInterval(interval);
  }, []);

  // Chargement initial des documents
  useEffect(() => {
    loadDocuments();
  }, []);

  const loadDocuments = async () => {
    try {
      const response = await fetch('/api/documents');
      if (response.ok) {
        const data = await response.json();
        // S'assurer que nous avons un tableau
        const docs = Array.isArray(data) ? data : (data.documents && Array.isArray(data.documents) ? data.documents : []);
        setDocuments(docs);
      } else {
        console.warn('Erreur HTTP lors du chargement des documents:', response.status);
        setDocuments([]); // Réinitialiser à un tableau vide en cas d'erreur
      }
    } catch (error) {
      console.error('Erreur chargement documents:', error);
      setDocuments([]); // Réinitialiser à un tableau vide en cas d'erreur
    }
  };

  const handleDocumentUploaded = (newDoc) => {
    setDocuments(prev => [...prev, newDoc]);
    loadDocuments(); // Recharger pour avoir les infos complètes
  };

  const handleDocumentAnalyzed = (documentId) => {
    loadDocuments(); // Recharger pour mettre à jour le statut
  };

  const handleDocumentSelected = (doc) => {
    setSelectedDocument(doc);
  };

  const handleDocumentDeleted = (documentId) => {
    setDocuments(prev => prev.filter(doc => doc.document_id !== documentId));
    if (selectedDocument?.document_id === documentId) {
      setSelectedDocument(null);
    }
  };

  return (
    <div className="App">
      {/* Header */}
      <header className="app-header">
        <h1>RAG CHU - Assistant Médical IA</h1>
        <p>
          Analysez vos documents médicaux et posez vos questions
          {isBackendReady ? (
            <span style={{ color: '#10b981', marginLeft: '1rem' }}>
              ● Backend connecté
            </span>
          ) : (
            <span style={{ color: '#ef4444', marginLeft: '1rem' }}>
              ● Backend déconnecté
            </span>
          )}
        </p>
      </header>

      {/* Layout principal en 3 colonnes */}
      <div className="app-grid">
        
        {/* Colonne gauche - Documents (étroite) */}
        <div className="left-column">
          <DocumentUpload
            onDocumentUploaded={handleDocumentUploaded}
            onDocumentAnalyzed={handleDocumentAnalyzed}
          />
          
          <DocumentList
            documents={documents}
            selectedDocument={selectedDocument}
            onDocumentSelected={handleDocumentSelected}
            onDocumentDeleted={handleDocumentDeleted}
            onRefresh={loadDocuments}
          />
        </div>

        {/* Colonne centre - Chat (large) */}
        <div className="center-column">
          <ChatInterface
            selectedDocument={selectedDocument}
            ws={ws}
          />
        </div>

        {/* Colonne droite - Console Debug (fixe) */}
        <div className="right-column">
          <DebugConsole ws={ws} />
        </div>

      </div>
    </div>
  );
}

export default App;