import {z} from 'zod' export type QueryVector = string | Array; export type ResultType = 'Count' | 'Topk' | 'TopkCount'; export type RangeType = 'CountWithinRange' | 'CountAboveRange' | 'CountBelowRange'; export type Vec = Array; export type DistanceUnit = 'Kilometers' | 'Miles'; export type QueryFacet = {U8: {field: string, range_type: RangeType, ranges: Array>}} | {U16: {field: string, range_type: RangeType, ranges: Array>}} | {U32: {field: string, range_type: RangeType, ranges: Array>}} | {U64: {field: string, range_type: RangeType, ranges: Array>}} | {I8: {field: string, range_type: RangeType, ranges: Array>}} | {I16: {field: string, range_type: RangeType, ranges: Array>}} | {I32: {field: string, range_type: RangeType, ranges: Array>}} | {I64: {field: string, range_type: RangeType, ranges: Array>}} | {Timestamp: {field: string, range_type: RangeType, ranges: Array>}} | {F32: {field: string, range_type: RangeType, ranges: Array>}} | {F64: {field: string, range_type: RangeType, ranges: Array>}} | {String16: {field: string, prefix: string, length: number}} | {String32: {field: string, prefix: string, length: number}} | {StringSet16: {field: string, prefix: string, length: number}} | {StringSet32: {field: string, prefix: string, length: number}} | {Point: {field: string, range_type: RangeType, ranges: Array>, base: Vec, unit: DistanceUnit}} | 'None'; export type RangeU8 = {start: number, end: number}; export type RangeU16 = {start: number, end: number}; export type RangeU32 = {start: number, end: number}; export type RangeU64 = {start: number, end: number}; export type RangeI8 = {start: number, end: number}; export type RangeI16 = {start: number, end: number}; export type RangeI32 = {start: number, end: number}; export type RangeI64 = {start: number, end: number}; export type RangeF32 = {start: number, end: number}; export type RangeF64 = {start: number, end: number}; export type FacetFilter = {U8: {field: string, filter: RangeU8}} | {U16: {field: string, filter: RangeU16}} | {U32: {field: string, filter: RangeU32}} | {U64: {field: string, filter: RangeU64}} | {I8: {field: string, filter: RangeI8}} | {I16: {field: string, filter: RangeI16}} | {I32: {field: string, filter: RangeI32}} | {I64: {field: string, filter: RangeI64}} | {Timestamp: {field: string, filter: RangeI64}} | {F32: {field: string, filter: RangeF32}} | {F64: {field: string, filter: RangeF64}} | {String16: {field: string, filter: Array}} | {StringSet16: {field: string, filter: Array}} | {String32: {field: string, filter: Array}} | {StringSet32: {field: string, filter: Array}} | {Point: {field: string, filter: Array}}; export type SortOrder = 'Ascending' | 'Descending'; export type FacetValue = {Bool: boolean} | {U8: number} | {U16: number} | {U32: number} | {U64: number} | {I8: number} | {I16: number} | {I32: number} | {I64: number} | {Timestamp: number} | {F32: number} | {F64: number} | {String: string} | {StringSet: Array} | {Point: Vec} | 'None'; export type ResultSort = {field: string, order: SortOrder, base?: FacetValue | undefined}; export type QueryType = 'Union' | 'Intersection' | 'Phrase' | 'Not'; export type QueryRewriting = 'SearchOnly' | {SearchSuggest: {correct?: (number | null) | undefined, distance: number, term_length_threshold?: (Array | null) | undefined, complete?: (number | null) | undefined, length?: (number | null) | undefined}} | {SearchRewrite: {correct?: (number | null) | undefined, distance: number, term_length_threshold?: (Array | null) | undefined, complete?: (number | null) | undefined, length?: (number | null) | undefined}} | {SuggestOnly: {correct?: (number | null) | undefined, distance: number, term_length_threshold?: (Array | null) | undefined, complete?: (number | null) | undefined, length?: (number | null) | undefined}}; export type AnnMode = 'All' | {Nprobe: number} | {Similaritythreshold: number} | {NprobeSimilaritythreshold: Array>}; export type SearchMode = 'Lexical' | {Vector: {similarity_threshold?: (number | null) | undefined, ann_mode: AnnMode}} | {Hybrid: {similarity_threshold?: (number | null) | undefined, ann_mode: AnnMode}}; export type DistanceField = {field: string, distance: string, base: Vec, unit: DistanceUnit}; export type Highlight = {field: string, name?: string | undefined, fragment_number?: number | undefined, fragment_size?: number | undefined, highlight_markup?: boolean | undefined, pre_tags?: string | undefined, post_tags?: string | undefined}; export type DocumentOption = {fields?: Array | undefined, distance_fields?: Array | undefined, highlights?: Array | undefined}; export type SearchRequest = {query_string?: string | undefined, query_vector?: (QueryVector | null) | undefined, enable_empty_query?: boolean | undefined, offset?: number | undefined, length?: number | undefined, result_type?: ResultType | undefined, include_uncommitted?: boolean | undefined, field_filter?: Array | undefined, query_facets?: Array | undefined, facet_filter?: Array | undefined, result_sort?: Array | undefined, query_type_default?: QueryType | undefined, query_rewriting?: QueryRewriting | undefined, search_mode?: SearchMode | undefined, return_documents?: (DocumentOption | null) | undefined}; export type CreateApiApiV1IndexIndexIdQueryArgs = {apikey: string, index_id: number, body: SearchRequest}; export type CreateApiApiV1IndexIndexIdQueryOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const resultSource = z.enum(["Lexical", "Vector", "Hybrid"]); export const result = z.object({doc_id: z.number().int().gte(0), score: z.number(), field_id: z.number().int().gte(0), chunk_id: z.number().int().gte(0), level_id: z.number().int().gte(0), shard_id: z.number().int().gte(0), cluster_id: z.number().int().gte(0), cluster_score: z.number(), vector_score: z.number(), lexical_score: z.number(), source: resultSource}); export const searchResult = z.object({original_query: z.string(), query: z.string(), query_terms: z.array(z.string()), offset: z.number().int().gte(0), length: z.number().int().gte(0), count: z.number().int().gte(0), count_total: z.number().int().gte(0), observed_vector_count: z.number().int().gte(0), observed_cluster_count: z.number().int().gte(0), results: z.array(result), documents: z.array(z.record(z.string(), z.unknown())), facets: z.record(z.string(), z.array(z.array(z.unknown()))), suggestions: z.array(z.string()), time: z.number().int().gte(0)}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Query Index * * POST /api/v1/index/{index_id}/query */ export const createApiApiV1IndexIndexIdQuery = async (args: CreateApiApiV1IndexIndexIdQueryArgs, options?: CreateApiApiV1IndexIndexIdQueryOptions) => { const {baseUrl = "http://127.0.0.1", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (args.apikey != null) headers.set("apikey", String(args.apikey)) const url = `${baseUrl.replace(/\/+$/, '')}/api/v1/index/${encodeURIComponent(String(args.index_id))}/query${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(searchResult, await res.json()) };