feat(personal-assistant): add confirmed project memory
This commit is contained in:
@@ -54,6 +54,30 @@ const normalizeSnippet = (snippet: RawKnowledgeSnippet): KnowledgeSnippet => ({
|
||||
content: snippet.content || snippet.text || ''
|
||||
});
|
||||
|
||||
export const mergeKnowledgeSnippets = (...groups: RawKnowledgeSnippet[][]): KnowledgeSnippet[] => {
|
||||
const rows: KnowledgeSnippet[] = [];
|
||||
const indexes = new Map<string, number>();
|
||||
groups.flat().forEach((item) => {
|
||||
const snippet = normalizeSnippet(item);
|
||||
const key = snippet.fragmentId
|
||||
? `fragment:${snippet.fragmentId}`
|
||||
: snippet.docId
|
||||
? `${snippet.domain || snippet.sourceType || ''}:doc:${snippet.docId}`
|
||||
: `${snippet.domain || snippet.sourceType || snippet.spaceCode || ''}|${snippet.docTitle}|${snippet.content}`;
|
||||
const existingIndex = indexes.get(key);
|
||||
if (existingIndex === undefined) {
|
||||
indexes.set(key, rows.length);
|
||||
rows.push(snippet);
|
||||
return;
|
||||
}
|
||||
const present = Object.fromEntries(
|
||||
Object.entries(snippet).filter(([, value]) => value !== undefined && value !== null && value !== '')
|
||||
);
|
||||
rows[existingIndex] = { ...rows[existingIndex], ...present };
|
||||
});
|
||||
return rows;
|
||||
};
|
||||
|
||||
export const searchKnowledge = async (
|
||||
queryText: string,
|
||||
position = getSelectedPosition(),
|
||||
@@ -136,9 +160,14 @@ const normalizeUnifiedResponse = (response: UnifiedKnowledgeResponse): Knowledge
|
||||
const citationSnippets = (response.citations || []).map((item) => normalizeSnippet({
|
||||
docTitle: item.title,
|
||||
content: item.snippet,
|
||||
docId: item.docId,
|
||||
fragmentId: item.fragmentId,
|
||||
spaceCode: item.spaceCode,
|
||||
sourceType: item.sourceType
|
||||
sourceType: item.sourceType,
|
||||
domain: item.domain,
|
||||
status: item.status,
|
||||
occurredAt: item.occurredAt,
|
||||
updatedAt: item.updatedAt
|
||||
}));
|
||||
return {
|
||||
...legacy,
|
||||
@@ -148,7 +177,7 @@ const normalizeUnifiedResponse = (response: UnifiedKnowledgeResponse): Knowledge
|
||||
answer: response.answer,
|
||||
reference: legacy.reference || (response.citations || []).map((item) => item.title).join('、'),
|
||||
docs: legacy.docs || [],
|
||||
snippets: (legacy.snippets?.length ? legacy.snippets : citationSnippets).map((item) => normalizeSnippet(item as RawKnowledgeSnippet)),
|
||||
snippets: mergeKnowledgeSnippets(citationSnippets, legacy.snippets || []),
|
||||
training: legacy.training || [],
|
||||
records: legacy.records || [],
|
||||
citations: response.citations || [],
|
||||
@@ -160,7 +189,8 @@ const normalizeUnifiedResponse = (response: UnifiedKnowledgeResponse): Knowledge
|
||||
contextVersion: response.contextVersion,
|
||||
intent: response.intent,
|
||||
rewrittenQuery: response.rewrittenQuery,
|
||||
resources: response.resources || []
|
||||
resources: response.resources || [],
|
||||
memoryCandidate: response.memoryCandidate || legacy.memoryCandidate
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import type {
|
||||
MemoryCandidate,
|
||||
MemoryConfirmRequest,
|
||||
MemoryConfirmResult,
|
||||
ServiceMemory
|
||||
} from '@/types/api';
|
||||
import { apiRequest } from './api';
|
||||
|
||||
const candidateBase = '/api/aihr/personal-assistant/memory-candidates';
|
||||
|
||||
type RawServiceMemory = Omit<ServiceMemory, 'version'> & { version?: number; currentVersion?: number };
|
||||
|
||||
const rowsOf = <T>(value: T[] | { rows?: T[]; records?: T[] } | null | undefined): T[] => {
|
||||
if (Array.isArray(value)) return value;
|
||||
return value?.rows || value?.records || [];
|
||||
};
|
||||
|
||||
export const createMemoryIdempotencyKey = (candidateId: number) => {
|
||||
const suffix = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
|
||||
? crypto.randomUUID()
|
||||
: `${Date.now()}-${Math.random().toString(36).slice(2, 12)}`;
|
||||
return `memory-confirm-${candidateId}-${suffix}`;
|
||||
};
|
||||
|
||||
export const getMemoryCandidates = async (status = 'DRAFT') =>
|
||||
rowsOf(await apiRequest<MemoryCandidate[] | { rows?: MemoryCandidate[]; records?: MemoryCandidate[] }>({
|
||||
url: `${candidateBase}?status=${encodeURIComponent(status)}`,
|
||||
method: 'GET',
|
||||
timeout: 15000
|
||||
}));
|
||||
|
||||
export const confirmMemoryCandidate = (candidateId: number, request: MemoryConfirmRequest) =>
|
||||
apiRequest<MemoryConfirmResult>({
|
||||
url: `${candidateBase}/${candidateId}/confirm`,
|
||||
method: 'POST',
|
||||
data: request,
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
export const dismissMemoryCandidate = (candidateId: number) =>
|
||||
apiRequest<{ id: number; status: string }>({
|
||||
url: `${candidateBase}/${candidateId}/dismiss`,
|
||||
method: 'POST',
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
export const getServiceMemories = async () => {
|
||||
const rows = rowsOf(await apiRequest<RawServiceMemory[] | { rows?: RawServiceMemory[]; records?: RawServiceMemory[] }>({
|
||||
url: '/api/aihr/service-memories',
|
||||
method: 'GET',
|
||||
timeout: 15000
|
||||
}));
|
||||
return rows.map((item) => ({ ...item, version: item.version ?? item.currentVersion ?? 0 }));
|
||||
};
|
||||
Reference in New Issue
Block a user