feat(opensearch): Add autocomplete functionality to opensearch. This gets proxied to the searxng instance.
This commit is contained in:
parent
03b27d9cbb
commit
c3a1e434e5
6 changed files with 105 additions and 16 deletions
79
src/app/api/autocomplete/route.ts
Normal file
79
src/app/api/autocomplete/route.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import { NextResponse } from 'next/server';
|
||||
import { getSearxngApiEndpoint } from '@/lib/config';
|
||||
|
||||
/**
|
||||
* Proxies autocomplete requests to SearXNG
|
||||
*/
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
// Get the query parameter from the request URL
|
||||
const { searchParams } = new URL(request.url);
|
||||
const query = searchParams.get('q');
|
||||
|
||||
// Check if query exists
|
||||
if (!query) {
|
||||
return new NextResponse(JSON.stringify([query || '', []]), {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-suggestions+json',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Get the SearXNG API endpoint
|
||||
const searxngUrl = getSearxngApiEndpoint();
|
||||
|
||||
if (!searxngUrl) {
|
||||
console.error('SearXNG API endpoint not configured');
|
||||
return new NextResponse(JSON.stringify([query, []]), {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-suggestions+json',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Format the URL (remove trailing slashes)
|
||||
const formattedSearxngUrl = searxngUrl.replace(/\/+$/, '');
|
||||
const autocompleteUrl = `${formattedSearxngUrl}/autocompleter?q=${encodeURIComponent(query)}`;
|
||||
|
||||
// Make the request to SearXNG
|
||||
const response = await fetch(autocompleteUrl, {
|
||||
method: 'POST', // The example XML used POST method
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
signal: AbortSignal.timeout(3000), // 3 second timeout
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(
|
||||
`SearXNG autocompleter returned status: ${response.status}`,
|
||||
);
|
||||
return new NextResponse(JSON.stringify([query, []]), {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-suggestions+json',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Get the JSON response from SearXNG
|
||||
const suggestions = await response.json();
|
||||
|
||||
// Return the suggestions in the expected format
|
||||
console.log('SearXNG autocompleter response:', suggestions);
|
||||
return new NextResponse(JSON.stringify(suggestions), {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-suggestions+json',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error proxying to SearXNG autocompleter:', error);
|
||||
|
||||
// Return an empty suggestion list on error
|
||||
const query = new URL(request.url).searchParams.get('q') || '';
|
||||
return new NextResponse(JSON.stringify([query, []]), {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-suggestions+json',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ function generateOpenSearchResponse(origin: string): NextResponse {
|
|||
<InputEncoding>UTF-8</InputEncoding>
|
||||
<Image width="16" height="16" type="image/x-icon">${origin}/favicon.ico</Image>
|
||||
<Url type="text/html" template="${origin}/?q={searchTerms}"/>
|
||||
<Url rel="suggestions" type="application/x-suggestions+json" template="${origin}/api/autocomplete?q={searchTerms}"/>
|
||||
<Url type="application/opensearchdescription+xml" rel="self" template="${origin}/api/opensearch"/>
|
||||
</OpenSearchDescription>`;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue