-
+
+
diff --git a/src-ui/src/app/components/document-detail/document-detail.component.spec.ts b/src-ui/src/app/components/document-detail/document-detail.component.spec.ts
index 6f386ad73..1dbafd27d 100644
--- a/src-ui/src/app/components/document-detail/document-detail.component.spec.ts
+++ b/src-ui/src/app/components/document-detail/document-detail.component.spec.ts
@@ -1030,10 +1030,22 @@ describe('DocumentDetailComponent', () => {
it('should get suggestions', () => {
const suggestionsSpy = jest.spyOn(documentService, 'getSuggestions')
- suggestionsSpy.mockReturnValue(of({ tags: [42, 43] }))
+ suggestionsSpy.mockReturnValue(
+ of({
+ tags: [42, 43],
+ suggested_tags: [],
+ suggested_document_types: [],
+ suggested_correspondents: [],
+ })
+ )
initNormally()
expect(suggestionsSpy).toHaveBeenCalled()
- expect(component.suggestions).toEqual({ tags: [42, 43] })
+ expect(component.suggestions).toEqual({
+ tags: [42, 43],
+ suggested_tags: [],
+ suggested_document_types: [],
+ suggested_correspondents: [],
+ })
})
it('should show error if needed for get suggestions', () => {
diff --git a/src-ui/src/app/components/document-detail/document-detail.component.ts b/src-ui/src/app/components/document-detail/document-detail.component.ts
index 4f0893474..323f0f612 100644
--- a/src-ui/src/app/components/document-detail/document-detail.component.ts
+++ b/src-ui/src/app/components/document-detail/document-detail.component.ts
@@ -103,6 +103,7 @@ import { TextComponent } from '../common/input/text/text.component'
import { UrlComponent } from '../common/input/url/url.component'
import { PageHeaderComponent } from '../common/page-header/page-header.component'
import { ShareLinksDialogComponent } from '../common/share-links-dialog/share-links-dialog.component'
+import { SuggestionsDropdownComponent } from '../common/suggestions-dropdown/suggestions-dropdown.component'
import { DocumentHistoryComponent } from '../document-history/document-history.component'
import { DocumentNotesComponent } from '../document-notes/document-notes.component'
import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
@@ -159,6 +160,7 @@ export enum ZoomSetting {
NumberComponent,
MonetaryComponent,
UrlComponent,
+ SuggestionsDropdownComponent,
CustomDatePipe,
FileSizePipe,
IfPermissionsDirective,
diff --git a/src-ui/src/app/data/document-suggestions.ts b/src-ui/src/app/data/document-suggestions.ts
index 8c7aca515..447c4402b 100644
--- a/src-ui/src/app/data/document-suggestions.ts
+++ b/src-ui/src/app/data/document-suggestions.ts
@@ -2,12 +2,16 @@ export interface DocumentSuggestions {
title?: string
tags?: number[]
+ suggested_tags?: string[]
correspondents?: number[]
+ suggested_correspondents?: string[]
document_types?: number[]
+ suggested_document_types?: string[]
storage_paths?: number[]
+ suggested_storage_paths?: string[]
dates?: string[] // ISO-formatted date string e.g. 2022-11-03
}
diff --git a/src/documents/ai/matching.py b/src/documents/ai/matching.py
index 900fb8ac7..9267850df 100644
--- a/src/documents/ai/matching.py
+++ b/src/documents/ai/matching.py
@@ -80,3 +80,12 @@ def _match_names_to_queryset(names: list[str], queryset, attr: str):
logging.debug(f"No match for: '{name}' in {attr} list")
return results
+
+
+def extract_unmatched_names(
+ llm_names: list[str],
+ matched_objects: list,
+ attr="name",
+) -> list[str]:
+ matched_names = {getattr(obj, attr).lower() for obj in matched_objects}
+ return [name for name in llm_names if name.lower() not in matched_names]
diff --git a/src/documents/views.py b/src/documents/views.py
index ed13bf245..b475cbff1 100644
--- a/src/documents/views.py
+++ b/src/documents/views.py
@@ -78,6 +78,7 @@ from rest_framework.viewsets import ViewSet
from documents import bulk_edit
from documents import index
from documents.ai.llm_classifier import get_ai_document_classification
+from documents.ai.matching import extract_unmatched_names
from documents.ai.matching import match_correspondents_by_name
from documents.ai.matching import match_document_types_by_name
from documents.ai.matching import match_storage_paths_by_name
@@ -745,32 +746,42 @@ class DocumentViewSet(
return Response(cached.suggestions)
llm_resp = get_ai_document_classification(doc)
+
+ matched_tags = match_tags_by_name(llm_resp.get("tags", []), request.user)
+ matched_correspondents = match_correspondents_by_name(
+ llm_resp.get("correspondents", []),
+ request.user,
+ )
+ matched_types = match_document_types_by_name(
+ llm_resp.get("document_types", []),
+ )
+ matched_paths = match_storage_paths_by_name(
+ llm_resp.get("storage_paths", []),
+ request.user,
+ )
+
resp_data = {
"title": llm_resp.get("title"),
- "tags": [
- t.id
- for t in match_tags_by_name(llm_resp.get("tags", []), request.user)
- ],
- "correspondents": [
- c.id
- for c in match_correspondents_by_name(
- llm_resp.get("correspondents", []),
- request.user,
- )
- ],
- "document_types": [
- d.id
- for d in match_document_types_by_name(
- llm_resp.get("document_types", []),
- )
- ],
- "storage_paths": [
- s.id
- for s in match_storage_paths_by_name(
- llm_resp.get("storage_paths", []),
- request.user,
- )
- ],
+ "tags": [t.id for t in matched_tags],
+ "suggested_tags": extract_unmatched_names(
+ llm_resp.get("tags", []),
+ matched_tags,
+ ),
+ "correspondents": [c.id for c in matched_correspondents],
+ "suggested_correspondents": extract_unmatched_names(
+ llm_resp.get("correspondents", []),
+ matched_correspondents,
+ ),
+ "document_types": [d.id for d in matched_types],
+ "suggested_document_types": extract_unmatched_names(
+ llm_resp.get("document_types", []),
+ matched_types,
+ ),
+ "storage_paths": [s.id for s in matched_paths],
+ "suggested_storage_paths": extract_unmatched_names(
+ llm_resp.get("storage_paths", []),
+ matched_paths,
+ ),
"dates": llm_resp.get("dates", []),
}