Spaces:
Sleeping
Sleeping
File size: 9,586 Bytes
c075953 4a6c290 c075953 a706099 02158b8 a706099 f444dc0 3ecd1bf 70e74ea e79fdda 70e74ea 4a6c290 8066d07 70e74ea 3ecd1bf 70e74ea 3ecd1bf 70e74ea a706099 8d0b379 a706099 8d0b379 f444dc0 63428e7 a706099 9ded9e1 a706099 9f60175 3ecd1bf 70e74ea 9f60175 4a6c290 98d2bd7 a706099 9ded9e1 c075953 a706099 c075953 e79fdda ae3be96 f444dc0 9f60175 f444dc0 9f60175 3ecd1bf d38750a f444dc0 c075953 b1e57e4 63428e7 e79fdda a706099 e79fdda ae3be96 e79fdda d38750a f444dc0 70e74ea a706099 70e74ea 3ecd1bf e79fdda b1e57e4 a706099 c075953 |
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 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
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';
import WelcomeScreen from './WelcomeScreen';
import OnboardingWizard from './OnboardingWizard';
import Highlights from '../highlights.json';
function DocumentProcessor({ initialFile, fileName, academicBackground }) {
const onboardingData = {
hasFile: !!initialFile,
fileName,
academicBackground
};
// State for PDF navigation
const [pdfNavigation, setPdfNavigation] = useState(null);
// State for first LLM response loading
const [waitingForFirstResponse, setWaitingForFirstResponse] = useState(false);
// State for welcome screen visibility - if coming from onboarding, skip welcome
const [showWelcomeScreen, setShowWelcomeScreen] = useState(!onboardingData?.hasFile);
// State for document controls (like scrollToPage)
const [documentControls, setDocumentControls] = useState(null);
// State for onboarding wizard
const [showOnboarding, setShowOnboarding] = useState(!!onboardingData?.hasFile);
const [onboardingCompleted, setOnboardingCompleted] = useState(false);
// Custom hooks
const {
fileInputRef,
selectedFile,
processing,
uploadProgress,
documentData,
handleFileChange,
processDocument,
setSelectedFile
} = useDocumentProcessor();
// Auto-load document when coming from onboarding
useEffect(() => {
if (onboardingData?.hasFile && initialFile && !selectedFile && !documentData) {
// Use the actual uploaded file
setSelectedFile(initialFile);
setTimeout(() => {
processDocument();
}, 500);
}
}, [onboardingData, selectedFile, documentData, setSelectedFile, processDocument, initialFile]);
// Function to get the page number of the first chunk
const getFirstChunkPage = () => {
if (testPreloadedHighlights && testPreloadedHighlights[0] && testPreloadedHighlights[0].length > 0) {
return testPreloadedHighlights[0][0].position.boundingRect.pageNumber;
}
return 1; // Default to page 1 if no highlights found
};
// Function to handle "Let's start" click
const handleGetStarted = () => {
setShowWelcomeScreen(false);
// Scroll to the first chunk after a short delay to ensure the PDF viewer is ready
if (documentControls && documentControls.scrollToFirstChunk) {
setTimeout(() => {
documentControls.scrollToFirstChunk();
}, 500);
} else {
// Retry after a longer delay
setTimeout(() => {
if (documentControls && documentControls.scrollToFirstChunk) {
documentControls.scrollToFirstChunk();
}
}, 2000);
}
};
// Function to handle onboarding completion
const handleOnboardingComplete = (onboardingPreferences) => {
console.log('Onboarding preferences:', onboardingPreferences);
setShowOnboarding(false);
setOnboardingCompleted(true);
// TODO: Store onboarding preferences for use in tutoring
// Scroll to the first chunk after a short delay
if (documentControls && documentControls.scrollToFirstChunk) {
setTimeout(() => {
documentControls.scrollToFirstChunk();
}, 500);
}
};
const {
chunkStates,
currentChunkIndex,
chunkExpanded,
showChat,
goToNextChunk,
goToPrevChunk,
skipChunk,
markChunkUnderstood,
startInteractiveLesson,
setChunkExpanded,
setShowChat,
setChunkAsInteractive,
updateGlobalChatHistory,
getGlobalChatHistory,
addMessageToChunk,
getCurrentChunkMessages,
hasChunkMessages,
isChunkLoading,
streamResponse
} = useChunkNavigation(documentData);
const {
leftPanelWidth,
isDragging,
containerRef,
handleMouseDown
} = usePanelResize(50);
// Add test preloaded highlights data - keyed by chunk index
// Lennart version
const testPreloadedHighlights = Highlights;
// Temporarily inject test highlights into documentData for testing
const documentDataWithHighlights = documentData ? {
...documentData,
preloadedHighlights: testPreloadedHighlights
} : null;
// 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();
};
// 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={documentDataWithHighlights}
onPageChange={setPdfNavigation}
preloadedHighlights={documentDataWithHighlights?.preloadedHighlights || null}
currentChunkIndex={currentChunkIndex}
onDocumentReady={setDocumentControls}
isChunkLoading={isChunkLoading}
/>
</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>
{/* Right Panel Content - Welcome Screen, Onboarding, or Chunk Panel */}
<div className="flex-1 flex flex-col min-h-0 bg-white rounded-lg shadow-sm">
{showOnboarding ? (
<OnboardingWizard
fileName={onboardingData?.fileName || 'Unknown Paper'}
academicBackground={onboardingData?.academicBackground || ''}
onComplete={handleOnboardingComplete}
/>
) : showWelcomeScreen ? (
<WelcomeScreen onGetStarted={handleGetStarted} />
) : (
<ChunkPanel
documentData={documentDataWithHighlights}
currentChunkIndex={currentChunkIndex}
showChat={showChat}
updateGlobalChatHistory={updateGlobalChatHistory}
getGlobalChatHistory={getGlobalChatHistory}
addMessageToChunk={addMessageToChunk}
getCurrentChunkMessages={getCurrentChunkMessages}
hasChunkMessages={hasChunkMessages}
setWaitingForFirstResponse={setWaitingForFirstResponse}
isChunkLoading={isChunkLoading}
markChunkUnderstood={markChunkUnderstood}
skipChunk={skipChunk}
goToPrevChunk={goToPrevChunk}
streamResponse={streamResponse}
/>
)}
</div>
</div>
</div>
);
}
export default DocumentProcessor; |