diff --git a/README.md b/README.md index 39c3266..65ed11b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [](https://discord.gg/26aArMy8tT) -  ## Table of Contents diff --git a/docker-compose.yaml b/docker-compose.yaml index a942348..38c3f5d 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,7 +4,7 @@ services: volumes: - ./searxng:/etc/searxng:rw ports: - - "4000:8080" + - '4000:8080' networks: - perplexica-network restart: unless-stopped @@ -19,7 +19,7 @@ services: depends_on: - searxng ports: - - "3001:3001" + - '3001:3001' volumes: - backend-dbstore:/home/perplexica/data - uploads:/home/perplexica/uploads @@ -41,7 +41,7 @@ services: depends_on: - perplexica-backend ports: - - "3000:3000" + - '3000:3000' networks: - perplexica-network restart: unless-stopped diff --git a/src/chains/imageSearchAgent.ts b/src/chains/imageSearchAgent.ts index f1043ce..01f4ada 100644 --- a/src/chains/imageSearchAgent.ts +++ b/src/chains/imageSearchAgent.ts @@ -48,16 +48,18 @@ async function performImageSearch(query: string) { switch (searchEngine) { case 'google': { const googleResult = await searchGooglePSE(query); - images = googleResult.results.map((result) => { - if (result.img_src && result.url && result.title) { - return { - img_src: result.img_src, - url: result.url, - title: result.title, - source: result.displayLink - }; - } - }).filter(Boolean); + images = googleResult.results + .map((result) => { + if (result.img_src && result.url && result.title) { + return { + img_src: result.img_src, + url: result.url, + title: result.title, + source: result.displayLink, + }; + } + }) + .filter(Boolean); break; } @@ -80,46 +82,52 @@ async function performImageSearch(query: string) { case 'brave': { const braveResult = await searchBraveAPI(query); - images = braveResult.results.map((result) => { - if (result.img_src && result.url && result.title) { - return { - img_src: result.img_src, - url: result.url, - title: result.title, - source: result.url - }; - } - }).filter(Boolean); + images = braveResult.results + .map((result) => { + if (result.img_src && result.url && result.title) { + return { + img_src: result.img_src, + url: result.url, + title: result.title, + source: result.url, + }; + } + }) + .filter(Boolean); break; } case 'yacy': { const yacyResult = await searchYaCy(query); - images = yacyResult.results.map((result) => { - if (result.img_src && result.url && result.title) { - return { - img_src: result.img_src, - url: result.url, - title: result.title, - source: result.url + images = yacyResult.results + .map((result) => { + if (result.img_src && result.url && result.title) { + return { + img_src: result.img_src, + url: result.url, + title: result.title, + source: result.url, + }; } - } - }).filter(Boolean); + }) + .filter(Boolean); break; } case 'bing': { const bingResult = await searchBingAPI(query); - images = bingResult.results.map((result) => { - if (result.img_src && result.url && result.title) { - return { - img_src: result.img_src, - url: result.url, - title: result.title, - source: result.url + images = bingResult.results + .map((result) => { + if (result.img_src && result.url && result.title) { + return { + img_src: result.img_src, + url: result.url, + title: result.title, + source: result.url, + }; } - } - }).filter(Boolean); + }) + .filter(Boolean); break; } diff --git a/src/chains/videoSearchAgent.ts b/src/chains/videoSearchAgent.ts index 37f6a5b..331b8c8 100644 --- a/src/chains/videoSearchAgent.ts +++ b/src/chains/videoSearchAgent.ts @@ -50,14 +50,17 @@ async function performVideoSearch(query: string) { switch (searchEngine) { case 'google': { const googleResult = await searchGooglePSE(youtubeQuery); - googleResult.results.forEach((result) => { // Use .results instead of .originalres + googleResult.results.forEach((result) => { + // Use .results instead of .originalres if (result.img_src && result.url && result.title) { const videoId = new URL(result.url).searchParams.get('v'); videos.push({ img_src: result.img_src, url: result.url, title: result.title, - iframe_src: videoId ? `https://www.youtube.com/embed/${videoId}` : null + iframe_src: videoId + ? `https://www.youtube.com/embed/${videoId}` + : null, }); } }); @@ -95,7 +98,9 @@ async function performVideoSearch(query: string) { img_src: result.img_src, url: result.url, title: result.title, - iframe_src: videoId ? `https://www.youtube.com/embed/${videoId}` : null + iframe_src: videoId + ? `https://www.youtube.com/embed/${videoId}` + : null, }); } }); @@ -117,7 +122,9 @@ async function performVideoSearch(query: string) { img_src: result.img_src, url: result.url, title: result.title, - iframe_src: videoId ? `https://www.youtube.com/embed/${videoId}` : null + iframe_src: videoId + ? `https://www.youtube.com/embed/${videoId}` + : null, }); } }); @@ -159,4 +166,4 @@ const handleVideoSearch = ( return VideoSearchChain.invoke(input); }; -export default handleVideoSearch; \ No newline at end of file +export default handleVideoSearch; diff --git a/src/config.ts b/src/config.ts index bf1277d..70e292b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -15,7 +15,7 @@ interface Config { IMAGE: string; VIDEO: string; NEWS: string; - } + }; MODELS: { OPENAI: { API_KEY: string; @@ -103,7 +103,8 @@ export const getBraveApiKey = () => loadConfig().SEARCH_ENGINES.BRAVE.API_KEY; export const getBingSubscriptionKey = () => loadConfig().SEARCH_ENGINES.BING.SUBSCRIPTION_KEY; -export const getYacyJsonEndpoint = () => loadConfig().SEARCH_ENGINES.YACY.ENDPOINT; +export const getYacyJsonEndpoint = () => + loadConfig().SEARCH_ENGINES.YACY.ENDPOINT; export const getSearxngApiEndpoint = () => process.env.SEARXNG_API_URL || loadConfig().SEARCH_ENGINES.SEARXNG.ENDPOINT; diff --git a/src/lib/searchEngines/bing.ts b/src/lib/searchEngines/bing.ts index dd9efd8..0d46a10 100644 --- a/src/lib/searchEngines/bing.ts +++ b/src/lib/searchEngines/bing.ts @@ -60,8 +60,8 @@ export const searchBingAPI = async (query: string) => { const res = await axios.get(url.toString(), { headers: { 'Ocp-Apim-Subscription-Key': bingApiKey, - 'Accept': 'application/json' - } + Accept: 'application/json', + }, }); if (res.data.error) { @@ -79,17 +79,20 @@ export const searchBingAPI = async (query: string) => { title: item.name, url: item.url, content: item.snippet, - img_src: item.primaryImageOfPage?.thumbnailUrl - || imageResults.find((img: any) => img.hostPageUrl === item.url)?.thumbnailUrl - || videoResults.find((vid: any) => vid.hostPageUrl === item.url)?.thumbnailUrl, + img_src: + item.primaryImageOfPage?.thumbnailUrl || + imageResults.find((img: any) => img.hostPageUrl === item.url) + ?.thumbnailUrl || + videoResults.find((vid: any) => vid.hostPageUrl === item.url) + ?.thumbnailUrl, ...(item.video && { videoData: { duration: item.video.duration, - embedUrl: item.video.embedHtml?.match(/src="(.*?)"/)?.[1] + embedUrl: item.video.embedHtml?.match(/src="(.*?)"/)?.[1], }, - publisher: item.publisher, - datePublished: item.datePublished - }) + publisher: item.publisher, + datePublished: item.datePublished, + }), })); return { results, originalres }; @@ -99,4 +102,4 @@ export const searchBingAPI = async (query: string) => { : error.message || 'Unknown error'; throw new Error(`Bing API Error: ${errorMessage}`); } -}; \ No newline at end of file +}; diff --git a/src/lib/searchEngines/brave.ts b/src/lib/searchEngines/brave.ts index 3d2ed68..ba6ae5a 100644 --- a/src/lib/searchEngines/brave.ts +++ b/src/lib/searchEngines/brave.ts @@ -33,7 +33,7 @@ interface BraveSearchResult { export const searchBraveAPI = async ( query: string, - numResults: number = 20 + numResults: number = 20, ): Promise<{ results: BraveSearchResult[]; originalres: any }> => { try { const braveApiKey = await getBraveApiKey(); @@ -45,8 +45,8 @@ export const searchBraveAPI = async ( const res = await axios.get(url.toString(), { headers: { 'X-Subscription-Token': braveApiKey, - 'Accept': 'application/json' - } + Accept: 'application/json', + }, }); if (res.data.error) { @@ -64,26 +64,32 @@ export const searchBraveAPI = async ( age: item.age, family_friendly: item.family_friendly, language: item.language, - video: item.video ? { - embedUrl: item.video.embed_url, - duration: item.video.duration - } : undefined, - rating: item.rating ? { - value: item.rating.value, - scale: item.rating.scale_max - } : undefined, + video: item.video + ? { + embedUrl: item.video.embed_url, + duration: item.video.duration, + } + : undefined, + rating: item.rating + ? { + value: item.rating.value, + scale: item.rating.scale_max, + } + : undefined, products: item.deep_results?.product_cluster?.map((p: any) => ({ name: p.name, - price: p.price + price: p.price, })), - recipe: item.recipe ? { - ingredients: item.recipe.ingredients, - cookTime: item.recipe.cook_time - } : undefined, + recipe: item.recipe + ? { + ingredients: item.recipe.ingredients, + cookTime: item.recipe.cook_time, + } + : undefined, meta: { fetched: item.meta?.fetched, - lastCrawled: item.meta?.last_crawled - } + lastCrawled: item.meta?.last_crawled, + }, })); return { results, originalres }; diff --git a/src/lib/searchEngines/google_pse.ts b/src/lib/searchEngines/google_pse.ts index f09531d..4cdb659 100644 --- a/src/lib/searchEngines/google_pse.ts +++ b/src/lib/searchEngines/google_pse.ts @@ -21,7 +21,7 @@ interface GooglePSESearchResult { }>; metatags?: Array<{ [key: string]: string; - 'author'?: string; + author?: string; }>; cse_image?: Array<{ src: string; @@ -43,7 +43,7 @@ export const searchGooglePSE = async (query: string) => { try { const [googleApiKey, googleCseID] = await Promise.all([ getGoogleApiKey(), - getGoogleCseId() + getGoogleCseId(), ]); const url = new URL(`https://www.googleapis.com/customsearch/v1`); @@ -63,15 +63,16 @@ export const searchGooglePSE = async (query: string) => { title: item.title, url: item.link, content: item.snippet, - img_src: item.pagemap?.cse_image?.[0]?.src - || item.pagemap?.cse_thumbnail?.[0]?.src - || item.image?.thumbnailLink, + img_src: + item.pagemap?.cse_image?.[0]?.src || + item.pagemap?.cse_thumbnail?.[0]?.src || + item.image?.thumbnailLink, ...(item.pagemap?.videoobject?.[0] && { videoData: { duration: item.pagemap.videoobject[0].duration, - embedUrl: item.pagemap.videoobject[0].embedurl - } - }) + embedUrl: item.pagemap.videoobject[0].embedurl, + }, + }), })); return { results, originalres }; diff --git a/src/lib/searchEngines/yacy.ts b/src/lib/searchEngines/yacy.ts index 909ca9b..74fc76c 100644 --- a/src/lib/searchEngines/yacy.ts +++ b/src/lib/searchEngines/yacy.ts @@ -48,11 +48,7 @@ interface YaCySearchResult { }[]; } - -export const searchYaCy = async ( - query: string, - numResults: number = 20 -) => { +export const searchYaCy = async (query: string, numResults: number = 20) => { try { const yacyBaseUrl = getYacyJsonEndpoint(); @@ -64,7 +60,7 @@ export const searchYaCy = async ( const originalres = res.data as YaCySearchResult; - const results = originalres.channels[0].items.map(item => ({ + const results = originalres.channels[0].items.map((item) => ({ title: item.title, url: item.link, content: item.description, diff --git a/src/routes/discover.ts b/src/routes/discover.ts index c0b25b6..3d3f1e3 100644 --- a/src/routes/discover.ts +++ b/src/routes/discover.ts @@ -15,7 +15,7 @@ async function performSearch(query: string, site: string) { case 'google': { const googleResult = await searchGooglePSE(query); - return googleResult.originalres.map(item => { + return googleResult.originalres.map((item) => { const imageSources = [ item.pagemap?.cse_image?.[0]?.src, item.pagemap?.cse_thumbnail?.[0]?.src, @@ -29,10 +29,11 @@ async function performSearch(query: string, site: string) { url: item.link, content: item.snippet, thumbnail: imageSources[0], // First available image - img_src: imageSources[0], // Same as thumbnail for consistency + img_src: imageSources[0], // Same as thumbnail for consistency iframe_src: null, author: item.pagemap?.metatags?.[0]?.['og:site_name'] || site, - publishedDate: item.pagemap?.metatags?.[0]?.['article:published_time'] + publishedDate: + item.pagemap?.metatags?.[0]?.['article:published_time'], }; }); } @@ -47,7 +48,7 @@ async function performSearch(query: string, site: string) { case 'brave': { const braveResult = await searchBraveAPI(query); - return braveResult.results.map(item => ({ + return braveResult.results.map((item) => ({ title: item.title, url: item.url, content: item.content, @@ -55,7 +56,7 @@ async function performSearch(query: string, site: string) { img_src: item.img_src, iframe_src: null, author: item.meta?.fetched || site, - publishedDate: item.meta?.lastCrawled + publishedDate: item.meta?.lastCrawled, })); } @@ -69,13 +70,13 @@ async function performSearch(query: string, site: string) { img_src: item.img_src, iframe_src: null, author: item?.host || site, - publishedDate: item?.pubDate - })) + publishedDate: item?.pubDate, + })); } case 'bing': { const bingResult = await searchBingAPI(query); - return bingResult.results.map(item => ({ + return bingResult.results.map((item) => ({ title: item.title, url: item.url, content: item.content, @@ -83,8 +84,8 @@ async function performSearch(query: string, site: string) { img_src: item.img_src, iframe_src: null, author: item?.publisher || site, - publishedDate: item?.datePublished - })) + publishedDate: item?.datePublished, + })); } default: @@ -92,7 +93,6 @@ async function performSearch(query: string, site: string) { } } - router.get('/', async (req, res) => { try { const queries = [ @@ -114,12 +114,12 @@ router.get('/', async (req, res) => { logger.error(`Error searching ${site}: ${error.message}`); return []; } - }) + }), ) ) .flat() .sort(() => Math.random() - 0.5) - .filter(item => item.title && item.url && item.content); + .filter((item) => item.title && item.url && item.content); return res.json({ blogs: data }); } catch (err: any) { diff --git a/src/search/metaSearchAgent.ts b/src/search/metaSearchAgent.ts index 3c1c150..81dd063 100644 --- a/src/search/metaSearchAgent.ts +++ b/src/search/metaSearchAgent.ts @@ -208,7 +208,6 @@ class MetaSearchAgent implements MetaSearchAgentType { return { query: question, docs: docs }; } else { - const searchEngine = getSearchEngineBackend(); let res; @@ -236,7 +235,9 @@ class MetaSearchAgent implements MetaSearchAgentType { } if (!res?.results) { - throw new Error(`No results found for search engine: ${searchEngine}`); + throw new Error( + `No results found for search engine: ${searchEngine}`, + ); } const documents = res.results.map( diff --git a/ui/components/MessageBox.tsx b/ui/components/MessageBox.tsx index a7942d1..61f4f05 100644 --- a/ui/components/MessageBox.tsx +++ b/ui/components/MessageBox.tsx @@ -68,7 +68,13 @@ const MessageBox = ({ return (