feat: support custon endpint for Firecrawl
This commit is contained in:
@ -11,6 +11,7 @@
|
|||||||
const {
|
const {
|
||||||
config,
|
config,
|
||||||
aiApiBase,
|
aiApiBase,
|
||||||
|
webSearchApiBase,
|
||||||
showConfigManager: showModal,
|
showConfigManager: showModal,
|
||||||
} = storeToRefs(useConfigStore())
|
} = storeToRefs(useConfigStore())
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@ -66,6 +67,7 @@
|
|||||||
// Only kept for easy reference in i18n Ally
|
// Only kept for easy reference in i18n Ally
|
||||||
_help: t('settings.webSearch.providers.firecrawl.help'),
|
_help: t('settings.webSearch.providers.firecrawl.help'),
|
||||||
link: 'https://www.firecrawl.dev/app/api-keys',
|
link: 'https://www.firecrawl.dev/app/api-keys',
|
||||||
|
supportsCustomApiBase: true,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
const selectedAiProvider = computed(() =>
|
const selectedAiProvider = computed(() =>
|
||||||
@ -121,6 +123,7 @@
|
|||||||
config.value.ai.model = model
|
config.value.ai.model = model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Automatically fetch AI models list
|
||||||
watch(
|
watch(
|
||||||
() => [
|
() => [
|
||||||
config.value.ai.provider,
|
config.value.ai.provider,
|
||||||
@ -134,6 +137,24 @@
|
|||||||
},
|
},
|
||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
)
|
)
|
||||||
|
// Reset AI config when provider changed
|
||||||
|
watch(
|
||||||
|
() => config.value.ai.provider,
|
||||||
|
() => {
|
||||||
|
config.value.ai.apiKey = ''
|
||||||
|
config.value.ai.apiBase = ''
|
||||||
|
config.value.ai.model = ''
|
||||||
|
config.value.ai.contextSize = undefined
|
||||||
|
},
|
||||||
|
)
|
||||||
|
// Reset web search config when provider changed
|
||||||
|
watch(
|
||||||
|
() => config.value.webSearch.provider,
|
||||||
|
() => {
|
||||||
|
config.value.webSearch.apiKey = ''
|
||||||
|
config.value.webSearch.apiBase = ''
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
show() {
|
show() {
|
||||||
@ -250,17 +271,30 @@
|
|||||||
</template>
|
</template>
|
||||||
<USelect
|
<USelect
|
||||||
v-model="config.webSearch.provider"
|
v-model="config.webSearch.provider"
|
||||||
class="w-auto"
|
class="w-30"
|
||||||
:items="webSearchProviderOptions"
|
:items="webSearchProviderOptions"
|
||||||
/>
|
/>
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<UFormField :label="$t('settings.webSearch.apiKey')" required>
|
<UFormField
|
||||||
|
:label="$t('settings.webSearch.apiKey')"
|
||||||
|
:required="!config.webSearch.apiBase"
|
||||||
|
>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
v-model="config.webSearch.apiKey"
|
v-model="config.webSearch.apiKey"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
:placeholder="$t('settings.webSearch.apiKey')"
|
:placeholder="$t('settings.webSearch.apiKey')"
|
||||||
/>
|
/>
|
||||||
</UFormField>
|
</UFormField>
|
||||||
|
<UFormField
|
||||||
|
v-if="selectedWebSearchProvider?.supportsCustomApiBase"
|
||||||
|
:label="$t('settings.webSearch.apiBase')"
|
||||||
|
>
|
||||||
|
<UInput
|
||||||
|
v-model="config.webSearch.apiBase"
|
||||||
|
class="w-full"
|
||||||
|
:placeholder="webSearchApiBase"
|
||||||
|
/>
|
||||||
|
</UFormField>
|
||||||
<UFormField :label="$t('settings.webSearch.queryLanguage')">
|
<UFormField :label="$t('settings.webSearch.queryLanguage')">
|
||||||
<template #help>
|
<template #help>
|
||||||
<i18n-t
|
<i18n-t
|
||||||
|
@ -19,12 +19,13 @@ type WebSearchFunction = (
|
|||||||
) => Promise<WebSearchResult[]>
|
) => Promise<WebSearchResult[]>
|
||||||
|
|
||||||
export const useWebSearch = (): WebSearchFunction => {
|
export const useWebSearch = (): WebSearchFunction => {
|
||||||
const { config } = useConfigStore()
|
const { config, webSearchApiBase } = useConfigStore()
|
||||||
|
|
||||||
switch (config.webSearch.provider) {
|
switch (config.webSearch.provider) {
|
||||||
case 'firecrawl': {
|
case 'firecrawl': {
|
||||||
const fc = new Firecrawl({
|
const fc = new Firecrawl({
|
||||||
apiKey: config.webSearch.apiKey,
|
apiKey: config.webSearch.apiKey,
|
||||||
|
apiUrl: webSearchApiBase,
|
||||||
})
|
})
|
||||||
return async (q: string, o: WebSearchOptions) => {
|
return async (q: string, o: WebSearchOptions) => {
|
||||||
const results = await fc.search(q, o)
|
const results = await fc.search(q, o)
|
||||||
|
@ -40,11 +40,12 @@
|
|||||||
"help": "Similar to Firecrawl, but provides 1000 free credits / month. Get one API key at {0}."
|
"help": "Similar to Firecrawl, but provides 1000 free credits / month. Get one API key at {0}."
|
||||||
},
|
},
|
||||||
"firecrawl": {
|
"firecrawl": {
|
||||||
"help": "Get one API key at {0}."
|
"help": "Get one API key at {0} if you are using the official service."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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.",
|
||||||
"concurrencyLimit": "Concurrency Limit"
|
"concurrencyLimit": "Concurrency Limit",
|
||||||
|
"apiBase": "API Base URL"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"researchTopic": {
|
"researchTopic": {
|
||||||
@ -74,7 +75,6 @@
|
|||||||
"clickToView": "Click a child node to view details.",
|
"clickToView": "Click a child node to view details.",
|
||||||
"nodeDetails": "Node Details",
|
"nodeDetails": "Node Details",
|
||||||
"startNode": {
|
"startNode": {
|
||||||
"label": "Start",
|
|
||||||
"description": "This is the beginning of your deep research journey!"
|
"description": "This is the beginning of your deep research journey!"
|
||||||
},
|
},
|
||||||
"researchGoal": "Research Goal",
|
"researchGoal": "Research Goal",
|
||||||
|
@ -37,14 +37,15 @@
|
|||||||
"queryLanguageHelp": "修改搜索词的语言。如果你想获取不同的搜索结果(比如查询高质量的英文资料),可以在这里修改。\nAI 模型在总结的时候仍然会使用当前网页的语言。",
|
"queryLanguageHelp": "修改搜索词的语言。如果你想获取不同的搜索结果(比如查询高质量的英文资料),可以在这里修改。\nAI 模型在总结的时候仍然会使用当前网页的语言。",
|
||||||
"providers": {
|
"providers": {
|
||||||
"firecrawl": {
|
"firecrawl": {
|
||||||
"help": "在 {0} 获取一个 API key。"
|
"help": "如果你使用的是官方服务,请在 {0} 获取 API key。"
|
||||||
},
|
},
|
||||||
"tavily": {
|
"tavily": {
|
||||||
"help": "和 Firecrawl 类似,不过提供了每月 1000 次免费搜索。在 {0} 获取一个 API key。"
|
"help": "和 Firecrawl 类似,不过提供了每月 1000 次免费搜索。在 {0} 获取一个 API key。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"concurrencyLimit": "并发数",
|
"concurrencyLimit": "并发数",
|
||||||
"concurrencyLimitHelp": "限制同时进行的搜索数量。这样可以避免被 API 服务限流,导致请求失败。"
|
"concurrencyLimitHelp": "限制同时进行的搜索数量。这样可以避免被 API 服务限流,导致请求失败。",
|
||||||
|
"apiBase": "API Base URL"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"researchTopic": {
|
"researchTopic": {
|
||||||
@ -74,7 +75,6 @@
|
|||||||
"clickToView": "点击下面的节点查看搜索详情。",
|
"clickToView": "点击下面的节点查看搜索详情。",
|
||||||
"nodeDetails": "节点详情",
|
"nodeDetails": "节点详情",
|
||||||
"startNode": {
|
"startNode": {
|
||||||
"label": "Start",
|
|
||||||
"description": "这是本次研究的起点"
|
"description": "这是本次研究的起点"
|
||||||
},
|
},
|
||||||
"researchGoal": "研究目标",
|
"researchGoal": "研究目标",
|
||||||
|
@ -20,6 +20,8 @@ export interface ConfigAi {
|
|||||||
export interface ConfigWebSearch {
|
export interface ConfigWebSearch {
|
||||||
provider: ConfigWebSearchProvider
|
provider: ConfigWebSearchProvider
|
||||||
apiKey?: string
|
apiKey?: string
|
||||||
|
/** API base. Currently only works with Firecrawl */
|
||||||
|
apiBase?: string
|
||||||
/** Force the LLM to generate serp queries in a certain language */
|
/** Force the LLM to generate serp queries in a certain language */
|
||||||
searchLanguage?: Locale
|
searchLanguage?: Locale
|
||||||
/** Limit the number of concurrent tasks globally */
|
/** Limit the number of concurrent tasks globally */
|
||||||
@ -78,6 +80,15 @@ export const useConfigStore = defineStore('config', () => {
|
|||||||
}
|
}
|
||||||
return ai.apiBase || 'https://api.openai.com/v1'
|
return ai.apiBase || 'https://api.openai.com/v1'
|
||||||
})
|
})
|
||||||
|
const webSearchApiBase = computed(() => {
|
||||||
|
const { webSearch } = config.value
|
||||||
|
if (webSearch.provider === 'tavily') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (webSearch.provider === 'firecrawl') {
|
||||||
|
return webSearch.apiBase || 'https://api.firecrawl.dev'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const showConfigManager = ref(false)
|
const showConfigManager = ref(false)
|
||||||
|
|
||||||
@ -85,6 +96,7 @@ export const useConfigStore = defineStore('config', () => {
|
|||||||
config: skipHydrate(config),
|
config: skipHydrate(config),
|
||||||
isConfigValid,
|
isConfigValid,
|
||||||
aiApiBase,
|
aiApiBase,
|
||||||
|
webSearchApiBase,
|
||||||
showConfigManager,
|
showConfigManager,
|
||||||
dismissUpdateVersion: skipHydrate(dismissUpdateVersion),
|
dismissUpdateVersion: skipHydrate(dismissUpdateVersion),
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user