Spaces:
Sleeping
Sleeping
| import { useSettingStore } from "@/store/setting"; | |
| import { | |
| createSearchProvider, | |
| type SearchProviderOptions, | |
| } from "@/utils/deep-research/search"; | |
| import { multiApiKeyPolling } from "@/utils/model"; | |
| import { generateSignature } from "@/utils/signature"; | |
| function normalizeDomain(input: string) { | |
| return input | |
| .trim() | |
| .toLowerCase() | |
| .replace(/^https?:\/\//, "") | |
| .replace(/^www\./, "") | |
| .replace(/^\*\./, "") | |
| .replace(/\/.*$/, "") | |
| .replace(/:\d+$/, ""); | |
| } | |
| function parseDomainList(value: string) { | |
| return value | |
| .split(/[\s,\n]+/g) | |
| .map((item) => normalizeDomain(item)) | |
| .filter((item) => item.length > 0); | |
| } | |
| function matchDomain(hostname: string, domain: string) { | |
| return hostname === domain || hostname.endsWith(`.${domain}`); | |
| } | |
| function isUrlAllowed( | |
| url: string, | |
| includeDomains: string[], | |
| excludeDomains: string[] | |
| ) { | |
| try { | |
| const hostname = normalizeDomain(new URL(url).hostname); | |
| if (excludeDomains.some((domain) => matchDomain(hostname, domain))) { | |
| return false; | |
| } | |
| if (includeDomains.length === 0) { | |
| return true; | |
| } | |
| return includeDomains.some((domain) => matchDomain(hostname, domain)); | |
| } catch { | |
| return includeDomains.length === 0; | |
| } | |
| } | |
| function applyDomainFilters( | |
| result: { sources: Source[]; images: ImageSource[] }, | |
| includeDomains: string[], | |
| excludeDomains: string[] | |
| ) { | |
| if (includeDomains.length === 0 && excludeDomains.length === 0) { | |
| return result; | |
| } | |
| return { | |
| sources: result.sources.filter((source) => | |
| isUrlAllowed(source.url, includeDomains, excludeDomains) | |
| ), | |
| images: result.images.filter((image) => | |
| isUrlAllowed(image.url, includeDomains, excludeDomains) | |
| ), | |
| }; | |
| } | |
| function useWebSearch() { | |
| async function search(query: string) { | |
| const { | |
| mode, | |
| searchProvider, | |
| searchMaxResult, | |
| accessPassword, | |
| searchIncludeDomains, | |
| searchExcludeDomains, | |
| } = useSettingStore.getState(); | |
| const options: SearchProviderOptions = { | |
| provider: searchProvider, | |
| maxResult: searchMaxResult, | |
| query, | |
| }; | |
| const includeDomains = parseDomainList(searchIncludeDomains); | |
| const excludeDomains = parseDomainList(searchExcludeDomains); | |
| switch (searchProvider) { | |
| case "tavily": | |
| const { tavilyApiKey, tavilyApiProxy, tavilyScope } = | |
| useSettingStore.getState(); | |
| if (mode === "local") { | |
| options.baseURL = tavilyApiProxy; | |
| options.apiKey = multiApiKeyPolling(tavilyApiKey); | |
| } else { | |
| options.baseURL = typeof window !== "undefined" ? `${window.location.origin}/api/search/tavily` : "/api/search/tavily"; | |
| } | |
| options.scope = tavilyScope; | |
| break; | |
| case "firecrawl": | |
| const { firecrawlApiKey, firecrawlApiProxy } = | |
| useSettingStore.getState(); | |
| if (mode === "local") { | |
| options.baseURL = firecrawlApiProxy; | |
| options.apiKey = multiApiKeyPolling(firecrawlApiKey); | |
| } else { | |
| options.baseURL = typeof window !== "undefined" ? `${window.location.origin}/api/search/firecrawl` : "/api/search/firecrawl"; | |
| } | |
| break; | |
| case "exa": | |
| const { exaApiKey, exaApiProxy, exaScope } = useSettingStore.getState(); | |
| if (mode === "local") { | |
| options.baseURL = exaApiProxy; | |
| options.apiKey = multiApiKeyPolling(exaApiKey); | |
| } else { | |
| options.baseURL = typeof window !== "undefined" ? `${window.location.origin}/api/search/exa` : "/api/search/exa"; | |
| } | |
| options.scope = exaScope; | |
| break; | |
| case "bocha": | |
| const { bochaApiKey, bochaApiProxy } = useSettingStore.getState(); | |
| if (mode === "local") { | |
| options.baseURL = bochaApiProxy; | |
| options.apiKey = multiApiKeyPolling(bochaApiKey); | |
| } else { | |
| options.baseURL = typeof window !== "undefined" ? `${window.location.origin}/api/search/bocha` : "/api/search/bocha"; | |
| } | |
| break; | |
| case "brave": | |
| const { braveApiKey, braveApiProxy } = useSettingStore.getState(); | |
| if (mode === "local") { | |
| options.baseURL = braveApiProxy; | |
| options.apiKey = multiApiKeyPolling(braveApiKey); | |
| } else { | |
| options.baseURL = typeof window !== "undefined" ? `${window.location.origin}/api/search/brave` : "/api/search/brave"; | |
| } | |
| break; | |
| case "searxng": | |
| const { searxngApiProxy, searxngScope } = useSettingStore.getState(); | |
| if (mode === "local") { | |
| options.baseURL = searxngApiProxy; | |
| } else { | |
| options.baseURL = typeof window !== "undefined" ? `${window.location.origin}/api/search/searxng` : "/api/search/searxng"; | |
| } | |
| options.scope = searxngScope; | |
| break; | |
| default: | |
| break; | |
| } | |
| if (mode === "proxy") { | |
| options.apiKey = generateSignature(accessPassword, Date.now()); | |
| } | |
| const result = await createSearchProvider(options); | |
| return applyDomainFilters(result, includeDomains, excludeDomains); | |
| } | |
| return { search }; | |
| } | |
| export default useWebSearch; | |