anycoder-4e4382ca / index.js
BikoRiko's picture
Upload index.js with huggingface_hub
191bbfd verified
/**
* AI Web Search Assistant
* Uses DuckDuckGo Instant Answer API for real-time responses
*/
// Configuration
const CONFIG = {
DDG_API_BASE: 'https://api.duckduckgo.com/',
MAX_TOPICS: 8,
// Use a CORS proxy for better compatibility
CORS_PROXY: 'https://corsproxy.io/?'
};
// DOM Elements
const elements = {
chatMessages: document.getElementById('chatMessages'),
chatForm: document.getElementById('chatForm'),
userInput: document.getElementById('userInput'),
sendButton: document.getElementById('sendButton'),
statusBar: document.getElementById('statusBar'),
statusText: document.getElementById('statusText'),
loadingTemplate: document.getElementById('loadingTemplate')
};
// State
let isLoading = false;
/**
* Update status bar
*/
function updateStatus(text, state = 'ready') {
elements.statusText.textContent = text;
elements.statusBar.className = 'status-bar';
if (state === 'searching') {
elements.statusBar.classList.add('searching');
} else if (state === 'error') {
elements.statusBar.classList.add('error');
}
}
/**
* Create a loading message element
*/
function createLoadingMessage() {
const template = elements.loadingTemplate.content.cloneNode(true);
return template.querySelector('.loading-message');
}
/**
* Add a message to the chat
*/
function addMessage(content, isUser = false) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${isUser ? 'user-message' : 'ai-message'}`;
const avatar = document.createElement('div');
avatar.className = 'message-avatar';
avatar.innerHTML = isUser
? '<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="8" r="4" fill="white"/><path d="M4 20C4 17.2386 7.58172 15 12 15C16.4183 15 20 17.2386 20 20" stroke="white" stroke-width="2"/></svg>'
: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M12 2L2 7L12 12L22 7L12 2Z" fill="#4F46E5"/></svg>';
const contentDiv = document.createElement('div');
contentDiv.className = 'message-content';
if (typeof content === 'string') {
contentDiv.innerHTML = `<p>${content}</p>`;
} else {
contentDiv.appendChild(content);
}
messageDiv.appendChild(avatar);
messageDiv.appendChild(contentDiv);
elements.chatMessages.appendChild(messageDiv);
// Scroll to bottom
elements.chatMessages.parentElement.scrollTop = elements.chatMessages.parentElement.scrollHeight;
return messageDiv;
}
/**
* Create an answer section
*/
function createAnswerSection(title, content, className = '', source = null) {
const section = document.createElement('div');
section.className = `answer-section ${className}`;
let html = `<h4>${title}</h4><p>${content}</p>`;
if (source) {
html += `<p class="source-link">Source: ${source}</p>`;
}
section.innerHTML = html;
return section;
}
/**
* Format DuckDuckGo response for display
*/
function formatDuckDuckGoResponse(data) {
const container = document.createElement('div');
let hasContent = false;
// Debug: Log the raw response
console.log('DuckDuckGo Response:', data);
// Check for Instant Answer (most prominent)
if (data.Answer && data.Answer.trim()) {
const answerSection = createAnswerSection('πŸ’¬ Answer', data.Answer, 'answer');
if (data.AnswerType) {
answerSection.querySelector('h4').textContent += ` (${data.AnswerType})`;
}
container.appendChild(answerSection);
hasContent = true;
}
// Check for Definition
if (data.Definition && data.Definition.trim()) {
const defSection = createAnswerSection('πŸ“– Definition', data.Definition, 'definition', data.DefinitionSource);
container.appendChild(defSection);
hasContent = true;
}
// Check for Abstract (main topic info)
if (data.Abstract && data.Abstract.trim()) {
const abstractSection = createAnswerSection(
`πŸ“ ${data.AbstractTitle || 'Topic Overview'}`,
data.Abstract,
'abstract',
data.AbstractSource
);
container.appendChild(abstractSection);
hasContent = true;
}
// Check for Related Topics (from main entity)
if (data.RelatedTopics && data.RelatedTopics.length > 0) {
const topicsSection = document.createElement('div');
topicsSection.className = 'related-topics';
const title = document.createElement('h4');
title.textContent = 'πŸ”— Related Topics';
topicsSection.appendChild(title);
const tagsContainer = document.createElement('div');
tagsContainer.className = 'topic-tags';
data.RelatedTopics.slice(0, CONFIG.MAX_TOPICS).forEach(topic => {
if (topic.Text && topic.FirstURL) {
const tag = document.createElement('button');
tag.className = 'topic-tag';
tag.textContent = topic.Text.replace(/<[^>]*>/g, '');
tag.addEventListener('click', () => {
elements.userInput.value = topic.Text.replace(/<[^>]*>/g, '');
elements.chatForm.dispatchEvent(new Event('submit'));
});
tagsContainer.appendChild(tag);
} else if (topic.Name && topic.Topics) {
// Grouped topics (e.g., for famous people)
topic.Topics.slice(0, 3).forEach(subTopic => {
if (subTopic.Text && subTopic.FirstURL) {
const tag = document.createElement('button');
tag.className = 'topic-tag';
tag.textContent = subTopic.Text.replace(/<[^>]*>/g, '');
tag.addEventListener('click', () => {
elements.userInput.value = subTopic.Text.replace(/<[^>]*>/g, '');
elements.chatForm.dispatchEvent(new Event('submit'));
});
tagsContainer.appendChild(tag);
}
});
}
});
if (tagsContainer.children.length > 0) {
topicsSection.appendChild(tagsContainer);
container.appendChild(topicsSection);
hasContent = true;
}
}
// Check for Results (additional web results)
if (data.Results && data.Results.length > 0) {
const resultsSection = document.createElement('div');
resultsSection.className = 'related-topics';
const title = document.createElement('h4');
title.textContent = 'πŸ” More Results';
resultsSection.appendChild(title);
const tagsContainer = document.createElement('div');
tagsContainer.className = 'topic-tags';
data.Results.slice(0, CONFIG.MAX_TOPICS).forEach(result => {
if (result.Text && result.FirstURL) {
const tag = document.createElement('button');
tag.className = 'topic-tag';
tag.textContent = result.Text.replace(/<[^>]*>/g, '').substring(0, 50);
tag.title = result.FirstURL;
tag.addEventListener('click', () => {
window.open(result.FirstURL, '_blank');
});
tagsContainer.appendChild(tag);
}
});
if (tagsContainer.children.length > 0) {
resultsSection.appendChild(tagsContainer);
container.appendChild(resultsSection);
hasContent = true;
}
}
// Check for Redirect (when query needs different search)
if (data.Redirect && data.Redirect.trim()) {
const redirectMsg = document.createElement('p');
redirectMsg.innerHTML = `πŸ”€ For better results, try searching for: <strong>${data.Redirect}</strong>`;
container.appendChild(redirectMsg);
hasContent = true;
}
// If no data found - provide helpful message
if (!hasContent) {
const noResult = document.createElement('div');
noResult.innerHTML = `
<p>πŸ˜• I couldn't find specific information for that query.</p>
<p style="margin-top: 0.5rem; font-size: 0.875rem; color: var(--text-secondary);">
Try:</p>
<ul style="margin-left: 1.25rem; margin-top: 0.25rem; color: var(--text-secondary); font-size: 0.875rem;">
<li>Using different keywords</li>
<li>Asking a factual question</li>
<li>Searching for a specific person, place, or concept</li>
</ul>
`;
container.appendChild(noResult);
}
return container;
}
/**
* Fetch answer from DuckDuckGo API
*/
async function fetchDuckDuckGoAnswer(query) {
const params = new URLSearchParams({
q: query,
format: 'json',
no_html: '1',
skip_disambig: '1',
pretty: '1'
});
const url = `${CONFIG.DDG_API_BASE}?${params}`;
// Try direct first, then with CORS proxy
const urlsToTry = [url, CONFIG.CORS_PROXY + encodeURIComponent(url)];
let lastError = null;
for (const attemptUrl of urlsToTry) {
try {
console.log('Trying URL:', attemptUrl);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);
const response = await fetch(attemptUrl, {
method: 'GET',
headers: {
'Accept': 'application/json',
},
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// Check if we got any meaningful response
if (data && (data.Abstract || data.Answer || data.Definition || data.RelatedTopics || data.Results)) {
return data;
}
// If response exists but is empty, try next URL
console.log('Empty response, trying next URL');
lastError = new Error('Empty response');
} catch (error) {
console.log('Error with URL:', attemptUrl, error.message);
lastError = error;
continue;
}
}
throw lastError || new Error('Failed to fetch results');
}
/**
* Handle user submission
*/
async function handleSubmit(event) {
event.preventDefault();
const query = elements.userInput.value.trim();
if (!query || isLoading) return;
// Add user message
addMessage(query, true);
elements.userInput.value = '';
// Set loading state
isLoading = true;
elements.sendButton.disabled = true;
elements.userInput.disabled = true;
const loadingMessage = createLoadingMessage();
elements.chatMessages.appendChild(loadingMessage);
elements.chatMessages.parentElement.scrollTop = elements.chatMessages.parentElement.scrollHeight;
updateStatus('Searching the web...', 'searching');
try {
// Fetch from DuckDuckGo
const data = await fetchDuckDuckGoAnswer(query);
// Remove loading message
loadingMessage.remove();
// Format and display response
const formattedResponse = formatDuckDuckGoResponse(data);
addMessage(formattedResponse, false);
updateStatus('Ready to search', 'ready');
} catch (error) {
// Remove loading message
loadingMessage.remove();
// Show error message with retry suggestion
const errorContent = document.createElement('div');
errorContent.innerHTML = `
<p>πŸ˜• Sorry, I couldn't find results for that query.</p>
<p style="margin-top: 0.5rem; font-size: 0.875rem; color: var(--text-secondary);">
${error.message.includes('abort') ? 'Request timed out. Please try again.' : 'Try using different keywords or check your internet connection.'}
</p>
`;
addMessage(errorContent, false);
updateStatus('Error occurred', 'error');
console.error('Search Error:', error);
} finally {
// Reset loading state
isLoading = false;
elements.sendButton.disabled = false;
elements.userInput.disabled = false;
elements.userInput.focus();
}
}
/**
* Handle example query clicks
*/
function setupExampleQueries() {
elements.chatMessages.addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
const query = event.target.textContent;
elements.userInput.value = query;
elements.chatForm.dispatchEvent(new Event('submit'));
}
});
}
/**
* Initialize the application
*/
function init() {
// Set up event listeners
elements.chatForm.addEventListener('submit', handleSubmit);
// Handle Enter key
elements.userInput.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
elements.chatForm.dispatchEvent(new Event('submit'));
}
});
// Set up example query clicks
setupExampleQueries();
// Focus input
elements.userInput.focus();
updateStatus('Ready to search', 'ready');
console.log('πŸ” AI Web Search Assistant initialized!');
console.log('Powered by DuckDuckGo Instant Answer API');
}
// Start the app
document.addEventListener('DOMContentLoaded', init);