mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
feat(search): add Tavily search provider
This commit is contained in:
@@ -196,7 +196,13 @@
|
||||
"searchPlaceholder": "Search providers...",
|
||||
"emptyTitle": "No Search Providers",
|
||||
"emptyDescription": "Add a search provider to configure web search",
|
||||
"deleteConfirm": "Are you sure you want to delete this search provider? This action cannot be undone."
|
||||
"deleteConfirm": "Are you sure you want to delete this search provider? This action cannot be undone.",
|
||||
"providerNames": {
|
||||
"brave": "Brave",
|
||||
"bing": "Bing",
|
||||
"google": "Google",
|
||||
"tavily": "Tavily"
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"addTitle": "Add MCP",
|
||||
|
||||
@@ -192,7 +192,13 @@
|
||||
"searchPlaceholder": "搜索提供方…",
|
||||
"emptyTitle": "暂无搜索提供方",
|
||||
"emptyDescription": "请先添加搜索提供方,才能配置搜索功能",
|
||||
"deleteConfirm": "确定删除该搜索提供方?删除后无法恢复。"
|
||||
"deleteConfirm": "确定删除该搜索提供方?删除后无法恢复。",
|
||||
"providerNames": {
|
||||
"brave": "Brave",
|
||||
"bing": "Bing",
|
||||
"google": "Google",
|
||||
"tavily": "Tavily"
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"addTitle": "添加 MCP",
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
:key="type"
|
||||
:value="type"
|
||||
>
|
||||
{{ type }}
|
||||
{{ $t(`searchProvider.providerNames.${type}`, type) }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
@@ -109,7 +109,7 @@ import { useI18n } from 'vue-i18n'
|
||||
import FormDialogShell from '@/components/form-dialog-shell/index.vue'
|
||||
import { useDialogMutation } from '@/composables/useDialogMutation'
|
||||
|
||||
const PROVIDER_TYPES = ['brave', 'bing', 'google'] as const
|
||||
const PROVIDER_TYPES = ['brave', 'bing', 'google', 'tavily'] as const
|
||||
|
||||
const open = defineModel<boolean>('open')
|
||||
const { t } = useI18n()
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
:key="type"
|
||||
:value="type"
|
||||
>
|
||||
{{ type }}
|
||||
{{ $t(`searchProvider.providerNames.${type}`, type) }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
@@ -85,6 +85,9 @@
|
||||
<template v-else-if="form.values.provider === 'google'">
|
||||
<GoogleSettings v-model="configProxy" />
|
||||
</template>
|
||||
<template v-else-if="form.values.provider === 'tavily'">
|
||||
<TavilySettings v-model="configProxy" />
|
||||
</template>
|
||||
<div
|
||||
v-else-if="form.values.provider"
|
||||
class="text-sm text-muted-foreground"
|
||||
@@ -143,6 +146,7 @@ import ConfirmPopover from '@/components/confirm-popover/index.vue'
|
||||
import BraveSettings from './brave-settings.vue'
|
||||
import BingSettings from './bing-settings.vue'
|
||||
import GoogleSettings from './google-settings.vue'
|
||||
import TavilySettings from './tavily-settings.vue'
|
||||
import SearchProviderLogo from '@/components/search-provider-logo/index.vue'
|
||||
import { computed, inject, ref, watch } from 'vue'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
@@ -152,7 +156,7 @@ import { useMutation, useQueryCache } from '@pinia/colada'
|
||||
import { putSearchProvidersById, deleteSearchProvidersById } from '@memoh/sdk'
|
||||
import type { SearchprovidersGetResponse } from '@memoh/sdk'
|
||||
|
||||
const PROVIDER_TYPES = ['brave', 'bing', 'google'] as const
|
||||
const PROVIDER_TYPES = ['brave', 'bing', 'google', 'tavily'] as const
|
||||
|
||||
const curProvider = inject('curSearchProvider', ref<SearchprovidersGetResponse>())
|
||||
const curProviderId = computed(() => curProvider.value?.id)
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="tavily-api-key">API Key</Label>
|
||||
<Input
|
||||
id="tavily-api-key"
|
||||
v-model="localConfig.api_key"
|
||||
type="password"
|
||||
aria-label="API Key"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="tavily-base-url">Base URL</Label>
|
||||
<Input
|
||||
id="tavily-base-url"
|
||||
v-model="localConfig.base_url"
|
||||
aria-label="Base URL"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="tavily-timeout-seconds">Timeout (seconds)</Label>
|
||||
<Input
|
||||
id="tavily-timeout-seconds"
|
||||
v-model.number="localConfig.timeout_seconds"
|
||||
type="number"
|
||||
:min="1"
|
||||
aria-label="Timeout (seconds)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, watch } from 'vue'
|
||||
import { Input, Label } from '@memoh/ui'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: Record<string, unknown>
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: Record<string, unknown>]
|
||||
}>()
|
||||
|
||||
const localConfig = reactive({
|
||||
api_key: '',
|
||||
base_url: 'https://api.tavily.com/search',
|
||||
timeout_seconds: 15,
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
localConfig.api_key = String(val?.api_key ?? '')
|
||||
localConfig.base_url = String(val?.base_url ?? 'https://api.tavily.com/search')
|
||||
const timeout = Number(val?.timeout_seconds ?? 15)
|
||||
localConfig.timeout_seconds = Number.isFinite(timeout) && timeout > 0 ? timeout : 15
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
|
||||
watch(localConfig, () => {
|
||||
emit('update:modelValue', {
|
||||
api_key: localConfig.api_key,
|
||||
base_url: localConfig.base_url,
|
||||
timeout_seconds: localConfig.timeout_seconds,
|
||||
})
|
||||
}, { deep: true })
|
||||
</script>
|
||||
@@ -28,7 +28,7 @@ import ProviderSetting from './components/provider-setting.vue'
|
||||
import SearchProviderLogo from '@/components/search-provider-logo/index.vue'
|
||||
import MasterDetailSidebarLayout from '@/components/master-detail-sidebar-layout/index.vue'
|
||||
|
||||
const PROVIDER_TYPES = ['brave', 'bing', 'google'] as const
|
||||
const PROVIDER_TYPES = ['brave', 'bing', 'google', 'tavily'] as const
|
||||
|
||||
const filterProvider = ref('')
|
||||
const { data: providerData } = useQuery({
|
||||
@@ -155,7 +155,7 @@ const openStatus = reactive({
|
||||
:key="type"
|
||||
:value="type"
|
||||
>
|
||||
{{ type }}
|
||||
{{ $t(`searchProvider.providerNames.${type}`, type) }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
|
||||
Reference in New Issue
Block a user