AbdulElahGwaith's picture
Upload folder using huggingface_hub
88df9e4 verified
/*
When a request is made to a /search endpoint with query parameters, e.g. ?query=foo&version=free-pro-team,
we need to validate and parse the parameters. This file contains the configuration for which parameters
to expect based on the type of search request "e.g. general search vs autocomplete search" and how to validate them.
*/
import languages from '@/languages/lib/languages-server'
import { allIndexVersionKeys, versionToIndexVersionMap } from '@/search/lib/elasticsearch-versions'
import { SearchTypes } from '@/search/types'
import type { SearchRequestQueryParams } from '@/search/lib/search-request-params/types'
// Entry to this file, returns the query parameters to expect based on the type of search request
export function getSearchRequestParamsObject(type: SearchTypes): SearchRequestQueryParams[] {
if (type === 'aiSearchAutocomplete') {
return AI_SEARCH_AUTOCOMPLETE_PARAMS_OBJ
}
return GENERAL_SEARCH_PARAMS_OBJ
}
// - - - Everything below this line is for building the search query param objects - - - //
// Constants
const DEFAULT_AUTOCOMPLETE_SIZE = 5
const MAX_AUTOCOMPLETE_SIZE = 10
const DEFAULT_SIZE = 10
const MAX_SIZE = 50
const DEFAULT_PAGE = 1
const POSSIBLE_SORTS = ['best', 'relevance'] as const
const DEFAULT_SORT = POSSIBLE_SORTS[0]
const MAX_PAGE = 10
const V1_AGGREGATES = ['toplevel'] as const
export const POSSIBLE_HIGHLIGHT_FIELDS = ['title', 'content'] as const
// This needs to match what we *use* in the `<SearchResults>` component.
// For example, if we don't display "headings" we shouldn't request
// highlights for it either.
export const DEFAULT_HIGHLIGHT_FIELDS: readonly string[] = ['title', 'content']
export const V1_ADDITIONAL_INCLUDES = ['intro', 'headings', 'toplevel'] as const
export class ValidationError extends Error {}
const SHARED_PARAMS_OBJ: SearchRequestQueryParams[] = [
{ key: 'query' },
{
key: 'version',
default_: 'free-pro-team',
validate: (version: string) => {
if (!versionToIndexVersionMap[version]) {
throw new ValidationError(`'${version}' not in ${allIndexVersionKeys.join(', ')}`)
}
return true
},
},
]
const GENERAL_SEARCH_PARAMS_OBJ: SearchRequestQueryParams[] = [
...SHARED_PARAMS_OBJ,
{ key: 'query' },
{ key: 'language', default_: 'en', validate: (v) => v in languages },
{
key: 'size',
default_: DEFAULT_SIZE,
cast: (v) => parseInt(v, 10),
validate: (v) => v >= 0 && v <= MAX_SIZE,
},
{
key: 'page',
default_: DEFAULT_PAGE,
cast: (v) => parseInt(v, 10),
validate: (v) => v >= 1 && v <= MAX_PAGE,
},
{ key: 'sort', default_: DEFAULT_SORT, validate: (v) => POSSIBLE_SORTS.includes(v as any) },
{
key: 'highlights',
default_: DEFAULT_HIGHLIGHT_FIELDS,
cast: (v) => (Array.isArray(v) ? v : [v]),
multiple: true,
validate: (v) => {
for (const highlight of v) {
if (!POSSIBLE_HIGHLIGHT_FIELDS.includes(highlight)) {
throw new ValidationError(`highlight value '${highlight}' is not valid`)
}
}
return true
},
},
{ key: 'autocomplete', default_: false, cast: toBoolean },
{ key: 'debug', default_: process.env.NODE_ENV === 'development', cast: toBoolean },
{
key: 'include',
default_: [],
cast: toArray,
multiple: true,
validate: (values) =>
values.every((value: string) => V1_ADDITIONAL_INCLUDES.includes(value as any)),
},
{
key: 'toplevel',
default_: [],
cast: toArray,
multiple: true,
},
{
key: 'aggregate',
default_: [],
cast: toArray,
multiple: true,
validate: (values) => values.every((value: string) => V1_AGGREGATES.includes(value as any)),
},
]
const SHARED_AUTOCOMPLETE_PARAMS_OBJ: SearchRequestQueryParams[] = [
{ key: 'query' },
{
key: 'size',
default_: DEFAULT_AUTOCOMPLETE_SIZE,
cast: (size: string) => parseInt(size, 10),
validate: (size: number) => size >= 0 && size <= MAX_AUTOCOMPLETE_SIZE,
},
{
key: 'version',
default_: 'free-pro-team',
validate: (version: string) => {
if (!versionToIndexVersionMap[version]) {
throw new ValidationError(`'${version}' not in ${allIndexVersionKeys.join(', ')}`)
}
return true
},
},
]
const AI_SEARCH_AUTOCOMPLETE_PARAMS_OBJ: SearchRequestQueryParams[] = [
...SHARED_AUTOCOMPLETE_PARAMS_OBJ,
{ key: 'language', default_: 'en', validate: (language: string) => language === 'en' },
]
function toBoolean(value: any): boolean {
return value === 'true' || value === '1'
}
function toArray(value: any): any[] {
return Array.isArray(value) ? value : [value]
}