mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-06-15 06:18:41 +00:00
Compare commits
2 Commits
c645ffdcde
...
495d0d75d5
Author | SHA1 | Date | |
---|---|---|---|
495d0d75d5 | |||
c3a1e434e5 |
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>`;
|
||||
|
||||
|
@ -32,9 +32,11 @@ const SearchImages = ({
|
||||
const handleShowMore = () => {
|
||||
// If we're already showing all images, don't do anything
|
||||
if (images && displayLimit >= images.length) return;
|
||||
|
||||
|
||||
// Otherwise, increase the display limit by 10, or show all images
|
||||
setDisplayLimit(prev => images ? Math.min(prev + 10, images.length) : prev);
|
||||
setDisplayLimit((prev) =>
|
||||
images ? Math.min(prev + 10, images.length) : prev,
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -92,7 +94,6 @@ const SearchImages = ({
|
||||
if (onImagesLoaded && images.length > 0) {
|
||||
onImagesLoaded(images.length);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching images:', error);
|
||||
} finally {
|
||||
@ -101,7 +102,6 @@ const SearchImages = ({
|
||||
};
|
||||
|
||||
fetchImages();
|
||||
|
||||
}, [query, messageId, chatHistory, onImagesLoaded]);
|
||||
|
||||
return (
|
||||
@ -118,7 +118,10 @@ const SearchImages = ({
|
||||
)}
|
||||
{images !== null && images.length > 0 && (
|
||||
<>
|
||||
<div className="grid grid-cols-2 gap-2" key={`image-results-${messageId}`}>
|
||||
<div
|
||||
className="grid grid-cols-2 gap-2"
|
||||
key={`image-results-${messageId}`}
|
||||
>
|
||||
{images.slice(0, displayLimit).map((image, i) => (
|
||||
<img
|
||||
onClick={() => {
|
||||
@ -142,8 +145,10 @@ const SearchImages = ({
|
||||
onClick={handleShowMore}
|
||||
className="px-4 py-2 bg-light-secondary dark:bg-dark-secondary hover:bg-light-200 dark:hover:bg-dark-200 text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white rounded-md transition duration-200 flex items-center space-x-2"
|
||||
>
|
||||
<span>Show More Images</span>
|
||||
<span className="text-sm opacity-75">({displayLimit} of {images.length})</span>
|
||||
<span>Show More Images</span>
|
||||
<span className="text-sm opacity-75">
|
||||
({displayLimit} of {images.length})
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
@ -48,9 +48,11 @@ const Searchvideos = ({
|
||||
const handleShowMore = () => {
|
||||
// If we're already showing all videos, don't do anything
|
||||
if (videos && displayLimit >= videos.length) return;
|
||||
|
||||
|
||||
// Otherwise, increase the display limit by 10, or show all videos
|
||||
setDisplayLimit(prev => videos ? Math.min(prev + 10, videos.length) : prev);
|
||||
setDisplayLimit((prev) =>
|
||||
videos ? Math.min(prev + 10, videos.length) : prev,
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -118,7 +120,6 @@ const Searchvideos = ({
|
||||
};
|
||||
|
||||
fetchVideos();
|
||||
|
||||
}, [query, messageId, chatHistory, onVideosLoaded]);
|
||||
|
||||
return (
|
||||
@ -135,7 +136,10 @@ const Searchvideos = ({
|
||||
)}
|
||||
{videos !== null && videos.length > 0 && (
|
||||
<>
|
||||
<div className="grid grid-cols-2 gap-2" key={`video-results-${messageId}`}>
|
||||
<div
|
||||
className="grid grid-cols-2 gap-2"
|
||||
key={`video-results-${messageId}`}
|
||||
>
|
||||
{videos.slice(0, displayLimit).map((video, i) => (
|
||||
<div
|
||||
onClick={() => {
|
||||
@ -167,8 +171,10 @@ const Searchvideos = ({
|
||||
onClick={handleShowMore}
|
||||
className="px-4 py-2 bg-light-secondary dark:bg-dark-secondary hover:bg-light-200 dark:hover:bg-dark-200 text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white rounded-md transition duration-200 flex items-center space-x-2"
|
||||
>
|
||||
<span>Show More Videos</span>
|
||||
<span className="text-sm opacity-75">({displayLimit} of {videos.length})</span>
|
||||
<span>Show More Videos</span>
|
||||
<span className="text-sm opacity-75">
|
||||
({displayLimit} of {videos.length})
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
@ -64,6 +64,6 @@ export const searchHandlers: Record<string, MetaSearchAgent> = {
|
||||
rerankThreshold: 0.3,
|
||||
searchWeb: true,
|
||||
summarizer: false,
|
||||
additionalSearchCriteria: "site:reddit.com",
|
||||
additionalSearchCriteria: 'site:reddit.com',
|
||||
}),
|
||||
};
|
||||
|
@ -207,7 +207,6 @@ class MetaSearchAgent implements MetaSearchAgentType {
|
||||
|
||||
return { query: question, docs: docs };
|
||||
} else {
|
||||
|
||||
if (this.config.additionalSearchCriteria) {
|
||||
question = `${question} ${this.config.additionalSearchCriteria}`;
|
||||
}
|
||||
@ -249,7 +248,6 @@ class MetaSearchAgent implements MetaSearchAgentType {
|
||||
optimizationMode: 'speed' | 'balanced' | 'quality',
|
||||
systemInstructions: string,
|
||||
) {
|
||||
|
||||
return RunnableSequence.from([
|
||||
RunnableMap.from({
|
||||
systemInstructions: () => systemInstructions,
|
||||
|
Reference in New Issue
Block a user