fix(core): filter embedding results to return only user-selected tags and documents (#11770)

Close [AI-73](https://linear.app/affine-design/issue/AI-73)
This commit is contained in:
akumatus
2025-04-18 03:25:29 +00:00
parent d71cbd5fd3
commit 203e931e30
4 changed files with 53 additions and 6 deletions

View File

@@ -448,11 +448,10 @@ export class ChatPanelChips extends SignalWatcher(
if (!contextId || !AIProvider.context) {
throw new Error('Context not found');
}
const collection = this._collections.value.find(
collection => collection.id === chip.collectionId
);
// TODO: server side docIds calculation
const docIds = collection?.allowList ?? [];
const docIds = this.docDisplayConfig.getCollectionPageIds(
chip.collectionId
);
await AIProvider.context.addContextCollection({
contextId,
collectionId: chip.collectionId,

View File

@@ -74,6 +74,7 @@ export interface DocDisplayConfig {
signal: Signal<Collection[]>;
cleanup: () => void;
};
getCollectionPageIds: (collectionId: string) => string[];
}
export interface SearchMenuConfig {

View File

@@ -23,7 +23,12 @@ import type {
DocDisplayConfig,
FileChip,
} from '../ai-chat-chips/type';
import { isDocChip, isFileChip } from '../ai-chat-chips/utils';
import {
isCollectionChip,
isDocChip,
isFileChip,
isTagChip,
} from '../ai-chat-chips/utils';
import type { ChatMessage } from '../ai-chat-messages';
import type { AIChatInputContext, AINetworkSearchConfig } from './type';
@@ -521,7 +526,8 @@ export class AIChatInput extends SignalWatcher(WithDisposable(LitElement)) {
await this._preUpdateMessages(userInput, attachments);
const sessionId = await this.createSessionId();
const contexts = await this._getMatchedContexts(userInput);
let contexts = await this._getMatchedContexts(userInput);
contexts = this._filterContexts(contexts);
if (abortController.signal.aborted) {
return;
}
@@ -684,6 +690,42 @@ export class AIChatInput extends SignalWatcher(WithDisposable(LitElement)) {
files: Array.from(fileContexts.values()),
};
}
// TODO: remove this function after workspace embedding is ready
private _filterContexts(contexts: {
docs: BlockSuitePresets.AIDocContextOption[];
files: BlockSuitePresets.AIFileContextOption[];
}) {
const docIds = this.chips.reduce((acc, chip) => {
if (isDocChip(chip)) {
acc.push(chip.docId);
}
if (isTagChip(chip)) {
const docIds = this.docDisplayConfig.getTagPageIds(chip.tagId);
acc.push(...docIds);
}
if (isCollectionChip(chip)) {
const docIds = this.docDisplayConfig.getCollectionPageIds(
chip.collectionId
);
acc.push(...docIds);
}
return acc;
}, [] as string[]);
const fileIds = this.chips.reduce((acc, chip) => {
if (isFileChip(chip) && chip.blobId) {
acc.push(chip.blobId);
}
return acc;
}, [] as string[]);
const { docs, files } = contexts;
return {
docs: docs.filter(doc => docIds.includes(doc.docId)),
files: files.filter(file => fileIds.includes(file.blobId)),
};
}
}
declare global {

View File

@@ -77,6 +77,11 @@ export function useAIChatConfig() {
const collections$ = collectionService.collections$;
return createSignalFromObservable(collections$, []);
},
getCollectionPageIds: (collectionId: string) => {
const collection$ = collectionService.collection$(collectionId);
// TODO: lack of documents that meet the collection rules
return collection$?.value?.allowList ?? [];
},
};
const searchMenuConfig = {