mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-07 09:21:24 +08:00
chore(server): improve semantic search (#12838)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Updated document-related tools in chat prompts, including new options for document keyword and semantic search. - **Refactor** - Renamed and reorganized document search tools for improved clarity in tool selection and results display. - **Bug Fixes** - Ensured tool identifiers and results are consistent across chat and search features. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1792,11 +1792,11 @@ Below is the user's query. Please respond in the user's preferred language witho
|
|||||||
],
|
],
|
||||||
config: {
|
config: {
|
||||||
tools: [
|
tools: [
|
||||||
'readDoc',
|
'docRead',
|
||||||
'editDoc',
|
'docEdit',
|
||||||
|
'docKeywordSearch',
|
||||||
|
'docSemanticSearch',
|
||||||
'webSearch',
|
'webSearch',
|
||||||
'keywordSearch',
|
|
||||||
'semanticSearch',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import { AccessController } from '../../../core/permission';
|
|||||||
import { CopilotContextService } from '../context';
|
import { CopilotContextService } from '../context';
|
||||||
import {
|
import {
|
||||||
buildDocSearchGetter,
|
buildDocSearchGetter,
|
||||||
|
createDocSemanticSearchTool,
|
||||||
createExaCrawlTool,
|
createExaCrawlTool,
|
||||||
createExaSearchTool,
|
createExaSearchTool,
|
||||||
createSemanticSearchTool,
|
|
||||||
} from '../tools';
|
} from '../tools';
|
||||||
import { CopilotProviderFactory } from './factory';
|
import { CopilotProviderFactory } from './factory';
|
||||||
import {
|
import {
|
||||||
@@ -131,20 +131,21 @@ export abstract class CopilotProvider<C = any> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (tool) {
|
switch (tool) {
|
||||||
case 'webSearch': {
|
case 'docSemanticSearch': {
|
||||||
tools.web_search_exa = createExaSearchTool(this.AFFiNEConfig);
|
|
||||||
tools.web_crawl_exa = createExaCrawlTool(this.AFFiNEConfig);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'semanticSearch': {
|
|
||||||
const ac = this.moduleRef.get(AccessController, { strict: false });
|
const ac = this.moduleRef.get(AccessController, { strict: false });
|
||||||
const context = this.moduleRef.get(CopilotContextService, {
|
const context = this.moduleRef.get(CopilotContextService, {
|
||||||
strict: false,
|
strict: false,
|
||||||
});
|
});
|
||||||
const searchDocs = buildDocSearchGetter(ac, context);
|
const searchDocs = buildDocSearchGetter(ac, context);
|
||||||
tools.semantic_search = createSemanticSearchTool(
|
tools.doc_semantic_search = createDocSemanticSearchTool(
|
||||||
searchDocs.bind(null, options)
|
searchDocs.bind(null, options)
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'webSearch': {
|
||||||
|
tools.web_search_exa = createExaSearchTool(this.AFFiNEConfig);
|
||||||
|
tools.web_crawl_exa = createExaCrawlTool(this.AFFiNEConfig);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,14 +60,14 @@ export const PromptConfigStrictSchema = z.object({
|
|||||||
tools: z
|
tools: z
|
||||||
.enum([
|
.enum([
|
||||||
// work with morph
|
// work with morph
|
||||||
'editDoc',
|
'docEdit',
|
||||||
|
// work with indexer
|
||||||
|
'docRead',
|
||||||
|
'docKeywordSearch',
|
||||||
|
// work with embeddings
|
||||||
|
'docSemanticSearch',
|
||||||
// work with exa/model internal tools
|
// work with exa/model internal tools
|
||||||
'webSearch',
|
'webSearch',
|
||||||
// work with indexer
|
|
||||||
'readDoc',
|
|
||||||
'keywordSearch',
|
|
||||||
// work with embeddings
|
|
||||||
'semanticSearch',
|
|
||||||
])
|
])
|
||||||
.array()
|
.array()
|
||||||
.nullable()
|
.nullable()
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import {
|
|||||||
import { ZodType } from 'zod';
|
import { ZodType } from 'zod';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
createDocSemanticSearchTool,
|
||||||
createExaCrawlTool,
|
createExaCrawlTool,
|
||||||
createExaSearchTool,
|
createExaSearchTool,
|
||||||
createSemanticSearchTool,
|
|
||||||
} from '../tools';
|
} from '../tools';
|
||||||
import { PromptMessage } from './types';
|
import { PromptMessage } from './types';
|
||||||
|
|
||||||
@@ -380,9 +380,9 @@ export class CitationParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CustomAITools extends ToolSet {
|
export interface CustomAITools extends ToolSet {
|
||||||
|
doc_semantic_search: ReturnType<typeof createDocSemanticSearchTool>;
|
||||||
web_search_exa: ReturnType<typeof createExaSearchTool>;
|
web_search_exa: ReturnType<typeof createExaSearchTool>;
|
||||||
web_crawl_exa: ReturnType<typeof createExaCrawlTool>;
|
web_crawl_exa: ReturnType<typeof createExaCrawlTool>;
|
||||||
semantic_search: ReturnType<typeof createSemanticSearchTool>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChunkType = TextStreamPart<CustomAITools>['type'];
|
type ChunkType = TextStreamPart<CustomAITools>['type'];
|
||||||
@@ -429,7 +429,7 @@ export class TextStreamParser {
|
|||||||
case 'tool-result': {
|
case 'tool-result': {
|
||||||
result = this.addPrefix(result);
|
result = this.addPrefix(result);
|
||||||
switch (chunk.toolName) {
|
switch (chunk.toolName) {
|
||||||
case 'semantic_search': {
|
case 'doc_semantic_search': {
|
||||||
if (Array.isArray(chunk.result)) {
|
if (Array.isArray(chunk.result)) {
|
||||||
result += `\nFound ${chunk.result.length} document${chunk.result.length !== 1 ? 's' : ''} related to “${chunk.args.query}”.\n`;
|
result += `\nFound ${chunk.result.length} document${chunk.result.length !== 1 ? 's' : ''} related to “${chunk.args.query}”.\n`;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -20,12 +20,21 @@ export const buildDocSearchGetter = (
|
|||||||
.can('Workspace.Read');
|
.can('Workspace.Read');
|
||||||
if (!canAccess) return undefined;
|
if (!canAccess) return undefined;
|
||||||
const chunks = await context.matchWorkspaceAll(options.workspace, query);
|
const chunks = await context.matchWorkspaceAll(options.workspace, query);
|
||||||
return chunks || undefined;
|
const docChunks = await ac
|
||||||
|
.user(options.user)
|
||||||
|
.workspace(options.workspace)
|
||||||
|
.docs(
|
||||||
|
chunks.filter(c => 'docId' in c),
|
||||||
|
'Doc.Read'
|
||||||
|
);
|
||||||
|
const fileChunks = chunks.filter(c => 'fileId' in c);
|
||||||
|
if (!docChunks.length && !fileChunks.length) return undefined;
|
||||||
|
return [...fileChunks, ...docChunks];
|
||||||
};
|
};
|
||||||
return searchDocs;
|
return searchDocs;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createSemanticSearchTool = (
|
export const createDocSemanticSearchTool = (
|
||||||
searchDocs: (query: string) => Promise<ChunkSimilarity[] | undefined>
|
searchDocs: (query: string) => Promise<ChunkSimilarity[] | undefined>
|
||||||
) => {
|
) => {
|
||||||
return tool({
|
return tool({
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
export * from './semantic-search';
|
export * from './doc-semantic-search';
|
||||||
export * from './web-search';
|
export * from './web-search';
|
||||||
|
|||||||
Reference in New Issue
Block a user