Skip to content

Commit

Permalink
Feat/Exa Search Tool (FlowiseAI#2524)
Browse files Browse the repository at this point in the history
* add exa search tool

* add exa svg
  • Loading branch information
HenryHengZJ authored May 30, 2024
1 parent 7706b34 commit b5b929e
Show file tree
Hide file tree
Showing 5 changed files with 287 additions and 0 deletions.
26 changes: 26 additions & 0 deletions packages/components/credentials/ExaSearchApi.credential.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { INodeParams, INodeCredential } from '../src/Interface'

class ExaSearchApi implements INodeCredential {
label: string
name: string
version: number
description: string
inputs: INodeParams[]

constructor() {
this.label = 'Exa Search API'
this.name = 'exaSearchApi'
this.version = 1.0
this.description =
'Refer to <a target="_blank" href="https://docs.exa.ai/reference/getting-started#getting-access">official guide</a> on how to get an API Key from Exa'
this.inputs = [
{
label: 'ExaSearch Api Key',
name: 'exaSearchApiKey',
type: 'password'
}
]
}
}

module.exports = { credClass: ExaSearchApi }
230 changes: 230 additions & 0 deletions packages/components/nodes/tools/ExaSearch/ExaSearch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import { ExaSearchResults } from '@langchain/exa'
import Exa from 'exa-js'
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'

const DESC = `A wrapper around Exa Search. Input should be an Exa-optimized query. Output is a JSON array of the query results`

class ExaSearch_Tools implements INode {
label: string
name: string
version: number
description: string
type: string
icon: string
category: string
baseClasses: string[]
credential: INodeParams
inputs: INodeParams[]

constructor() {
this.label = 'Exa Search'
this.name = 'exaSearch'
this.version = 1.0
this.type = 'ExaSearch'
this.icon = 'exa.svg'
this.category = 'Tools'
this.description = 'Wrapper around Exa Search API - search engine fully designed for use by LLMs'
this.inputs = [
{
label: 'Tool Description',
name: 'description',
type: 'string',
description: 'Description of what the tool does. This is for LLM to determine when to use this tool.',
rows: 4,
additionalParams: true,
default: DESC
},
{
label: 'Num of Results',
name: 'numResults',
type: 'number',
optional: true,
step: 1,
additionalParams: true,
description: 'Number of search results to return. Default 10. Max 10 for basic plans. Up to thousands for custom plans.'
},
{
label: 'Search Type',
name: 'type',
type: 'options',
options: [
{
label: 'keyword',
name: 'keyword'
},
{
label: 'neural',
name: 'neural'
},
{
label: 'magic',
name: 'magic',
description: 'decides between keyword and neural'
}
],
optional: true,
additionalParams: true
},
{
label: 'Use Auto Prompt',
name: 'useAutoprompt',
type: 'boolean',
optional: true,
additionalParams: true,
description: 'If true, your query will be converted to a Exa query. Default false.'
},
{
label: 'Category (Beta)',
name: 'category',
type: 'options',
description:
'A data category to focus on, with higher comprehensivity and data cleanliness. Categories right now include company, research paper, news, github, tweet, movie, song, personal site, and pdf',
options: [
{
label: 'company',
name: 'company'
},
{
label: 'research paper',
name: 'research paper'
},
{
label: 'news',
name: 'news'
},
{
label: 'github',
name: 'github'
},
{
label: 'tweet',
name: 'tweet'
},
{
label: 'movie',
name: 'movie'
},
{
label: 'song',
name: 'song'
},
{
label: 'pdf',
name: 'pdf'
},
{
label: 'personal site',
name: 'personal site'
}
],
optional: true,
additionalParams: true
},
{
label: 'Include Domains',
name: 'includeDomains',
type: 'string',
rows: 4,
optional: true,
additionalParams: true,
description:
'List of domains to include in the search, separated by comma. If specified, results will only come from these domains.'
},
{
label: 'Exclude Domains',
name: 'excludeDomains',
type: 'string',
rows: 4,
optional: true,
additionalParams: true,
description:
'List of domains to exclude in the search, separated by comma. If specified, results will not include any from these domains.'
},
{
label: 'Start Crawl Date',
name: 'startCrawlDate',
type: 'string',
optional: true,
additionalParams: true,
placeholder: '2023-01-01T00:00:00.000Z',
description:
'Crawl date refers to the date that Exa discovered a link. Results will include links that were crawled after this date. Must be specified in ISO 8601 format.'
},
{
label: 'End Crawl Date',
name: 'endCrawlDate',
type: 'string',
optional: true,
additionalParams: true,
placeholder: '2023-12-31T00:00:00.000Z',
description:
'Crawl date refers to the date that Exa discovered a link. Results will include links that were crawled before this date. Must be specified in ISO 8601 format.'
},
{
label: 'Start Published Date',
name: 'startPublishedDate',
type: 'string',
optional: true,
additionalParams: true,
placeholder: '2023-01-01T00:00:00.000Z',
description: 'Only links with a published date after this will be returned. Must be specified in ISO 8601 format.'
},
{
label: 'End Published Date',
name: 'endPublishedDate',
type: 'string',
optional: true,
additionalParams: true,
placeholder: '2023-12-31T00:00:00.000Z',
description: 'Only links with a published date before this will be returned. Must be specified in ISO 8601 format.'
}
]
this.credential = {
label: 'Connect Credential',
name: 'credential',
type: 'credential',
credentialNames: ['exaSearchApi']
}
this.baseClasses = [this.type, ...getBaseClasses(ExaSearchResults)]
}

async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const description = nodeData.inputs?.description as string
const numResults = nodeData.inputs?.numResults as string
const type = nodeData.inputs?.type as string
const useAutoprompt = nodeData.inputs?.useAutoprompt as boolean
const category = nodeData.inputs?.category as string
const includeDomains = nodeData.inputs?.includeDomains as string
const excludeDomains = nodeData.inputs?.excludeDomains as string
const startCrawlDate = nodeData.inputs?.startCrawlDate as string
const endCrawlDate = nodeData.inputs?.endCrawlDate as string
const startPublishedDate = nodeData.inputs?.startPublishedDate as string
const endPublishedDate = nodeData.inputs?.endPublishedDate as string

const credentialData = await getCredentialData(nodeData.credential ?? '', options)
const exaSearchApiKey = getCredentialParam('exaSearchApiKey', credentialData, nodeData)

const tool = new ExaSearchResults({
client: new Exa(exaSearchApiKey),
searchArgs: {
numResults: numResults ? parseFloat(numResults) : undefined,
type: type || undefined,
useAutoprompt: useAutoprompt || undefined,
category: category || undefined,
includeDomains: includeDomains ? includeDomains.split(',') : undefined,
excludeDomains: excludeDomains ? excludeDomains.split(',') : undefined,
startCrawlDate: startCrawlDate || undefined,
endCrawlDate: endCrawlDate || undefined,
startPublishedDate: startPublishedDate || undefined,
endPublishedDate: endPublishedDate || undefined
}
})

if (description) tool.description = description

return tool
}
}

module.exports = { nodeClass: ExaSearch_Tools }
3 changes: 3 additions & 0 deletions packages/components/nodes/tools/ExaSearch/exa.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@langchain/cohere": "^0.0.7",
"@langchain/community": "^0.0.43",
"@langchain/core": "^0.1.63",
"@langchain/exa": "^0.0.5",
"@langchain/google-genai": "^0.0.10",
"@langchain/google-vertexai": "^0.0.5",
"@langchain/groq": "^0.0.8",
Expand Down Expand Up @@ -68,6 +69,7 @@
"css-what": "^6.1.0",
"d3-dsv": "2",
"dotenv": "^16.0.0",
"exa-js": "^1.0.12",
"express": "^4.17.3",
"faiss-node": "^0.5.1",
"fast-json-patch": "^3.1.1",
Expand Down
26 changes: 26 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b5b929e

Please sign in to comment.