mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-08-13 19:28:40 +00:00
added multi search engine support (didnt test) WIP
This commit is contained in:
@ -8,6 +8,8 @@ import formatChatHistoryAsString from '../utils/formatHistory';
|
||||
import { BaseMessage } from '@langchain/core/messages';
|
||||
import { StringOutputParser } from '@langchain/core/output_parsers';
|
||||
import { searchSearxng } from '../lib/searchEngines/searxng';
|
||||
import { searchGooglePSE } from '../lib/searchEngines/google_pse';
|
||||
import { getSearchEngineBackend } from '../config';
|
||||
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||
|
||||
const imageSearchChainPrompt = `
|
||||
@ -36,6 +38,59 @@ type ImageSearchChainInput = {
|
||||
query: string;
|
||||
};
|
||||
|
||||
async function performImageSearch(query: string) {
|
||||
const searchEngine = getSearchEngineBackend();
|
||||
let images = [];
|
||||
|
||||
switch (searchEngine) {
|
||||
case 'google': {
|
||||
const googleResult = await searchGooglePSE(query);
|
||||
images = googleResult.originalres
|
||||
.map((result) => {
|
||||
// Extract image URL from multiple possible locations in Google's response
|
||||
const imageSrc = result.pagemap?.cse_image?.[0]?.src ||
|
||||
result.pagemap?.cse_thumbnail?.[0]?.src ||
|
||||
result.image?.thumbnailLink;
|
||||
|
||||
if (imageSrc && result.link && result.title) {
|
||||
images.push({
|
||||
img_src: imageSrc,
|
||||
url: result.link,
|
||||
title: result.title,
|
||||
// Add additional metadata if needed
|
||||
source: result.displayLink,
|
||||
fileFormat: result.fileFormat,
|
||||
});
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'searxng': {
|
||||
const searxResult = await searchSearxng(query, {
|
||||
engines: ['google images', 'bing images'],
|
||||
pageno: 1,
|
||||
});
|
||||
searxResult.results.forEach((result) => {
|
||||
if (result.img_src && result.url && result.title) {
|
||||
images.push({
|
||||
img_src: result.img_src,
|
||||
url: result.url,
|
||||
title: result.title,
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown search engine ${searchEngine}`);
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
const strParser = new StringOutputParser();
|
||||
|
||||
const createImageSearchChain = (llm: BaseChatModel) => {
|
||||
@ -52,22 +107,7 @@ const createImageSearchChain = (llm: BaseChatModel) => {
|
||||
llm,
|
||||
strParser,
|
||||
RunnableLambda.from(async (input: string) => {
|
||||
const res = await searchSearxng(input, {
|
||||
engines: ['bing images', 'google images'],
|
||||
});
|
||||
|
||||
const images = [];
|
||||
|
||||
res.results.forEach((result) => {
|
||||
if (result.img_src && result.url && result.title) {
|
||||
images.push({
|
||||
img_src: result.img_src,
|
||||
url: result.url,
|
||||
title: result.title,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const images = await performImageSearch(input);
|
||||
return images.slice(0, 10);
|
||||
}),
|
||||
]);
|
||||
|
@ -8,6 +8,8 @@ import formatChatHistoryAsString from '../utils/formatHistory';
|
||||
import { BaseMessage } from '@langchain/core/messages';
|
||||
import { StringOutputParser } from '@langchain/core/output_parsers';
|
||||
import { searchSearxng } from '../lib/searchEngines/searxng';
|
||||
import { searchGooglePSE } from '../lib/searchEngines/google_pse';
|
||||
import { getSearchEngineBackend } from '../config';
|
||||
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||
|
||||
const VideoSearchChainPrompt = `
|
||||
@ -38,27 +40,45 @@ type VideoSearchChainInput = {
|
||||
|
||||
const strParser = new StringOutputParser();
|
||||
|
||||
const createVideoSearchChain = (llm: BaseChatModel) => {
|
||||
return RunnableSequence.from([
|
||||
RunnableMap.from({
|
||||
chat_history: (input: VideoSearchChainInput) => {
|
||||
return formatChatHistoryAsString(input.chat_history);
|
||||
},
|
||||
query: (input: VideoSearchChainInput) => {
|
||||
return input.query;
|
||||
},
|
||||
}),
|
||||
PromptTemplate.fromTemplate(VideoSearchChainPrompt),
|
||||
llm,
|
||||
strParser,
|
||||
RunnableLambda.from(async (input: string) => {
|
||||
const res = await searchSearxng(input, {
|
||||
function extractYouTubeVideoId(url: string): string | null {
|
||||
const regex = /(?:v=|\/embed\/|\.be\/)([a-zA-Z0-9_-]{11})/;
|
||||
const match = url.match(regex);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
async function performVideoSearch(query: string) {
|
||||
const searchEngine = getSearchEngineBackend();
|
||||
const youtubeQuery = `${query} site:youtube.com`;
|
||||
let videos = [];
|
||||
|
||||
switch (searchEngine) {
|
||||
case 'google': {
|
||||
const googleResult = await searchGooglePSE(youtubeQuery);
|
||||
googleResult.originalres.results.forEach((result) => {
|
||||
// Extract video metadata from Google PSE results
|
||||
const thumbnail = result.pagemap?.cse_thumbnail?.[0]?.src
|
||||
|| result.pagemap?.videoobject?.[0]?.thumbnailurl;
|
||||
|
||||
if (thumbnail && result.link && result.title) {
|
||||
videos.push({
|
||||
img_src: thumbnail,
|
||||
url: result.link,
|
||||
title: result.title,
|
||||
// Construct iframe URL from YouTube video ID
|
||||
iframe_src: result.link.includes('youtube.com/watch?v=')
|
||||
? `https://www.youtube.com/embed/${result.link.split('v=')[1].split('&')[0]}`
|
||||
: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'searxng': {
|
||||
const searxResult = await searchSearxng(query, {
|
||||
engines: ['youtube'],
|
||||
});
|
||||
|
||||
const videos = [];
|
||||
|
||||
res.results.forEach((result) => {
|
||||
searxResult.results.forEach((result) => {
|
||||
if (
|
||||
result.thumbnail &&
|
||||
result.url &&
|
||||
@ -73,7 +93,31 @@ const createVideoSearchChain = (llm: BaseChatModel) => {
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown search engine ${searchEngine}`);
|
||||
}
|
||||
|
||||
return videos;
|
||||
}
|
||||
|
||||
const createVideoSearchChain = (llm: BaseChatModel) => {
|
||||
return RunnableSequence.from([
|
||||
RunnableMap.from({
|
||||
chat_history: (input: VideoSearchChainInput) => {
|
||||
return formatChatHistoryAsString(input.chat_history);
|
||||
},
|
||||
query: (input: VideoSearchChainInput) => {
|
||||
return input.query;
|
||||
},
|
||||
}),
|
||||
PromptTemplate.fromTemplate(VideoSearchChainPrompt),
|
||||
llm,
|
||||
strParser,
|
||||
RunnableLambda.from(async (input: string) => {
|
||||
const videos = await performVideoSearch(input);
|
||||
return videos.slice(0, 10);
|
||||
}),
|
||||
]);
|
||||
@ -87,4 +131,4 @@ const handleVideoSearch = (
|
||||
return VideoSearchChain.invoke(input);
|
||||
};
|
||||
|
||||
export default handleVideoSearch;
|
||||
export default handleVideoSearch;
|
Reference in New Issue
Block a user