Spaces:
Sleeping
Sleeping
| import 'katex/dist/katex.min.css'; | |
| import { useState, useEffect } from 'react'; | |
| // Import custom hooks | |
| import { useDocumentProcessor } from '../hooks/useDocumentProcessor'; | |
| import { useChunkNavigation } from '../hooks/useChunkNavigation'; | |
| import { usePanelResize } from '../hooks/usePanelResize'; | |
| // Import components | |
| import LoadingAnimation from './LoadingAnimation'; | |
| import DocumentViewer from './DocumentViewer'; | |
| import ChunkPanel from './ChunkPanel'; | |
| import ProgressBar from './ProgressBar'; | |
| function DocumentProcessor() { | |
| // State for PDF navigation | |
| const [pdfNavigation, setPdfNavigation] = useState(null); | |
| // State for first LLM response loading | |
| const [waitingForFirstResponse, setWaitingForFirstResponse] = useState(false); | |
| // Custom hooks | |
| const { | |
| fileInputRef, | |
| selectedFile, | |
| processing, | |
| uploadProgress, | |
| documentData, | |
| handleFileChange, | |
| processDocument, | |
| setSelectedFile | |
| } = useDocumentProcessor(); | |
| const { | |
| chunkStates, | |
| currentChunkIndex, | |
| chunkExpanded, | |
| showChat, | |
| isTransitioning, | |
| goToNextChunk, | |
| goToPrevChunk, | |
| skipChunk, | |
| markChunkUnderstood, | |
| startInteractiveLesson, | |
| setChunkExpanded, | |
| setShowChat, | |
| setChunkAsInteractive, | |
| updateGlobalChatHistory, | |
| getGlobalChatHistory, | |
| addMessageToChunk, | |
| getCurrentChunkMessages, | |
| hasChunkMessages, | |
| isChunkCompleted, | |
| canEditChunk | |
| } = useChunkNavigation(documentData, null); | |
| const { | |
| leftPanelWidth, | |
| isDragging, | |
| containerRef, | |
| handleMouseDown | |
| } = usePanelResize(50); | |
| // Sync PDF page navigation with chunk switching | |
| useEffect(() => { | |
| if (pdfNavigation && documentData && documentData.chunks[currentChunkIndex]) { | |
| const currentChunk = documentData.chunks[currentChunkIndex]; | |
| if (currentChunk.page && pdfNavigation.goToPage) { | |
| pdfNavigation.goToPage(currentChunk.page); | |
| } | |
| } | |
| }, [currentChunkIndex, pdfNavigation, documentData]); | |
| // Simplified startInteractiveLesson | |
| const handleStartInteractiveLesson = () => { | |
| startInteractiveLesson(); | |
| }; | |
| // Early returns for different states | |
| if (!selectedFile) { | |
| return ( | |
| <div className="h-screen bg-gray-50 flex items-center justify-center"> | |
| <input | |
| ref={fileInputRef} | |
| type="file" | |
| accept=".pdf" | |
| className="hidden" | |
| onChange={handleFileChange} | |
| /> | |
| <button | |
| onClick={() => fileInputRef.current.click()} | |
| className="px-6 py-3 bg-white shadow-md hover:shadow-lg text-gray-700 font-medium rounded-lg transition-all" | |
| > | |
| Select PDF | |
| </button> | |
| </div> | |
| ); | |
| } | |
| if (!documentData) { | |
| return ( | |
| <div className="h-screen bg-gray-50 flex items-center justify-center"> | |
| <div className="flex gap-4"> | |
| <button | |
| onClick={processDocument} | |
| className="px-6 py-3 bg-white shadow-md hover:shadow-lg text-gray-700 font-medium rounded-lg transition-all" | |
| > | |
| Process | |
| </button> | |
| <button | |
| onClick={() => setSelectedFile(null)} | |
| className="px-6 py-3 bg-white shadow-md hover:shadow-lg text-gray-700 font-medium rounded-lg transition-all" | |
| > | |
| ← Back | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| // Main render | |
| return ( | |
| <div | |
| ref={containerRef} | |
| className="h-screen bg-gray-100 flex gap-2 p-6 overflow-hidden" | |
| style={{ cursor: isDragging ? 'col-resize' : 'default' }} | |
| > | |
| {/* Left Panel - Document */} | |
| <div style={{ width: `${leftPanelWidth}%`, height: '100%' }} className="flex flex-col"> | |
| {/* Document Viewer */} | |
| <div className="flex-1 min-h-0"> | |
| <DocumentViewer | |
| selectedFile={selectedFile} | |
| documentData={documentData} | |
| onPageChange={setPdfNavigation} | |
| /> | |
| </div> | |
| </div> | |
| {/* Resizable Divider */} | |
| <div | |
| className="flex items-center justify-center cursor-col-resize group transition-all duration-200" | |
| style={{ width: '8px' }} | |
| onMouseDown={handleMouseDown} | |
| > | |
| <div | |
| className="w-px h-full rounded-full transition-all duration-200 group-hover:shadow-lg" | |
| style={{ | |
| backgroundColor: isDragging ? 'rgba(59, 130, 246, 0.8)' : 'transparent', | |
| boxShadow: isDragging ? '0 0 8px rgba(59, 130, 246, 0.8)' : 'none' | |
| }} | |
| ></div> | |
| </div> | |
| {/* Right Panel Container */} | |
| <div | |
| className="flex flex-col" | |
| style={{ width: `${100 - leftPanelWidth}%` }} | |
| > {/* Progress Bar */} | |
| <div className="mb-4 flex-shrink-0"> | |
| <ProgressBar | |
| currentChunkIndex={currentChunkIndex} | |
| totalChunks={documentData?.chunks?.length || 0} | |
| onChunkClick={null} // Start with linear progression only | |
| /> | |
| </div> | |
| {/* Chunk Panel */} | |
| <div className="flex-1 flex flex-col min-h-0 bg-white rounded-lg shadow-sm"> | |
| <ChunkPanel | |
| documentData={documentData} | |
| currentChunkIndex={currentChunkIndex} | |
| showChat={showChat} | |
| isTransitioning={isTransitioning} | |
| updateGlobalChatHistory={updateGlobalChatHistory} | |
| getGlobalChatHistory={getGlobalChatHistory} | |
| addMessageToChunk={addMessageToChunk} | |
| getCurrentChunkMessages={getCurrentChunkMessages} | |
| hasChunkMessages={hasChunkMessages} | |
| isChunkCompleted={isChunkCompleted} | |
| canEditChunk={canEditChunk} | |
| setWaitingForFirstResponse={setWaitingForFirstResponse} | |
| markChunkUnderstood={markChunkUnderstood} | |
| skipChunk={skipChunk} | |
| goToPrevChunk={goToPrevChunk} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| export default DocumentProcessor; |