|
const BASE_URL = "https://oevortex-webscout-api.hf.space"; |
|
const searchForm = document.getElementById("search-form"); |
|
const searchQueryInput = document.getElementById("search-query"); |
|
const resultsContainer = document.getElementById("results"); |
|
const suggestionsContainer = document.getElementById("suggestions"); |
|
const loadingOverlay = document.querySelector('.loading-overlay'); |
|
const noResultsMessage = document.getElementById('no-results'); |
|
const loadingMoreIndicator = document.getElementById('loading-more'); |
|
const aiResponseContainer = document.getElementById('ai-response'); |
|
|
|
const INITIAL_RESULTS = 5; |
|
const CACHED_RESULTS = 50; |
|
const RESULTS_PER_PAGE = 5; |
|
|
|
let allResultsFetched = false; |
|
const seenUrls = new Set(); |
|
let selectedSuggestionIndex = -1; |
|
let suggestionRequestTimeout; |
|
let cachedSearchResults = []; |
|
const suggestionCache = {}; |
|
let prefetchTimeout; |
|
let allResults = []; |
|
let startTime; |
|
|
|
function debounce(func, delay) { |
|
return function() { |
|
clearTimeout(suggestionRequestTimeout); |
|
suggestionRequestTimeout = setTimeout(() => { |
|
func.apply(this, arguments); |
|
}, delay); |
|
}; |
|
} |
|
|
|
async function fetchSuggestions(query) { |
|
if (suggestionCache[query]) { |
|
return suggestionCache[query]; |
|
} |
|
try { |
|
const response = await fetch(`${BASE_URL}/api/suggestions?q=${encodeURIComponent(query)}`); |
|
if (response.ok) { |
|
const suggestions = await response.json(); |
|
suggestionCache[query] = suggestions; |
|
return suggestions; |
|
} else { |
|
console.error("Error fetching suggestions:", response.status); |
|
return []; |
|
} |
|
} catch (error) { |
|
console.error("Error fetching suggestions:", error); |
|
return []; |
|
} |
|
} |
|
|
|
searchQueryInput.addEventListener("input", () => { |
|
clearTimeout(prefetchTimeout); |
|
const searchQuery = searchQueryInput.value.trim(); |
|
if (searchQuery === "") { |
|
suggestionsContainer.style.display = "none"; |
|
return; |
|
} |
|
prefetchTimeout = setTimeout(async () => { |
|
const suggestions = await fetchSuggestions(searchQuery); |
|
displaySuggestions(suggestions); |
|
}, 100); |
|
}); |
|
|
|
function displaySuggestions(suggestions) { |
|
suggestionsContainer.innerHTML = ""; |
|
if (suggestions.length === 0 || searchQueryInput.value.trim() === "") { |
|
suggestionsContainer.style.display = "none"; |
|
return; |
|
} |
|
const suggestionList = document.createElement("ul"); |
|
suggestions.forEach((suggestion, index) => { |
|
const listItem = document.createElement("li"); |
|
listItem.textContent = suggestion.phrase; |
|
listItem.addEventListener("click", () => { |
|
searchQueryInput.value = suggestion.phrase; |
|
suggestionsContainer.style.display = "none"; |
|
performSearch(suggestion.phrase); |
|
}); |
|
listItem.addEventListener("focus", () => { |
|
selectedSuggestionIndex = index; |
|
updateSuggestionSelection(); |
|
}); |
|
suggestionList.appendChild(listItem); |
|
}); |
|
suggestionsContainer.appendChild(suggestionList); |
|
suggestionsContainer.style.display = "block"; |
|
} |
|
|
|
function updateSuggestionSelection() { |
|
const suggestionItems = suggestionsContainer.querySelectorAll("li"); |
|
suggestionItems.forEach((item, index) => { |
|
item.classList.toggle("selected", index === selectedSuggestionIndex); |
|
}); |
|
} |
|
|
|
function showLoading() { |
|
loadingOverlay.style.display = 'block'; |
|
} |
|
|
|
function hideLoading() { |
|
loadingOverlay.style.display = 'none'; |
|
} |
|
|
|
async function performSearch(query) { |
|
showLoading(); |
|
aiResponseContainer.style.display = 'none'; |
|
suggestionsContainer.style.display = "none"; |
|
startTime = performance.now(); |
|
seenUrls.clear(); |
|
allResultsFetched = false; |
|
resultsContainer.innerHTML = ''; |
|
noResultsMessage.style.display = 'none'; |
|
loadingMoreIndicator.classList.remove('active'); |
|
speechSynthesis.cancel(); |
|
|
|
const initialResults = await fetchResults(query, INITIAL_RESULTS); |
|
displayResults(initialResults); |
|
hideLoading(); |
|
|
|
fetchResults(query, CACHED_RESULTS).then(cachedResults => { |
|
cachedSearchResults = removeDuplicateResults(cachedResults); |
|
allResults = allResults.concat(cachedSearchResults); |
|
displayResults(cachedSearchResults.slice(INITIAL_RESULTS, RESULTS_PER_PAGE), true); |
|
|
|
if (cachedSearchResults.length > RESULTS_PER_PAGE) { |
|
allResultsFetched = false; |
|
loadingMoreIndicator.classList.add('active'); |
|
} |
|
}); |
|
|
|
fetchAIResponse(query).then(aiResponse => { |
|
displayAIResponse(aiResponse); |
|
aiResponseContainer.style.display = 'block'; |
|
}).catch(error => { |
|
console.error("Error fetching AI response:", error); |
|
}); |
|
|
|
updateURLWithQuery(query); |
|
} |
|
|
|
async function fetchAIResponse(query) { |
|
try { |
|
const encodedQuery = encodeURIComponent(query); |
|
const response = await fetch(`${BASE_URL}/api/ask_website?url=https://google.com/search?q=${encodedQuery}&question=Answer this question from google search result ${encodedQuery}&model=gpt-4o-mini`); |
|
if (response.ok) { |
|
const aiResponse = await response.json(); |
|
return aiResponse; |
|
} else { |
|
console.error("Error fetching AI response from website:", response.status); |
|
return null; |
|
} |
|
} catch (error) { |
|
console.error("Error fetching AI response from website:", error); |
|
return null; |
|
} |
|
} |
|
|
|
function displayAIResponse(response) { |
|
aiResponseContainer.innerHTML = ''; |
|
if (response) { |
|
const aiResultElement = document.createElement('div'); |
|
aiResultElement.classList.add('ai-result'); |
|
const aiHeading = document.createElement('h2'); |
|
aiHeading.textContent = "AI Response"; |
|
aiResultElement.appendChild(aiHeading); |
|
const aiText = document.createElement('p'); |
|
const decodedResponse = decodeHtml(response); |
|
const msg = new SpeechSynthesisUtterance(decodedResponse); |
|
speechSynthesis.speak(msg); |
|
aiText.textContent = decodedResponse; |
|
const pauseButton = document.createElement('button'); |
|
pauseButton.id = 'pause'; |
|
pauseButton.innerHTML = '<i class="fas fa-pause"></i>'; |
|
const stopButton = document.createElement('button'); |
|
stopButton.id = 'stop'; |
|
stopButton.innerHTML = '<i class="fas fa-stop"></i>'; |
|
let isPaused = false; |
|
let isStoped = false; |
|
pauseButton.addEventListener('click', () => { |
|
if ('speechSynthesis' in window) { |
|
if (isPaused) { |
|
window.speechSynthesis.resume(); |
|
isPaused = false; |
|
stopButton.style.display = 'inline-block'; |
|
pauseButton.innerHTML = '<i class="fas fa-pause"></i>'; |
|
} else { |
|
window.speechSynthesis.pause(); |
|
isPaused = true; |
|
stopButton.style.display = 'none'; |
|
pauseButton.innerHTML = '<i class="fas fa-play"></i>'; |
|
} |
|
} |
|
}); |
|
|
|
stopButton.addEventListener('click', () => { |
|
if ('speechSynthesis' in window) { |
|
if (isStoped) { |
|
speechSynthesis.speak(msg); |
|
isPaused = false; |
|
isStoped = false; |
|
pauseButton.innerHTML = '<i class="fas fa-pause"></i>'; |
|
pauseButton.style.display = 'inline-block'; |
|
stopButton.innerHTML = '<i class="fas fa-stop"></i>'; |
|
} else { |
|
window.speechSynthesis.cancel(); |