Skip to content

Commit 694b5e4

Browse files
authored
Implement AI overview search UI (#364)
* Implement AI overview search UI * Show search results when summary fails * feat(search): support loading more results * fix(editor): preserve simple table indexes * chore: update UI
1 parent 1c3e089 commit 694b5e4

20 files changed

Lines changed: 1439 additions & 515 deletions

File tree

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,12 @@
1-
export { searchWorkspace } from '../js-services/http/misc-api';
1+
export {
2+
generateSearchSummary,
3+
searchWorkspace,
4+
searchWorkspaceDocumentPage,
5+
searchWorkspaceDocuments,
6+
} from '../js-services/http/misc-api';
7+
export type {
8+
SearchDocumentPageResponse,
9+
SearchDocumentResponseItem,
10+
SearchSummary,
11+
SearchSummaryResult,
12+
} from '../js-services/http/misc-api';

src/application/services/js-services/http/misc-api.ts

Lines changed: 114 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,113 @@ import { RepeatedChatMessage } from '@/components/chat';
88

99
import { APIResponse, executeAPIRequest, executeAPIVoidRequest, getAxios } from './core';
1010

11-
export async function searchWorkspace(workspaceId: string, query: string) {
11+
export interface SearchDocumentResponseItem {
12+
object_id: string;
13+
workspace_id: string;
14+
score: number;
15+
content: string;
16+
preview?: string | null;
17+
database_view_id?: string | null;
18+
database_id?: string | null;
19+
database_row_id?: string | null;
20+
}
21+
22+
export interface SearchDocumentPageResponse {
23+
items: SearchDocumentResponseItem[];
24+
next_offset?: number | null;
25+
has_more: boolean;
26+
}
27+
28+
export interface SearchResult {
29+
object_id: string;
30+
content: string;
31+
database_view_id?: string | null;
32+
database_id?: string | null;
33+
database_row_id?: string | null;
34+
}
35+
36+
export interface SearchSummary {
37+
content: string;
38+
highlights?: string;
39+
sources: string[];
40+
}
41+
42+
export interface SearchSummaryResult {
43+
summaries: SearchSummary[];
44+
}
45+
46+
const SEARCH_RESULT_LIMIT = 10;
47+
const SEARCH_PREVIEW_SIZE = 80;
48+
49+
export async function searchWorkspaceDocuments(workspaceId: string, query: string) {
1250
const url = `/api/search/${workspaceId}`;
13-
const payload = await executeAPIRequest<
14-
{
15-
object_id: string;
16-
}[]
17-
>(() =>
18-
getAxios()?.get<APIResponse<{ object_id: string }[]>>(url, {
19-
params: { query },
51+
52+
return executeAPIRequest<SearchDocumentResponseItem[]>(() =>
53+
getAxios()?.get<APIResponse<SearchDocumentResponseItem[]>>(url, {
54+
params: { query, limit: SEARCH_RESULT_LIMIT, preview_size: SEARCH_PREVIEW_SIZE },
55+
headers: { 'x-request-time': Date.now().toString() },
56+
})
57+
);
58+
}
59+
60+
export async function searchWorkspaceDocumentPage(workspaceId: string, query: string, offset = 0) {
61+
const url = `/api/search/${workspaceId}/page`;
62+
63+
return executeAPIRequest<SearchDocumentPageResponse>(() =>
64+
getAxios()?.get<APIResponse<SearchDocumentPageResponse>>(url, {
65+
params: {
66+
query,
67+
limit: SEARCH_RESULT_LIMIT,
68+
offset,
69+
preview_size: SEARCH_PREVIEW_SIZE,
70+
mode: 'keyword',
71+
},
2072
headers: { 'x-request-time': Date.now().toString() },
2173
})
2274
);
75+
}
76+
77+
export async function searchWorkspace(workspaceId: string, query: string) {
78+
const payload = await searchWorkspaceDocuments(workspaceId, query);
2379

2480
return payload.map((item) => item.object_id);
2581
}
2682

83+
export async function generateSearchSummary(
84+
workspaceId: string,
85+
query: string,
86+
searchResults: SearchDocumentResponseItem[]
87+
) {
88+
const url = `/api/search/${workspaceId}/summary`;
89+
const search_results: SearchResult[] = searchResults
90+
.filter((item) => item.content)
91+
.slice(0, SEARCH_RESULT_LIMIT)
92+
.map((item) => ({
93+
object_id: item.object_id,
94+
content: item.content,
95+
...(item.database_view_id ? { database_view_id: item.database_view_id } : {}),
96+
...(item.database_id ? { database_id: item.database_id } : {}),
97+
...(item.database_row_id ? { database_row_id: item.database_row_id } : {}),
98+
}));
99+
100+
if (search_results.length === 0) {
101+
return { summaries: [] };
102+
}
103+
104+
const payload = {
105+
query,
106+
search_results,
107+
only_context: true,
108+
};
109+
const headers = { 'x-request-time': Date.now().toString() };
110+
111+
return executeAPIRequest<SearchSummaryResult>(() =>
112+
getAxios()?.post<APIResponse<SearchSummaryResult>>(url, payload, {
113+
headers,
114+
})
115+
);
116+
}
117+
27118
export async function getChatMessages(workspaceId: string, chatId: string, limit?: number | undefined) {
28119
const url = `/api/chat/${workspaceId}/${chatId}/message`;
29120

@@ -52,11 +143,13 @@ export async function generateAITranslateForRow(workspaceId: string, payload: Ge
52143
[key: string]: string;
53144
}[];
54145
}>(() =>
55-
getAxios()?.post<APIResponse<{
56-
items: {
57-
[key: string]: string;
58-
}[];
59-
}>>(url, {
146+
getAxios()?.post<
147+
APIResponse<{
148+
items: {
149+
[key: string]: string;
150+
}[];
151+
}>
152+
>(url, {
60153
workspace_id: workspaceId,
61154
data: payload,
62155
})
@@ -81,10 +174,12 @@ export async function getQuickNoteList(
81174
quick_notes: QuickNote[];
82175
has_more: boolean;
83176
}>(() =>
84-
getAxios()?.get<APIResponse<{
85-
quick_notes: QuickNote[];
86-
has_more: boolean;
87-
}>>(url, {
177+
getAxios()?.get<
178+
APIResponse<{
179+
quick_notes: QuickNote[];
180+
has_more: boolean;
181+
}>
182+
>(url, {
88183
params: {
89184
offset: params.offset,
90185
limit: params.limit,
@@ -102,17 +197,13 @@ export async function getQuickNoteList(
102197
export async function createQuickNote(workspaceId: string, payload: QuickNoteEditorData[]): Promise<QuickNote> {
103198
const url = `/api/workspace/${workspaceId}/quick-note`;
104199

105-
return executeAPIRequest<QuickNote>(() =>
106-
getAxios()?.post<APIResponse<QuickNote>>(url, { data: payload })
107-
);
200+
return executeAPIRequest<QuickNote>(() => getAxios()?.post<APIResponse<QuickNote>>(url, { data: payload }));
108201
}
109202

110203
export async function updateQuickNote(workspaceId: string, noteId: string, payload: QuickNoteEditorData[]) {
111204
const url = `/api/workspace/${workspaceId}/quick-note/${noteId}`;
112205

113-
return executeAPIVoidRequest(() =>
114-
getAxios()?.put<APIResponse>(url, { data: payload })
115-
);
206+
return executeAPIVoidRequest(() => getAxios()?.put<APIResponse>(url, { data: payload }));
116207
}
117208

118209
export async function deleteQuickNote(workspaceId: string, noteId: string) {

0 commit comments

Comments
 (0)