Spaces:
Running
Running
File size: 6,877 Bytes
a50c30f ee8dccf a50c30f ee8dccf a50c30f ee8dccf a50c30f ee8dccf a50c30f ee8dccf a50c30f ee8dccf a50c30f ee8dccf a50c30f ee8dccf a50c30f ee8dccf a50c30f ee8dccf a50c30f ee8dccf a50c30f | 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 |
// Document content storage
let documentContent = '';
// Process uploaded document
async function processDocument(file) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => {
documentContent = e.target.result;
resolve({ success: true });
};
reader.readAsText(file);
});
}
// Enhanced document search with better matching and context
function searchDocument(question) {
if (!documentContent) return "Please upload a document first.";
const questionLower = question.toLowerCase();
const docLower = documentContent.toLowerCase();
// Split into meaningful units (paragraphs or sections)
const sections = documentContent.split(/\n\s*\n+/);
// First try exact matches or very close matches
for (const section of sections) {
const sectionLower = section.toLowerCase();
// Check for direct question matches
if (sectionLower.includes(questionLower)) {
return extractBestAnswer(section, questionLower);
}
// Check for "what is" questions
if (questionLower.startsWith('what is') || questionLower.startsWith('what are')) {
const targetTerm = questionLower.split(' ').slice(2).join(' ');
if (sectionLower.includes(targetTerm)) {
return extractDefinition(section, targetTerm);
}
}
// Check for "how to" questions
if (questionLower.startsWith('how to') || questionLower.startsWith('how do')) {
const action = questionLower.split(' ').slice(2).join(' ');
if (sectionLower.includes(action)) {
return extractInstructions(section, action);
}
}
}
// Try semantic matching with weighted keywords
const keywords = extractKeywords(questionLower);
let bestMatch = { text: '', score: 0 };
for (const section of sections) {
const sectionLower = section.toLowerCase();
let score = 0;
for (const keyword of keywords) {
if (sectionLower.includes(keyword)) {
score += keyword.weight;
// Bonus for proximity to other keywords
const keywordPos = sectionLower.indexOf(keyword);
for (const otherKeyword of keywords) {
if (otherKeyword !== keyword) {
const otherPos = sectionLower.indexOf(otherKeyword);
if (otherPos !== -1 && Math.abs(keywordPos - otherPos) < 100) {
score += 5;
}
}
}
}
}
if (score > bestMatch.score) {
bestMatch = { text: section, score };
}
}
if (bestMatch.score > 0) {
return extractRelevantPart(bestMatch.text, keywords);
}
// As last resort, try to find any relevant information
const relevant = findAnyRelevant(questionLower, sections);
if (relevant) return relevant;
return "I found some information that might be relevant, but couldn't find a direct answer to your question. Try asking differently or check these sections:\n" +
findPossibleSections(questionLower, sections);
}
// Helper functions
function extractKeywords(question) {
const words = question.split(' ').filter(w => w.length > 3);
const weights = {
'what': 1, 'how': 2, 'why': 2, 'when': 2, 'where': 2,
'is': 1, 'are': 1, 'does': 2, 'do': 1, 'can': 2,
'explain': 3, 'describe': 3, 'define': 3, 'list': 2
};
return words.map(word => ({
word: word,
weight: weights[word] || 1
}));
}
function extractBestAnswer(text, question) {
// Split into sentences
const sentences = text.split(/[.!?]+/).map(s => s.trim()).filter(s => s);
// Find the most relevant sentence
for (const sentence of sentences) {
if (sentence.toLowerCase().includes(question)) {
return sentence + '.';
}
}
// If no exact match, return first few sentences
return sentences.slice(0, 3).join(' ') + '...';
}
function extractDefinition(text, term) {
const sentences = text.split(/[.!?]+/);
for (let i = 0; i < sentences.length; i++) {
if (sentences[i].toLowerCase().includes(term)) {
// Try to get the definition sentence
if (sentences[i].toLowerCase().includes('is') || sentences[i].toLowerCase().includes('are')) {
return sentences[i].trim() + '.';
}
// Or combine with next sentence
if (i < sentences.length - 1) {
return (sentences[i] + ' ' + sentences[i+1]).trim() + '.';
}
}
}
return text.split('\n')[0]; // Fallback to first line
}
function findAnyRelevant(question, sections) {
const keywords = extractKeywords(question).map(k => k.word);
for (const section of sections) {
const sectionLower = section.toLowerCase();
let matches = 0;
for (const keyword of keywords) {
if (sectionLower.includes(keyword)) matches++;
}
if (matches >= keywords.length / 2) {
return "This might help:\n" + section.split('\n').slice(0, 3).join('\n') + '...';
}
}
return null;
}
function findPossibleSections(question, sections) {
const keywords = extractKeywords(question).map(k => k.word);
const relevantSections = [];
for (const section of sections) {
const sectionLower = section.toLowerCase();
let matches = 0;
for (const keyword of keywords) {
if (sectionLower.includes(keyword)) matches++;
}
if (matches > 0) {
const firstLine = section.split('\n')[0];
if (firstLine && !relevantSections.includes(firstLine)) {
relevantSections.push(firstLine);
}
}
}
return relevantSections.slice(0, 3).map(s => "• " + s).join('\n');
}
async function askQuestion(question) {
if (!documentContent) {
return { answer: "Please upload a document first." };
}
const answer = searchDocument(question);
// Enhance simple answers with more context
let enhancedAnswer = answer;
if (answer.includes('is') && !answer.includes('.')) {
// Try to find the next sentence for more context
const sentences = documentContent.split(/[.!?]+/);
const idx = sentences.findIndex(s => s.trim() + '.' === answer);
if (idx !== -1 && idx < sentences.length - 1) {
enhancedAnswer += ' ' + sentences[idx+1].trim() + '.';
}
}
return { answer: enhancedAnswer };
}
|