93 lines
2.5 KiB
JavaScript
93 lines
2.5 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* SearXNG Search Tool
|
|
*
|
|
* Provides web search via local SearXNG instance at http://10.0.0.8:8888/
|
|
*/
|
|
|
|
const SEARXNG_BASE_URL = process.env.SEARXNG_URL || 'http://10.0.0.8:8888';
|
|
|
|
async function searxSearch(args) {
|
|
const { query, count = 5, lang = 'en', safesearch = 0 } = args;
|
|
|
|
if (!query || typeof query !== 'string') {
|
|
throw new Error('Missing required parameter: query');
|
|
}
|
|
|
|
// Build the search URL
|
|
const searchParams = new URLSearchParams({
|
|
q: query,
|
|
format: 'json',
|
|
language: lang,
|
|
safesearch: String(safesearch),
|
|
});
|
|
|
|
const url = `${SEARXNG_BASE_URL}/search?${searchParams.toString()}`;
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'User-Agent': 'OpenClaw-SearXNG-Skill/1.0',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`SearXNG returned HTTP ${response.status}: ${response.statusText}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
// Transform SearXNG results to a standard format
|
|
const results = (data.results || []).slice(0, Math.min(count, 20)).map(result => ({
|
|
title: result.title || '',
|
|
url: result.url || '',
|
|
snippet: result.content || '',
|
|
engine: result.engine || 'unknown',
|
|
engines: result.engines || [],
|
|
thumbnail: result.thumbnail || null,
|
|
publishedDate: result.publishedDate || null,
|
|
}));
|
|
|
|
// Include infoboxes if available
|
|
const infoboxes = (data.infoboxes || []).map(box => ({
|
|
title: box.infobox || box.title || '',
|
|
content: box.content || '',
|
|
image: box.img_src || null,
|
|
urls: box.urls || [],
|
|
engine: box.engine || 'wikipedia',
|
|
}));
|
|
|
|
return {
|
|
success: true,
|
|
query: data.query || query,
|
|
resultCount: results.length,
|
|
totalResults: data.number_of_results || results.length,
|
|
results,
|
|
infoboxes: infoboxes.length > 0 ? infoboxes : undefined,
|
|
unresponsiveEngines: data.unresponsive_engines || [],
|
|
};
|
|
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: error.message,
|
|
query,
|
|
};
|
|
}
|
|
}
|
|
|
|
// CLI execution
|
|
if (require.main === module) {
|
|
const args = JSON.parse(process.argv[2] || '{}');
|
|
searxSearch(args).then(result => {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}).catch(error => {
|
|
console.error(JSON.stringify({ success: false, error: error.message }));
|
|
process.exit(1);
|
|
});
|
|
}
|
|
|
|
module.exports = { searxSearch };
|