mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-12-18 17:48:16 +00:00
feat(academic-search): add academic search
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import z from 'zod';
|
||||
import { ResearchAction } from '../../types';
|
||||
import { Chunk, SearchResultsResearchBlock } from '@/lib/types';
|
||||
import { searchSearxng } from '@/lib/searxng';
|
||||
|
||||
const schema = z.object({
|
||||
queries: z.array(z.string()).describe('List of academic search queries'),
|
||||
});
|
||||
|
||||
const academicSearchDescription = `
|
||||
Use this tool to perform academic searches for scholarly articles, papers, and research studies relevant to the user's query. Provide a list of concise search queries that will help gather comprehensive academic information on the topic at hand.
|
||||
You can provide up to 3 queries at a time. Make sure the queries are specific and relevant to the user's needs.
|
||||
|
||||
For example, if the user is interested in recent advancements in renewable energy, your queries could be:
|
||||
1. "Recent advancements in renewable energy 2024"
|
||||
2. "Cutting-edge research on solar power technologies"
|
||||
3. "Innovations in wind energy systems"
|
||||
|
||||
If this tool is present and no other tools are more relevant, you MUST use this tool to get the needed academic information.
|
||||
`;
|
||||
|
||||
const academicSearchAction: ResearchAction<typeof schema> = {
|
||||
name: 'academic_search',
|
||||
schema: schema,
|
||||
getDescription: () => academicSearchDescription,
|
||||
getToolDescription: () =>
|
||||
"Use this tool to perform academic searches for scholarly articles, papers, and research studies relevant to the user's query. Provide a list of concise search queries that will help gather comprehensive academic information on the topic at hand.",
|
||||
enabled: (config) =>
|
||||
config.sources.includes('academic') &&
|
||||
config.classification.classification.skipSearch === false &&
|
||||
config.classification.classification.academicSearch === true,
|
||||
execute: async (input, additionalConfig) => {
|
||||
input.queries = input.queries.slice(0, 3);
|
||||
|
||||
const researchBlock = additionalConfig.session.getBlock(
|
||||
additionalConfig.researchBlockId,
|
||||
);
|
||||
|
||||
if (researchBlock && researchBlock.type === 'research') {
|
||||
researchBlock.data.subSteps.push({
|
||||
type: 'searching',
|
||||
id: crypto.randomUUID(),
|
||||
searching: input.queries,
|
||||
});
|
||||
|
||||
additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [
|
||||
{
|
||||
op: 'replace',
|
||||
path: '/data/subSteps',
|
||||
value: researchBlock.data.subSteps,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
const searchResultsBlockId = crypto.randomUUID();
|
||||
let searchResultsEmitted = false;
|
||||
|
||||
let results: Chunk[] = [];
|
||||
|
||||
const search = async (q: string) => {
|
||||
const res = await searchSearxng(q, {
|
||||
engines: ['arxiv', 'google scholar', 'pubmed'],
|
||||
});
|
||||
|
||||
const resultChunks: Chunk[] = res.results.map((r) => ({
|
||||
content: r.content || r.title,
|
||||
metadata: {
|
||||
title: r.title,
|
||||
url: r.url,
|
||||
},
|
||||
}));
|
||||
|
||||
results.push(...resultChunks);
|
||||
|
||||
if (
|
||||
!searchResultsEmitted &&
|
||||
researchBlock &&
|
||||
researchBlock.type === 'research'
|
||||
) {
|
||||
searchResultsEmitted = true;
|
||||
|
||||
researchBlock.data.subSteps.push({
|
||||
id: searchResultsBlockId,
|
||||
type: 'search_results',
|
||||
reading: resultChunks,
|
||||
});
|
||||
|
||||
additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [
|
||||
{
|
||||
op: 'replace',
|
||||
path: '/data/subSteps',
|
||||
value: researchBlock.data.subSteps,
|
||||
},
|
||||
]);
|
||||
} else if (
|
||||
searchResultsEmitted &&
|
||||
researchBlock &&
|
||||
researchBlock.type === 'research'
|
||||
) {
|
||||
const subStepIndex = researchBlock.data.subSteps.findIndex(
|
||||
(step) => step.id === searchResultsBlockId,
|
||||
);
|
||||
|
||||
const subStep = researchBlock.data.subSteps[
|
||||
subStepIndex
|
||||
] as SearchResultsResearchBlock;
|
||||
|
||||
subStep.reading.push(...resultChunks);
|
||||
|
||||
additionalConfig.session.updateBlock(additionalConfig.researchBlockId, [
|
||||
{
|
||||
op: 'replace',
|
||||
path: '/data/subSteps',
|
||||
value: researchBlock.data.subSteps,
|
||||
},
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
await Promise.all(input.queries.map(search));
|
||||
|
||||
return {
|
||||
type: 'search_results',
|
||||
results,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default academicSearchAction;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import academicSearchAction from './academicSearch';
|
||||
import doneAction from './done';
|
||||
import planAction from './plan';
|
||||
import ActionRegistry from './registry';
|
||||
@@ -10,5 +11,6 @@ ActionRegistry.register(doneAction);
|
||||
ActionRegistry.register(planAction);
|
||||
ActionRegistry.register(scrapeURLAction);
|
||||
ActionRegistry.register(uploadsSearchAction);
|
||||
ActionRegistry.register(academicSearchAction);
|
||||
|
||||
export { ActionRegistry };
|
||||
|
||||
Reference in New Issue
Block a user