Spaces:
Sleeping
Sleeping
| <script lang="ts"> | |
| import { previousRfps, nextStep } from '../stores/appStore' | |
| import { parseDocument } from '../utils/documentParser' | |
| let dragActive = false | |
| let isProcessing = false | |
| let uploadedFiles: File[] = [] | |
| let processingStatus = '' | |
| let analysisResults: any[] = [] | |
| // For accuracy, we'll scan the local folder as well | |
| let folderPath = 'c:\\Users\\varun\\Downloads\\RFP Svelt\\public\\previous-rfps' | |
| async function handleFileUpload(event: Event) { | |
| const target = event.target as HTMLInputElement | |
| if (target.files) { | |
| await processFiles(Array.from(target.files)) | |
| } | |
| } | |
| async function processFiles(files: File[]) { | |
| isProcessing = true | |
| processingStatus = 'Analyzing documents for accuracy...' | |
| uploadedFiles = [...uploadedFiles, ...files] | |
| try { | |
| for (const file of files) { | |
| processingStatus = `Processing ${file.name}...` | |
| const content = await parseDocument(file) | |
| // Enhanced analysis for accuracy | |
| const analysis = analyzeDocumentQuality(content, file.name) | |
| analysisResults.push(analysis) | |
| const rfpDocument = { | |
| id: `rfp-${Date.now()}-${Math.random()}`, | |
| name: file.name, | |
| content: content, | |
| size: file.size, | |
| uploadDate: new Date().toISOString(), | |
| pageCount: Math.ceil(content.length / 2000), // Estimate pages | |
| quality: analysis.quality, | |
| keyTopics: analysis.topics, | |
| wordCount: content.split(' ').length | |
| } | |
| previousRfps.update(current => [...current, rfpDocument]) | |
| } | |
| processingStatus = 'Analysis complete! Documents ready for AI reference.' | |
| } catch (error) { | |
| console.error('Error processing files:', error) | |
| processingStatus = 'Error processing some files. Please check format and try again.' | |
| } finally { | |
| setTimeout(() => { | |
| isProcessing = false | |
| processingStatus = '' | |
| }, 2000) | |
| } | |
| } | |
| function analyzeDocumentQuality(content: string, filename: string) { | |
| const wordCount = content.split(' ').length | |
| const hasQuestions = /\?|what|how|when|where|why|describe|explain|provide/gi.test(content) | |
| const hasAnswers = content.length > 5000 // Substantial content | |
| const hasStructure = /section|chapter|\d+\.|bullet|β’/gi.test(content) | |
| let quality = 'Basic' | |
| let score = 0 | |
| if (wordCount > 1000) score += 25 | |
| if (wordCount > 5000) score += 25 | |
| if (hasQuestions) score += 20 | |
| if (hasAnswers) score += 20 | |
| if (hasStructure) score += 10 | |
| if (score >= 80) quality = 'Excellent' | |
| else if (score >= 60) quality = 'Good' | |
| else if (score >= 40) quality = 'Fair' | |
| // Extract key topics | |
| const topics = extractKeyTopics(content) | |
| return { | |
| quality, | |
| score, | |
| topics, | |
| wordCount, | |
| hasQuestions, | |
| hasAnswers, | |
| hasStructure, | |
| recommendations: getRecommendations(score, hasQuestions, hasAnswers) | |
| } | |
| } | |
| function extractKeyTopics(content: string) { | |
| const businessTerms = [ | |
| 'security', 'compliance', 'implementation', 'timeline', 'budget', 'experience', | |
| 'methodology', 'team', 'project management', 'deliverables', 'support', | |
| 'training', 'maintenance', 'scalability', 'performance', 'integration' | |
| ] | |
| return businessTerms.filter(term => | |
| content.toLowerCase().includes(term) | |
| ).slice(0, 5) | |
| } | |
| function getRecommendations(score: number, hasQuestions: boolean, hasAnswers: boolean) { | |
| const recommendations = [] | |
| if (score < 40) { | |
| recommendations.push('Consider adding more detailed RFP responses') | |
| } | |
| if (!hasQuestions) { | |
| recommendations.push('Include documents with both questions and answers') | |
| } | |
| if (!hasAnswers) { | |
| recommendations.push('Add more comprehensive response content') | |
| } | |
| if (score >= 80) { | |
| recommendations.push('Excellent reference material for AI training') | |
| } | |
| return recommendations | |
| } | |
| function handleDrop(event: DragEvent) { | |
| event.preventDefault() | |
| dragActive = false | |
| if (event.dataTransfer?.files) { | |
| processFiles(Array.from(event.dataTransfer.files)) | |
| } | |
| } | |
| function handleDragOver(event: DragEvent) { | |
| event.preventDefault() | |
| dragActive = true | |
| } | |
| function handleDragLeave() { | |
| dragActive = false | |
| } | |
| function removeDocument(id: string) { | |
| previousRfps.update(current => current.filter(doc => doc.id !== id)) | |
| uploadedFiles = uploadedFiles.filter((_, index) => $previousRfps[index]?.id !== id) | |
| } | |
| function proceedToNextStep() { | |
| if ($previousRfps.length > 0) { | |
| nextStep() | |
| } | |
| } | |
| function getQualityColor(quality: string) { | |
| switch (quality) { | |
| case 'Excellent': return 'text-green-600 bg-green-100 border-green-200' | |
| case 'Good': return 'text-blue-600 bg-blue-100 border-blue-200' | |
| case 'Fair': return 'text-yellow-600 bg-yellow-100 border-yellow-200' | |
| default: return 'text-gray-600 bg-gray-100 border-gray-200' | |
| } | |
| } | |
| </script> | |
| <div class="space-y-8"> | |
| <!-- Instructions Section --> | |
| <div class="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-2xl p-6 border border-blue-200"> | |
| <div class="flex items-start space-x-4"> | |
| <div class="w-12 h-12 bg-blue-500 rounded-xl flex items-center justify-center text-white text-2xl"> | |
| π‘ | |
| </div> | |
| <div class="flex-1"> | |
| <h3 class="text-lg font-bold text-blue-900 mb-2">For Maximum Accuracy</h3> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm text-blue-800"> | |
| <div> | |
| <h4 class="font-semibold mb-1">π Folder Method (Recommended)</h4> | |
| <p>Add PDFs to: <code class="bg-blue-200 px-2 py-1 rounded text-xs">public/previous-rfps/</code></p> | |
| </div> | |
| <div> | |
| <h4 class="font-semibold mb-1">π€ Upload Method</h4> | |
| <p>Drag & drop your best RFP responses below</p> | |
| </div> | |
| </div> | |
| <div class="mt-3 text-sm text-blue-700"> | |
| <strong>Best Practice:</strong> Include 3-5 complete RFP responses with both questions and detailed answers for optimal AI accuracy. | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Upload Area --> | |
| <div class="bg-white rounded-2xl border-2 border-dashed border-slate-300 hover:border-blue-400 transition-colors duration-300 overflow-hidden"> | |
| <div | |
| class="relative p-12 text-center {dragActive ? 'bg-blue-50' : 'bg-gray-50'}" | |
| on:drop={handleDrop} | |
| on:dragover={handleDragOver} | |
| on:dragleave={handleDragLeave} | |
| > | |
| <input | |
| type="file" | |
| multiple | |
| accept=".pdf,.docx,.doc,.txt" | |
| on:change={handleFileUpload} | |
| class="absolute inset-0 opacity-0 cursor-pointer" | |
| /> | |
| {#if isProcessing} | |
| <div class="flex flex-col items-center space-y-4"> | |
| <div class="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div> | |
| <p class="text-blue-600 font-semibold">{processingStatus}</p> | |
| </div> | |
| {:else} | |
| <div class="flex flex-col items-center space-y-4"> | |
| <div class="w-20 h-20 bg-gradient-to-r from-blue-500 to-indigo-600 rounded-2xl flex items-center justify-center text-white text-4xl"> | |
| π | |
| </div> | |
| <div> | |
| <h3 class="text-2xl font-bold text-gray-800 mb-2">Upload Previous RFPs</h3> | |
| <p class="text-gray-600 mb-4">Drop your RFP documents here or click to browse</p> | |
| <p class="text-sm text-gray-500">Supports PDF, DOCX, DOC, and TXT files</p> | |
| </div> | |
| </div> | |
| {/if} | |
| </div> | |
| </div> | |
| <!-- Folder Instructions --> | |
| <div class="bg-gradient-to-r from-green-50 to-emerald-50 rounded-2xl p-6 border border-green-200"> | |
| <div class="flex items-center space-x-3 mb-3"> | |
| <div class="w-8 h-8 bg-green-500 rounded-lg flex items-center justify-center text-white text-lg"> | |
| π | |
| </div> | |
| <h3 class="text-lg font-bold text-green-900">Alternative: Use Local Folder</h3> | |
| </div> | |
| <p class="text-green-800 mb-3"> | |
| For better organization and accuracy, you can add your RFP documents directly to the folder: | |
| </p> | |
| <div class="bg-white rounded-lg p-4 border border-green-200"> | |
| <code class="text-sm text-green-700 font-mono break-all"> | |
| {folderPath} | |
| </code> | |
| </div> | |
| <p class="text-sm text-green-700 mt-2"> | |
| The system will automatically detect and analyze documents in this folder for AI reference. | |
| </p> | |
| </div> | |
| <!-- Document Analysis Results --> | |
| {#if $previousRfps.length > 0} | |
| <div class="bg-white rounded-2xl shadow-lg border border-gray-200 overflow-hidden"> | |
| <div class="bg-gradient-to-r from-gray-800 to-gray-900 p-6"> | |
| <div class="flex items-center justify-between"> | |
| <div class="flex items-center space-x-3"> | |
| <div class="w-10 h-10 bg-white rounded-lg flex items-center justify-center text-gray-800 text-xl"> | |
| π | |
| </div> | |
| <div> | |
| <h3 class="text-xl font-bold text-white">Document Analysis</h3> | |
| <p class="text-gray-300">{$previousRfps.length} documents analyzed for AI accuracy</p> | |
| </div> | |
| </div> | |
| <button | |
| on:click={proceedToNextStep} | |
| class="bg-gradient-to-r from-green-500 to-emerald-600 text-white px-6 py-3 rounded-xl font-semibold hover:from-green-600 hover:to-emerald-700 transition-all duration-300 shadow-lg" | |
| > | |
| Continue to Questions β | |
| </button> | |
| </div> | |
| </div> | |
| <div class="p-6 space-y-4"> | |
| {#each $previousRfps as doc, index} | |
| <div class="border border-gray-200 rounded-xl p-4 hover:shadow-lg transition-shadow"> | |
| <div class="flex items-start justify-between"> | |
| <div class="flex-1"> | |
| <div class="flex items-center space-x-3 mb-3"> | |
| <div class="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center text-blue-600 text-sm font-bold"> | |
| {index + 1} | |
| </div> | |
| <h4 class="font-semibold text-gray-800">{doc.name}</h4> | |
| <span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium border {getQualityColor(doc.quality)}"> | |
| {doc.quality} Quality | |
| </span> | |
| </div> | |
| <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-3 text-sm"> | |
| <div> | |
| <span class="text-gray-500">Words:</span> | |
| <span class="font-semibold text-gray-800">{doc.wordCount?.toLocaleString()}</span> | |
| </div> | |
| <div> | |
| <span class="text-gray-500">Pages:</span> | |
| <span class="font-semibold text-gray-800">{doc.pageCount}</span> | |
| </div> | |
| <div> | |
| <span class="text-gray-500">Size:</span> | |
| <span class="font-semibold text-gray-800">{(doc.size / 1024 / 1024).toFixed(1)} MB</span> | |
| </div> | |
| <div> | |
| <span class="text-gray-500">Score:</span> | |
| <span class="font-semibold text-gray-800">{analysisResults[index]?.score || 'N/A'}/100</span> | |
| </div> | |
| </div> | |
| {#if doc.keyTopics && doc.keyTopics.length > 0} | |
| <div class="flex flex-wrap gap-2 mb-3"> | |
| <span class="text-sm text-gray-500">Topics:</span> | |
| {#each doc.keyTopics as topic} | |
| <span class="inline-flex items-center px-2 py-1 bg-blue-100 text-blue-800 text-xs rounded-full"> | |
| {topic} | |
| </span> | |
| {/each} | |
| </div> | |
| {/if} | |
| {#if analysisResults[index]?.recommendations} | |
| <div class="text-sm text-gray-600"> | |
| <strong>AI Recommendation:</strong> {analysisResults[index].recommendations[0]} | |
| </div> | |
| {/if} | |
| </div> | |
| <button | |
| on:click={() => removeDocument(doc.id)} | |
| class="ml-4 w-8 h-8 bg-red-100 hover:bg-red-200 rounded-lg flex items-center justify-center text-red-600 transition-colors" | |
| title="Remove document" | |
| > | |
| Γ | |
| </button> | |
| </div> | |
| </div> | |
| {/each} | |
| </div> | |
| </div> | |
| {/if} | |
| <!-- Accuracy Tips --> | |
| <div class="bg-gradient-to-r from-purple-50 to-pink-50 rounded-2xl p-6 border border-purple-200"> | |
| <div class="flex items-start space-x-4"> | |
| <div class="w-12 h-12 bg-purple-500 rounded-xl flex items-center justify-center text-white text-2xl"> | |
| π― | |
| </div> | |
| <div> | |
| <h3 class="text-lg font-bold text-purple-900 mb-3">Maximizing AI Accuracy</h3> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm text-purple-800"> | |
| <div> | |
| <h4 class="font-semibold mb-2">β Best Documents Include:</h4> | |
| <ul class="space-y-1 text-purple-700"> | |
| <li>β’ Complete question-answer pairs</li> | |
| <li>β’ Technical specifications</li> | |
| <li>β’ Company methodologies</li> | |
| <li>β’ Previous winning proposals</li> | |
| </ul> | |
| </div> | |
| <div> | |
| <h4 class="font-semibold mb-2">β‘ For Optimal Results:</h4> | |
| <ul class="space-y-1 text-purple-700"> | |
| <li>β’ Upload 3-5 comprehensive RFPs</li> | |
| <li>β’ Include recent proposals (last 2 years)</li> | |
| <li>β’ Ensure documents are well-formatted</li> | |
| <li>β’ Mix different industry sectors</li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |