| 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(); |