feat: Added Google PSE as an alternative web search provider (#65)
* Added Google PSE as an alternative web search tool * Removed unecessary comments * chore(ConfigManager): moved Google PSE input next to API key --------- Co-authored-by: AnotiaWang <anotia0202@gmail.com>
This commit is contained in:

committed by
GitHub

parent
651f445803
commit
5097c639d2
@ -91,6 +91,12 @@
|
|||||||
link: 'https://www.firecrawl.dev/app/api-keys',
|
link: 'https://www.firecrawl.dev/app/api-keys',
|
||||||
supportsCustomApiBase: true,
|
supportsCustomApiBase: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Google PSE',
|
||||||
|
value: 'google-pse',
|
||||||
|
help: 'settings.webSearch.providers.google-pse.help',
|
||||||
|
link: 'https://programmablesearchengine.google.com/', // Link to Google PSE console
|
||||||
|
},
|
||||||
])
|
])
|
||||||
const tavilySearchTopicOptions = ['general', 'news', 'finance']
|
const tavilySearchTopicOptions = ['general', 'news', 'finance']
|
||||||
const selectedAiProvider = computed(() =>
|
const selectedAiProvider = computed(() =>
|
||||||
@ -315,6 +321,26 @@
|
|||||||
:placeholder="$t('settings.webSearch.apiKey')"
|
:placeholder="$t('settings.webSearch.apiKey')"
|
||||||
/>
|
/>
|
||||||
</UFormField>
|
</UFormField>
|
||||||
|
|
||||||
|
<template v-if="config.webSearch.provider === 'google-pse'">
|
||||||
|
<UFormField
|
||||||
|
:label="
|
||||||
|
$t('settings.webSearch.providers.google-pse.pseIdLabel')
|
||||||
|
"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<UInput
|
||||||
|
v-model="config.webSearch.googlePseId"
|
||||||
|
class="w-full"
|
||||||
|
:placeholder="
|
||||||
|
$t(
|
||||||
|
'settings.webSearch.providers.google-pse.pseIdPlaceholder',
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</UFormField>
|
||||||
|
</template>
|
||||||
|
|
||||||
<UFormField
|
<UFormField
|
||||||
v-if="selectedWebSearchProvider?.supportsCustomApiBase"
|
v-if="selectedWebSearchProvider?.supportsCustomApiBase"
|
||||||
:label="$t('settings.webSearch.apiBase')"
|
:label="$t('settings.webSearch.apiBase')"
|
||||||
|
@ -46,6 +46,50 @@ export const useWebSearch = (): WebSearchFunction => {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 'google-pse': {
|
||||||
|
const apiKey = config.webSearch.apiKey
|
||||||
|
const pseId = config.webSearch.googlePseId
|
||||||
|
|
||||||
|
return async (q: string, o: WebSearchOptions) => {
|
||||||
|
if (!apiKey || !pseId) {
|
||||||
|
throw new Error('Google PSE API key or ID not set')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct Google PSE API URL
|
||||||
|
// Ref: https://developers.google.com/custom-search/v1/using_rest
|
||||||
|
const searchParams = new URLSearchParams({
|
||||||
|
key: apiKey,
|
||||||
|
cx: pseId,
|
||||||
|
q: q,
|
||||||
|
num: o.maxResults?.toString() || '5',
|
||||||
|
});
|
||||||
|
if (o.lang) {
|
||||||
|
searchParams.append('lr', `lang_${o.lang}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiUrl = `https://www.googleapis.com/customsearch/v1?${searchParams.toString()}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await $fetch<{ items?: Array<{ title: string; link: string; snippet: string }> }>(apiUrl, { method: 'GET' });
|
||||||
|
|
||||||
|
if (!response.items) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map response to WebSearchResult format
|
||||||
|
return response.items.map((item) => ({
|
||||||
|
content: item.snippet, // Use snippet as content
|
||||||
|
url: item.link,
|
||||||
|
title: item.title,
|
||||||
|
}));
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Google PSE search failed:', error);
|
||||||
|
// Attempt to parse Google API error format
|
||||||
|
const errorMessage = error?.data?.error?.message || error.message || 'Unknown error';
|
||||||
|
throw new Error(`Google PSE Error: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case 'tavily':
|
case 'tavily':
|
||||||
default: {
|
default: {
|
||||||
const tvly = tavily({
|
const tvly = tavily({
|
||||||
|
@ -9,7 +9,7 @@ export type ConfigAiProvider =
|
|||||||
| 'deepseek'
|
| 'deepseek'
|
||||||
| 'ollama'
|
| 'ollama'
|
||||||
|
|
||||||
export type ConfigWebSearchProvider = 'tavily' | 'firecrawl'
|
export type ConfigWebSearchProvider = 'tavily' | 'firecrawl' | 'google-pse'
|
||||||
|
|
||||||
export interface ConfigAi {
|
export interface ConfigAi {
|
||||||
provider: ConfigAiProvider
|
provider: ConfigAiProvider
|
||||||
@ -31,6 +31,7 @@ export interface ConfigWebSearch {
|
|||||||
tavilyAdvancedSearch?: boolean
|
tavilyAdvancedSearch?: boolean
|
||||||
/** Tavily: search topic. Defaults to `general` */
|
/** Tavily: search topic. Defaults to `general` */
|
||||||
tavilySearchTopic?: 'general' | 'news' | 'finance'
|
tavilySearchTopic?: 'general' | 'news' | 'finance'
|
||||||
|
googlePseId?: string; // Google PSE ID
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
@ -47,6 +48,7 @@ function validateConfig(config: Config) {
|
|||||||
if (ws.provider === 'tavily' && !ws.apiKey) return false
|
if (ws.provider === 'tavily' && !ws.apiKey) return false
|
||||||
// Either apiBase or apiKey is required for firecrawl
|
// Either apiBase or apiKey is required for firecrawl
|
||||||
if (ws.provider === 'firecrawl' && !ws.apiBase && !ws.apiKey) return false
|
if (ws.provider === 'firecrawl' && !ws.apiBase && !ws.apiKey) return false
|
||||||
|
if (ws.provider === 'google-pse' && (!ws.apiKey || !ws.googlePseId)) return false; // Require API Key and PSE ID
|
||||||
if (typeof ws.concurrencyLimit !== 'undefined' && ws.concurrencyLimit! < 1)
|
if (typeof ws.concurrencyLimit !== 'undefined' && ws.concurrencyLimit! < 1)
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
@ -49,6 +49,14 @@
|
|||||||
},
|
},
|
||||||
"firecrawl": {
|
"firecrawl": {
|
||||||
"help": "Get one API key at {0} if you are using the official service."
|
"help": "Get one API key at {0} if you are using the official service."
|
||||||
|
},
|
||||||
|
"google-pse": {
|
||||||
|
"title": "Google PSE",
|
||||||
|
"help": "Uses Google Programmable Search Engine. Requires an API Key and a PSE ID from Google Cloud Console / PSE Console. Find details at {0}.",
|
||||||
|
"apiKeyLabel": "Google API Key",
|
||||||
|
"apiKeyPlaceholder": "Enter your Google API Key",
|
||||||
|
"pseIdLabel": "Programmable Search Engine ID (cx)",
|
||||||
|
"pseIdPlaceholder": "Enter your PSE ID (cx value)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"concurrencyLimitHelp": "Limit the concurrent search tasks. This is useful to avoid overloading the search provider and causing requests to fail.",
|
"concurrencyLimitHelp": "Limit the concurrent search tasks. This is useful to avoid overloading the search provider and causing requests to fail.",
|
||||||
|
@ -49,6 +49,14 @@
|
|||||||
},
|
},
|
||||||
"firecrawl": {
|
"firecrawl": {
|
||||||
"help": "Ontvang een API-sleutel bij {0} als u de officiële service gebruikt."
|
"help": "Ontvang een API-sleutel bij {0} als u de officiële service gebruikt."
|
||||||
|
},
|
||||||
|
"google-pse": {
|
||||||
|
"title": "Google PSE",
|
||||||
|
"help": "Gebruikt Google Programmable Search Engine. Vereist een API-sleutel en een PSE-ID van Google Cloud Console / PSE Console. Vind details op {0}.",
|
||||||
|
"apiKeyLabel": "Google API-sleutel",
|
||||||
|
"apiKeyPlaceholder": "Voer uw Google API-sleutel in",
|
||||||
|
"pseIdLabel": "Programmable Search Engine ID (cx)",
|
||||||
|
"pseIdPlaceholder": "Voer uw PSE ID (cx-waarde) in"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"concurrencyLimitHelp": "Beperk de gelijktijdige zoektaken. Dit is handig om te voorkomen dat de zoekmachine overbelast raakt en verzoeken mislukken.",
|
"concurrencyLimitHelp": "Beperk de gelijktijdige zoektaken. Dit is handig om te voorkomen dat de zoekmachine overbelast raakt en verzoeken mislukken.",
|
||||||
|
@ -49,6 +49,14 @@
|
|||||||
"searchTopic": "搜索领域",
|
"searchTopic": "搜索领域",
|
||||||
"advancedSearch": "高质量搜索",
|
"advancedSearch": "高质量搜索",
|
||||||
"searchTopicHelp": "搜索特定领域的信息,获得更精确的结果。默认为“通用” (general)。"
|
"searchTopicHelp": "搜索特定领域的信息,获得更精确的结果。默认为“通用” (general)。"
|
||||||
|
},
|
||||||
|
"google-pse": {
|
||||||
|
"title": "Google PSE",
|
||||||
|
"help": "使用 Google 可编程搜索引擎。需要来自 Google Cloud Console / PSE Console 的 API 密钥和 PSE ID。在 {0} 查看详情。",
|
||||||
|
"apiKeyLabel": "Google API 密钥",
|
||||||
|
"apiKeyPlaceholder": "输入你的 Google API 密钥",
|
||||||
|
"pseIdLabel": "可编程搜索引擎 ID (cx)",
|
||||||
|
"pseIdPlaceholder": "输入你的 PSE ID (cx 值)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"concurrencyLimit": "并发数",
|
"concurrencyLimit": "并发数",
|
||||||
|
Reference in New Issue
Block a user