morphik 0.1.5__py3-none-any.whl → 0.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- morphik/__init__.py +1 -1
- morphik/_internal.py +8 -8
- morphik/async_.py +192 -36
- morphik/models.py +43 -1
- morphik/sync.py +212 -51
- {morphik-0.1.5.dist-info → morphik-0.1.6.dist-info}/METADATA +1 -1
- {morphik-0.1.5.dist-info → morphik-0.1.6.dist-info}/RECORD +8 -8
- {morphik-0.1.5.dist-info → morphik-0.1.6.dist-info}/WHEEL +0 -0
morphik/sync.py
CHANGED
@@ -287,6 +287,7 @@ class Folder:
|
|
287
287
|
k: int = 4,
|
288
288
|
min_score: float = 0.0,
|
289
289
|
use_colpali: bool = True,
|
290
|
+
additional_folders: Optional[List[str]] = None,
|
290
291
|
) -> List[FinalChunkResult]:
|
291
292
|
"""
|
292
293
|
Retrieve relevant chunks within this folder.
|
@@ -297,17 +298,19 @@ class Folder:
|
|
297
298
|
k: Number of results (default: 4)
|
298
299
|
min_score: Minimum similarity threshold (default: 0.0)
|
299
300
|
use_colpali: Whether to use ColPali-style embedding model
|
301
|
+
additional_folders: Optional list of extra folders to include in the scope
|
300
302
|
|
301
303
|
Returns:
|
302
304
|
List[FinalChunkResult]: List of relevant chunks
|
303
305
|
"""
|
306
|
+
effective_folder = self._merge_folders(additional_folders)
|
304
307
|
request = {
|
305
308
|
"query": query,
|
306
309
|
"filters": filters,
|
307
310
|
"k": k,
|
308
311
|
"min_score": min_score,
|
309
312
|
"use_colpali": use_colpali,
|
310
|
-
"folder_name":
|
313
|
+
"folder_name": effective_folder,
|
311
314
|
}
|
312
315
|
|
313
316
|
response = self._client._request("POST", "retrieve/chunks", request)
|
@@ -320,6 +323,7 @@ class Folder:
|
|
320
323
|
k: int = 4,
|
321
324
|
min_score: float = 0.0,
|
322
325
|
use_colpali: bool = True,
|
326
|
+
additional_folders: Optional[List[str]] = None,
|
323
327
|
) -> List[DocumentResult]:
|
324
328
|
"""
|
325
329
|
Retrieve relevant documents within this folder.
|
@@ -330,17 +334,19 @@ class Folder:
|
|
330
334
|
k: Number of results (default: 4)
|
331
335
|
min_score: Minimum similarity threshold (default: 0.0)
|
332
336
|
use_colpali: Whether to use ColPali-style embedding model
|
337
|
+
additional_folders: Optional list of extra folders to include in the scope
|
333
338
|
|
334
339
|
Returns:
|
335
340
|
List[DocumentResult]: List of relevant documents
|
336
341
|
"""
|
342
|
+
effective_folder = self._merge_folders(additional_folders)
|
337
343
|
request = {
|
338
344
|
"query": query,
|
339
345
|
"filters": filters,
|
340
346
|
"k": k,
|
341
347
|
"min_score": min_score,
|
342
348
|
"use_colpali": use_colpali,
|
343
|
-
"folder_name":
|
349
|
+
"folder_name": effective_folder,
|
344
350
|
}
|
345
351
|
|
346
352
|
response = self._client._request("POST", "retrieve/docs", request)
|
@@ -359,6 +365,7 @@ class Folder:
|
|
359
365
|
hop_depth: int = 1,
|
360
366
|
include_paths: bool = False,
|
361
367
|
prompt_overrides: Optional[Union[QueryPromptOverrides, Dict[str, Any]]] = None,
|
368
|
+
additional_folders: Optional[List[str]] = None,
|
362
369
|
schema: Optional[Union[Type[BaseModel], Dict[str, Any]]] = None,
|
363
370
|
) -> CompletionResponse:
|
364
371
|
"""
|
@@ -376,11 +383,13 @@ class Folder:
|
|
376
383
|
hop_depth: Number of relationship hops to traverse in the graph (1-3)
|
377
384
|
include_paths: Whether to include relationship paths in the response
|
378
385
|
prompt_overrides: Optional customizations for entity extraction, resolution, and query prompts
|
386
|
+
additional_folders: Optional list of extra folders to include in the scope
|
379
387
|
schema: Optional schema for structured output
|
380
388
|
|
381
389
|
Returns:
|
382
390
|
CompletionResponse: Generated completion
|
383
391
|
"""
|
392
|
+
effective_folder = self._merge_folders(additional_folders)
|
384
393
|
payload = self._client._logic._prepare_query_request(
|
385
394
|
query,
|
386
395
|
filters,
|
@@ -393,8 +402,8 @@ class Folder:
|
|
393
402
|
hop_depth,
|
394
403
|
include_paths,
|
395
404
|
prompt_overrides,
|
396
|
-
|
397
|
-
None,
|
405
|
+
effective_folder,
|
406
|
+
None, # end_user_id not supported at this level
|
398
407
|
schema,
|
399
408
|
)
|
400
409
|
|
@@ -413,7 +422,11 @@ class Folder:
|
|
413
422
|
return self._client._logic._parse_completion_response(response)
|
414
423
|
|
415
424
|
def list_documents(
|
416
|
-
self,
|
425
|
+
self,
|
426
|
+
skip: int = 0,
|
427
|
+
limit: int = 100,
|
428
|
+
filters: Optional[Dict[str, Any]] = None,
|
429
|
+
additional_folders: Optional[List[str]] = None,
|
417
430
|
) -> List[Document]:
|
418
431
|
"""
|
419
432
|
List accessible documents within this folder.
|
@@ -422,28 +435,34 @@ class Folder:
|
|
422
435
|
skip: Number of documents to skip
|
423
436
|
limit: Maximum number of documents to return
|
424
437
|
filters: Optional filters
|
438
|
+
additional_folders: Optional list of extra folders to include in the scope
|
425
439
|
|
426
440
|
Returns:
|
427
441
|
List[Document]: List of documents
|
428
442
|
"""
|
429
|
-
|
443
|
+
effective_folder = self._merge_folders(additional_folders)
|
444
|
+
params, data = self._client._logic._prepare_list_documents_request(skip, limit, filters, effective_folder, None)
|
430
445
|
response = self._client._request("POST", "documents", data=data, params=params)
|
431
446
|
docs = self._client._logic._parse_document_list_response(response)
|
432
447
|
for doc in docs:
|
433
448
|
doc._client = self._client
|
434
449
|
return docs
|
435
450
|
|
436
|
-
def batch_get_documents(
|
451
|
+
def batch_get_documents(
|
452
|
+
self, document_ids: List[str], additional_folders: Optional[List[str]] = None
|
453
|
+
) -> List[Document]:
|
437
454
|
"""
|
438
455
|
Retrieve multiple documents by their IDs in a single batch operation within this folder.
|
439
456
|
|
440
457
|
Args:
|
441
458
|
document_ids: List of document IDs to retrieve
|
459
|
+
additional_folders: Optional list of extra folders to include in the scope
|
442
460
|
|
443
461
|
Returns:
|
444
462
|
List[Document]: List of document metadata for found documents
|
445
463
|
"""
|
446
|
-
|
464
|
+
merged = self._merge_folders(additional_folders)
|
465
|
+
request = {"document_ids": document_ids, "folder_name": merged}
|
447
466
|
|
448
467
|
response = self._client._request("POST", "batch/documents", data=request)
|
449
468
|
docs = [self._client._logic._parse_document_response(doc) for doc in response]
|
@@ -451,12 +470,17 @@ class Folder:
|
|
451
470
|
doc._client = self._client
|
452
471
|
return docs
|
453
472
|
|
454
|
-
def batch_get_chunks(
|
473
|
+
def batch_get_chunks(
|
474
|
+
self,
|
475
|
+
sources: List[Union[ChunkSource, Dict[str, Any]]],
|
476
|
+
additional_folders: Optional[List[str]] = None,
|
477
|
+
) -> List[FinalChunkResult]:
|
455
478
|
"""
|
456
479
|
Retrieve specific chunks by their document ID and chunk number in a single batch operation within this folder.
|
457
480
|
|
458
481
|
Args:
|
459
482
|
sources: List of ChunkSource objects or dictionaries with document_id and chunk_number
|
483
|
+
additional_folders: Optional list of extra folders to include in the scope
|
460
484
|
|
461
485
|
Returns:
|
462
486
|
List[FinalChunkResult]: List of chunk results
|
@@ -469,8 +493,8 @@ class Folder:
|
|
469
493
|
else:
|
470
494
|
source_dicts.append(source.model_dump())
|
471
495
|
|
472
|
-
|
473
|
-
request = {"sources": source_dicts, "folder_name":
|
496
|
+
merged = self._merge_folders(additional_folders)
|
497
|
+
request = {"sources": source_dicts, "folder_name": merged}
|
474
498
|
|
475
499
|
response = self._client._request("POST", "batch/chunks", data=request)
|
476
500
|
return self._client._logic._parse_chunk_result_list_response(response)
|
@@ -507,7 +531,9 @@ class Folder:
|
|
507
531
|
}
|
508
532
|
|
509
533
|
response = self._client._request("POST", "graph/create", request)
|
510
|
-
|
534
|
+
graph = self._logic._parse_graph_response(response)
|
535
|
+
graph._client = self
|
536
|
+
return graph
|
511
537
|
|
512
538
|
def update_graph(
|
513
539
|
self,
|
@@ -540,7 +566,9 @@ class Folder:
|
|
540
566
|
}
|
541
567
|
|
542
568
|
response = self._client._request("POST", f"graph/{name}/update", request)
|
543
|
-
|
569
|
+
graph = self._logic._parse_graph_response(response)
|
570
|
+
graph._client = self
|
571
|
+
return graph
|
544
572
|
|
545
573
|
def delete_document_by_filename(self, filename: str) -> Dict[str, str]:
|
546
574
|
"""
|
@@ -559,6 +587,21 @@ class Folder:
|
|
559
587
|
# Then delete by ID
|
560
588
|
return self._client.delete_document(doc.external_id)
|
561
589
|
|
590
|
+
# Helper --------------------------------------------------------------
|
591
|
+
def _merge_folders(self, additional_folders: Optional[List[str]] = None) -> Union[str, List[str]]:
|
592
|
+
"""Return the effective folder scope.
|
593
|
+
|
594
|
+
If *additional_folders* is provided it will be combined with the folder's
|
595
|
+
own *self._name* and returned as a list (to preserve ordering and allow
|
596
|
+
duplicates to be removed server-side). Otherwise just *self._name* is
|
597
|
+
returned so we keep backward-compatibility with the original API that
|
598
|
+
expected a single string.
|
599
|
+
"""
|
600
|
+
if not additional_folders:
|
601
|
+
return self._name
|
602
|
+
# Pre-pend the scoped folder to the list provided by the caller.
|
603
|
+
return [self._name] + additional_folders
|
604
|
+
|
562
605
|
|
563
606
|
class UserScope:
|
564
607
|
"""
|
@@ -824,6 +867,7 @@ class UserScope:
|
|
824
867
|
k: int = 4,
|
825
868
|
min_score: float = 0.0,
|
826
869
|
use_colpali: bool = True,
|
870
|
+
additional_folders: Optional[List[str]] = None,
|
827
871
|
) -> List[FinalChunkResult]:
|
828
872
|
"""
|
829
873
|
Retrieve relevant chunks as this end user.
|
@@ -834,10 +878,12 @@ class UserScope:
|
|
834
878
|
k: Number of results (default: 4)
|
835
879
|
min_score: Minimum similarity threshold (default: 0.0)
|
836
880
|
use_colpali: Whether to use ColPali-style embedding model
|
881
|
+
additional_folders: Optional list of extra folders to include in the scope
|
837
882
|
|
838
883
|
Returns:
|
839
884
|
List[FinalChunkResult]: List of relevant chunks
|
840
885
|
"""
|
886
|
+
effective_folder = self._merge_folders(additional_folders)
|
841
887
|
request = {
|
842
888
|
"query": query,
|
843
889
|
"filters": filters,
|
@@ -845,6 +891,7 @@ class UserScope:
|
|
845
891
|
"min_score": min_score,
|
846
892
|
"use_colpali": use_colpali,
|
847
893
|
"end_user_id": self._end_user_id, # Add end user ID here
|
894
|
+
"folder_name": effective_folder, # Add folder name if provided
|
848
895
|
}
|
849
896
|
|
850
897
|
# Add folder name if scoped to a folder
|
@@ -861,6 +908,7 @@ class UserScope:
|
|
861
908
|
k: int = 4,
|
862
909
|
min_score: float = 0.0,
|
863
910
|
use_colpali: bool = True,
|
911
|
+
additional_folders: Optional[List[str]] = None,
|
864
912
|
) -> List[DocumentResult]:
|
865
913
|
"""
|
866
914
|
Retrieve relevant documents as this end user.
|
@@ -871,10 +919,12 @@ class UserScope:
|
|
871
919
|
k: Number of results (default: 4)
|
872
920
|
min_score: Minimum similarity threshold (default: 0.0)
|
873
921
|
use_colpali: Whether to use ColPali-style embedding model
|
922
|
+
additional_folders: Optional list of extra folders to include in the scope
|
874
923
|
|
875
924
|
Returns:
|
876
925
|
List[DocumentResult]: List of relevant documents
|
877
926
|
"""
|
927
|
+
effective_folder = self._merge_folders(additional_folders)
|
878
928
|
request = {
|
879
929
|
"query": query,
|
880
930
|
"filters": filters,
|
@@ -882,6 +932,7 @@ class UserScope:
|
|
882
932
|
"min_score": min_score,
|
883
933
|
"use_colpali": use_colpali,
|
884
934
|
"end_user_id": self._end_user_id, # Add end user ID here
|
935
|
+
"folder_name": effective_folder, # Add folder name if provided
|
885
936
|
}
|
886
937
|
|
887
938
|
# Add folder name if scoped to a folder
|
@@ -904,6 +955,7 @@ class UserScope:
|
|
904
955
|
hop_depth: int = 1,
|
905
956
|
include_paths: bool = False,
|
906
957
|
prompt_overrides: Optional[Union[QueryPromptOverrides, Dict[str, Any]]] = None,
|
958
|
+
additional_folders: Optional[List[str]] = None,
|
907
959
|
schema: Optional[Union[Type[BaseModel], Dict[str, Any]]] = None,
|
908
960
|
) -> CompletionResponse:
|
909
961
|
"""
|
@@ -921,11 +973,13 @@ class UserScope:
|
|
921
973
|
hop_depth: Number of relationship hops to traverse in the graph (1-3)
|
922
974
|
include_paths: Whether to include relationship paths in the response
|
923
975
|
prompt_overrides: Optional customizations for entity extraction, resolution, and query prompts
|
976
|
+
additional_folders: Optional list of extra folders to include in the scope
|
924
977
|
schema: Optional schema for structured output
|
925
978
|
|
926
979
|
Returns:
|
927
980
|
CompletionResponse: Generated completion
|
928
981
|
"""
|
982
|
+
effective_folder = self._merge_folders(additional_folders)
|
929
983
|
payload = self._client._logic._prepare_query_request(
|
930
984
|
query,
|
931
985
|
filters,
|
@@ -938,7 +992,7 @@ class UserScope:
|
|
938
992
|
hop_depth,
|
939
993
|
include_paths,
|
940
994
|
prompt_overrides,
|
941
|
-
|
995
|
+
effective_folder,
|
942
996
|
self._end_user_id,
|
943
997
|
schema,
|
944
998
|
)
|
@@ -958,7 +1012,11 @@ class UserScope:
|
|
958
1012
|
return self._client._logic._parse_completion_response(response)
|
959
1013
|
|
960
1014
|
def list_documents(
|
961
|
-
self,
|
1015
|
+
self,
|
1016
|
+
skip: int = 0,
|
1017
|
+
limit: int = 100,
|
1018
|
+
filters: Optional[Dict[str, Any]] = None,
|
1019
|
+
additional_folders: Optional[List[str]] = None,
|
962
1020
|
) -> List[Document]:
|
963
1021
|
"""
|
964
1022
|
List accessible documents for this end user.
|
@@ -967,6 +1025,7 @@ class UserScope:
|
|
967
1025
|
skip: Number of documents to skip
|
968
1026
|
limit: Maximum number of documents to return
|
969
1027
|
filters: Optional filters
|
1028
|
+
additional_folders: Optional list of extra folders to include in the scope
|
970
1029
|
|
971
1030
|
Returns:
|
972
1031
|
List[Document]: List of documents
|
@@ -978,6 +1037,11 @@ class UserScope:
|
|
978
1037
|
if self._folder_name:
|
979
1038
|
params["folder_name"] = self._folder_name
|
980
1039
|
|
1040
|
+
# Merge any additional folders into the request params
|
1041
|
+
effective_folder = self._merge_folders(additional_folders)
|
1042
|
+
if effective_folder:
|
1043
|
+
params["folder_name"] = effective_folder
|
1044
|
+
|
981
1045
|
response = self._client._request("POST", "documents", data=filters or {}, params=params)
|
982
1046
|
|
983
1047
|
docs = [self._client._logic._parse_document_response(doc) for doc in response]
|
@@ -985,21 +1049,24 @@ class UserScope:
|
|
985
1049
|
doc._client = self._client
|
986
1050
|
return docs
|
987
1051
|
|
988
|
-
def batch_get_documents(
|
1052
|
+
def batch_get_documents(
|
1053
|
+
self, document_ids: List[str], additional_folders: Optional[List[str]] = None
|
1054
|
+
) -> List[Document]:
|
989
1055
|
"""
|
990
1056
|
Retrieve multiple documents by their IDs in a single batch operation for this end user.
|
991
1057
|
|
992
1058
|
Args:
|
993
1059
|
document_ids: List of document IDs to retrieve
|
1060
|
+
additional_folders: Optional list of extra folders to include in the scope
|
994
1061
|
|
995
1062
|
Returns:
|
996
1063
|
List[Document]: List of document metadata for found documents
|
997
1064
|
"""
|
1065
|
+
merged = self._merge_folders(additional_folders)
|
998
1066
|
request = {"document_ids": document_ids, "end_user_id": self._end_user_id}
|
999
1067
|
|
1000
|
-
|
1001
|
-
|
1002
|
-
request["folder_name"] = self._folder_name
|
1068
|
+
if merged:
|
1069
|
+
request["folder_name"] = merged
|
1003
1070
|
|
1004
1071
|
response = self._client._request("POST", "batch/documents", data=request)
|
1005
1072
|
docs = [self._client._logic._parse_document_response(doc) for doc in response]
|
@@ -1007,12 +1074,17 @@ class UserScope:
|
|
1007
1074
|
doc._client = self._client
|
1008
1075
|
return docs
|
1009
1076
|
|
1010
|
-
def batch_get_chunks(
|
1077
|
+
def batch_get_chunks(
|
1078
|
+
self,
|
1079
|
+
sources: List[Union[ChunkSource, Dict[str, Any]]],
|
1080
|
+
additional_folders: Optional[List[str]] = None,
|
1081
|
+
) -> List[FinalChunkResult]:
|
1011
1082
|
"""
|
1012
1083
|
Retrieve specific chunks by their document ID and chunk number in a single batch operation for this end user.
|
1013
1084
|
|
1014
1085
|
Args:
|
1015
1086
|
sources: List of ChunkSource objects or dictionaries with document_id and chunk_number
|
1087
|
+
additional_folders: Optional list of extra folders to include in the scope
|
1016
1088
|
|
1017
1089
|
Returns:
|
1018
1090
|
List[FinalChunkResult]: List of chunk results
|
@@ -1025,12 +1097,11 @@ class UserScope:
|
|
1025
1097
|
else:
|
1026
1098
|
source_dicts.append(source.model_dump())
|
1027
1099
|
|
1028
|
-
|
1100
|
+
merged = self._merge_folders(additional_folders)
|
1029
1101
|
request = {"sources": source_dicts, "end_user_id": self._end_user_id}
|
1030
1102
|
|
1031
|
-
|
1032
|
-
|
1033
|
-
request["folder_name"] = self._folder_name
|
1103
|
+
if merged:
|
1104
|
+
request["folder_name"] = merged
|
1034
1105
|
|
1035
1106
|
response = self._client._request("POST", "batch/chunks", data=request)
|
1036
1107
|
return self._client._logic._parse_chunk_result_list_response(response)
|
@@ -1071,7 +1142,9 @@ class UserScope:
|
|
1071
1142
|
request["folder_name"] = self._folder_name
|
1072
1143
|
|
1073
1144
|
response = self._client._request("POST", "graph/create", request)
|
1074
|
-
|
1145
|
+
graph = self._logic._parse_graph_response(response)
|
1146
|
+
graph._client = self
|
1147
|
+
return graph
|
1075
1148
|
|
1076
1149
|
def update_graph(
|
1077
1150
|
self,
|
@@ -1108,7 +1181,9 @@ class UserScope:
|
|
1108
1181
|
request["folder_name"] = self._folder_name
|
1109
1182
|
|
1110
1183
|
response = self._client._request("POST", f"graph/{name}/update", request)
|
1111
|
-
|
1184
|
+
graph = self._logic._parse_graph_response(response)
|
1185
|
+
graph._client = self
|
1186
|
+
return graph
|
1112
1187
|
|
1113
1188
|
def delete_document_by_filename(self, filename: str) -> Dict[str, str]:
|
1114
1189
|
"""
|
@@ -1134,6 +1209,22 @@ class UserScope:
|
|
1134
1209
|
# Then delete by ID
|
1135
1210
|
return self._client.delete_document(doc.external_id)
|
1136
1211
|
|
1212
|
+
# Helper --------------------------------------------------------------
|
1213
|
+
def _merge_folders(self, additional_folders: Optional[List[str]] = None) -> Union[str, List[str], None]:
|
1214
|
+
"""Return combined folder scope for user.
|
1215
|
+
|
1216
|
+
When this user scope is already tied to *self._folder_name* we combine it
|
1217
|
+
with any *additional_folders* passed by the caller. Otherwise just the
|
1218
|
+
*additional_folders* (or None) is returned so that upstream logic is
|
1219
|
+
unchanged.
|
1220
|
+
"""
|
1221
|
+
base = self._folder_name
|
1222
|
+
if additional_folders:
|
1223
|
+
if base:
|
1224
|
+
return [base] + additional_folders
|
1225
|
+
return additional_folders
|
1226
|
+
return base
|
1227
|
+
|
1137
1228
|
|
1138
1229
|
class Morphik:
|
1139
1230
|
"""
|
@@ -1542,6 +1633,7 @@ class Morphik:
|
|
1542
1633
|
k: int = 4,
|
1543
1634
|
min_score: float = 0.0,
|
1544
1635
|
use_colpali: bool = True,
|
1636
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
1545
1637
|
) -> List[FinalChunkResult]:
|
1546
1638
|
"""
|
1547
1639
|
Retrieve relevant chunks.
|
@@ -1564,7 +1656,9 @@ class Morphik:
|
|
1564
1656
|
)
|
1565
1657
|
```
|
1566
1658
|
"""
|
1567
|
-
payload = self._logic._prepare_retrieve_chunks_request(
|
1659
|
+
payload = self._logic._prepare_retrieve_chunks_request(
|
1660
|
+
query, filters, k, min_score, use_colpali, folder_name, None
|
1661
|
+
)
|
1568
1662
|
response = self._request("POST", "retrieve/chunks", data=payload)
|
1569
1663
|
return self._logic._parse_chunk_result_list_response(response)
|
1570
1664
|
|
@@ -1575,6 +1669,7 @@ class Morphik:
|
|
1575
1669
|
k: int = 4,
|
1576
1670
|
min_score: float = 0.0,
|
1577
1671
|
use_colpali: bool = True,
|
1672
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
1578
1673
|
) -> List[DocumentResult]:
|
1579
1674
|
"""
|
1580
1675
|
Retrieve relevant documents.
|
@@ -1597,7 +1692,9 @@ class Morphik:
|
|
1597
1692
|
)
|
1598
1693
|
```
|
1599
1694
|
"""
|
1600
|
-
payload = self._logic._prepare_retrieve_docs_request(
|
1695
|
+
payload = self._logic._prepare_retrieve_docs_request(
|
1696
|
+
query, filters, k, min_score, use_colpali, folder_name, None
|
1697
|
+
)
|
1601
1698
|
response = self._request("POST", "retrieve/docs", data=payload)
|
1602
1699
|
return self._logic._parse_document_result_list_response(response)
|
1603
1700
|
|
@@ -1614,6 +1711,7 @@ class Morphik:
|
|
1614
1711
|
hop_depth: int = 1,
|
1615
1712
|
include_paths: bool = False,
|
1616
1713
|
prompt_overrides: Optional[Union[QueryPromptOverrides, Dict[str, Any]]] = None,
|
1714
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
1617
1715
|
schema: Optional[Union[Type[BaseModel], Dict[str, Any]]] = None,
|
1618
1716
|
) -> CompletionResponse:
|
1619
1717
|
"""
|
@@ -1633,6 +1731,7 @@ class Morphik:
|
|
1633
1731
|
include_paths: Whether to include relationship paths in the response
|
1634
1732
|
prompt_overrides: Optional customizations for entity extraction, resolution, and query prompts
|
1635
1733
|
Either a QueryPromptOverrides object or a dictionary with the same structure
|
1734
|
+
folder_name: Optional folder name to further scope operations
|
1636
1735
|
schema: Optional schema for structured output, can be a Pydantic model or a JSON schema dict
|
1637
1736
|
Returns:
|
1638
1737
|
CompletionResponse
|
@@ -1704,6 +1803,7 @@ class Morphik:
|
|
1704
1803
|
print(f"- {evidence}")
|
1705
1804
|
```
|
1706
1805
|
"""
|
1806
|
+
# Directly forward the supplied folder_name (may be None, str, or List[str])
|
1707
1807
|
payload = self._logic._prepare_query_request(
|
1708
1808
|
query,
|
1709
1809
|
filters,
|
@@ -1716,8 +1816,8 @@ class Morphik:
|
|
1716
1816
|
hop_depth,
|
1717
1817
|
include_paths,
|
1718
1818
|
prompt_overrides,
|
1719
|
-
|
1720
|
-
None,
|
1819
|
+
folder_name,
|
1820
|
+
None, # end_user_id not supported at this level
|
1721
1821
|
schema,
|
1722
1822
|
)
|
1723
1823
|
|
@@ -1736,7 +1836,11 @@ class Morphik:
|
|
1736
1836
|
return self._logic._parse_completion_response(response)
|
1737
1837
|
|
1738
1838
|
def list_documents(
|
1739
|
-
self,
|
1839
|
+
self,
|
1840
|
+
skip: int = 0,
|
1841
|
+
limit: int = 100,
|
1842
|
+
filters: Optional[Dict[str, Any]] = None,
|
1843
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
1740
1844
|
) -> List[Document]:
|
1741
1845
|
"""
|
1742
1846
|
List accessible documents.
|
@@ -1745,6 +1849,7 @@ class Morphik:
|
|
1745
1849
|
skip: Number of documents to skip
|
1746
1850
|
limit: Maximum number of documents to return
|
1747
1851
|
filters: Optional filters
|
1852
|
+
folder_name: Optional folder name (or list of names) to scope the request
|
1748
1853
|
|
1749
1854
|
Returns:
|
1750
1855
|
List[Document]: List of accessible documents
|
@@ -1758,7 +1863,7 @@ class Morphik:
|
|
1758
1863
|
next_page = db.list_documents(skip=10, limit=10, filters={"department": "research"})
|
1759
1864
|
```
|
1760
1865
|
"""
|
1761
|
-
params, data = self._logic._prepare_list_documents_request(skip, limit, filters,
|
1866
|
+
params, data = self._logic._prepare_list_documents_request(skip, limit, filters, folder_name, None)
|
1762
1867
|
response = self._request("POST", "documents", data=data, params=params)
|
1763
1868
|
docs = self._logic._parse_document_list_response(response)
|
1764
1869
|
for doc in docs:
|
@@ -2210,12 +2315,15 @@ class Morphik:
|
|
2210
2315
|
|
2211
2316
|
return result
|
2212
2317
|
|
2213
|
-
def batch_get_documents(
|
2318
|
+
def batch_get_documents(
|
2319
|
+
self, document_ids: List[str], folder_name: Optional[Union[str, List[str]]] = None
|
2320
|
+
) -> List[Document]:
|
2214
2321
|
"""
|
2215
|
-
Retrieve multiple documents by their IDs
|
2322
|
+
Retrieve multiple documents by their IDs.
|
2216
2323
|
|
2217
2324
|
Args:
|
2218
2325
|
document_ids: List of document IDs to retrieve
|
2326
|
+
folder_name: Optional folder name (or list of names) to scope the request
|
2219
2327
|
|
2220
2328
|
Returns:
|
2221
2329
|
List[Document]: List of document metadata for found documents
|
@@ -2227,19 +2335,23 @@ class Morphik:
|
|
2227
2335
|
print(f"Document {doc.external_id}: {doc.metadata.get('title')}")
|
2228
2336
|
```
|
2229
2337
|
"""
|
2230
|
-
#
|
2231
|
-
|
2338
|
+
# Build request respecting folder scoping if provided
|
2339
|
+
request = self._logic._prepare_batch_get_documents_request(document_ids, folder_name, None)
|
2340
|
+
response = self._request("POST", "batch/documents", data=request)
|
2232
2341
|
docs = self._logic._parse_document_list_response(response)
|
2233
2342
|
for doc in docs:
|
2234
2343
|
doc._client = self
|
2235
2344
|
return docs
|
2236
2345
|
|
2237
|
-
def batch_get_chunks(
|
2346
|
+
def batch_get_chunks(
|
2347
|
+
self, sources: List[Union[ChunkSource, Dict[str, Any]]], folder_name: Optional[Union[str, List[str]]] = None
|
2348
|
+
) -> List[FinalChunkResult]:
|
2238
2349
|
"""
|
2239
|
-
Retrieve specific chunks by their document ID and chunk number
|
2350
|
+
Retrieve specific chunks by their document ID and chunk number.
|
2240
2351
|
|
2241
2352
|
Args:
|
2242
2353
|
sources: List of ChunkSource objects or dictionaries with document_id and chunk_number
|
2354
|
+
folder_name: Optional folder name (or list of names) to scope the request
|
2243
2355
|
|
2244
2356
|
Returns:
|
2245
2357
|
List[FinalChunkResult]: List of chunk results
|
@@ -2264,15 +2376,8 @@ class Morphik:
|
|
2264
2376
|
print(f"Chunk from {chunk.document_id}, number {chunk.chunk_number}: {chunk.content[:50]}...")
|
2265
2377
|
```
|
2266
2378
|
"""
|
2267
|
-
|
2268
|
-
|
2269
|
-
for source in sources:
|
2270
|
-
if isinstance(source, dict):
|
2271
|
-
source_dicts.append(source)
|
2272
|
-
else:
|
2273
|
-
source_dicts.append(source.model_dump())
|
2274
|
-
|
2275
|
-
response = self._request("POST", "batch/chunks", data=source_dicts)
|
2379
|
+
request = self._logic._prepare_batch_get_chunks_request(sources, folder_name, None)
|
2380
|
+
response = self._request("POST", "batch/chunks", data=request)
|
2276
2381
|
return self._logic._parse_chunk_result_list_response(response)
|
2277
2382
|
|
2278
2383
|
def create_cache(
|
@@ -2410,7 +2515,9 @@ class Morphik:
|
|
2410
2515
|
request["prompt_overrides"] = prompt_overrides
|
2411
2516
|
|
2412
2517
|
response = self._request("POST", "graph/create", request)
|
2413
|
-
|
2518
|
+
graph = self._logic._parse_graph_response(response)
|
2519
|
+
graph._client = self
|
2520
|
+
return graph
|
2414
2521
|
|
2415
2522
|
def get_graph(self, name: str) -> Graph:
|
2416
2523
|
"""
|
@@ -2430,7 +2537,9 @@ class Morphik:
|
|
2430
2537
|
```
|
2431
2538
|
"""
|
2432
2539
|
response = self._request("GET", f"graph/{name}")
|
2433
|
-
|
2540
|
+
graph = self._logic._parse_graph_response(response)
|
2541
|
+
graph._client = self
|
2542
|
+
return graph
|
2434
2543
|
|
2435
2544
|
def list_graphs(self) -> List[Graph]:
|
2436
2545
|
"""
|
@@ -2448,7 +2557,10 @@ class Morphik:
|
|
2448
2557
|
```
|
2449
2558
|
"""
|
2450
2559
|
response = self._request("GET", "graphs")
|
2451
|
-
|
2560
|
+
graphs = self._logic._parse_graph_list_response(response)
|
2561
|
+
for g in graphs:
|
2562
|
+
g._client = self
|
2563
|
+
return graphs
|
2452
2564
|
|
2453
2565
|
def update_graph(
|
2454
2566
|
self,
|
@@ -2512,7 +2624,9 @@ class Morphik:
|
|
2512
2624
|
}
|
2513
2625
|
|
2514
2626
|
response = self._request("POST", f"graph/{name}/update", request)
|
2515
|
-
|
2627
|
+
graph = self._logic._parse_graph_response(response)
|
2628
|
+
graph._client = self
|
2629
|
+
return graph
|
2516
2630
|
|
2517
2631
|
def delete_document(self, document_id: str) -> Dict[str, str]:
|
2518
2632
|
"""
|
@@ -2574,3 +2688,50 @@ class Morphik:
|
|
2574
2688
|
|
2575
2689
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
2576
2690
|
self.close()
|
2691
|
+
|
2692
|
+
def create_app(self, app_id: str, name: str, expiry_days: int = 30) -> Dict[str, str]:
|
2693
|
+
"""Create a new application in Morphik Cloud and obtain its auth URI.
|
2694
|
+
|
2695
|
+
This wraps the enterprise endpoint ``/ee/create_app`` which
|
2696
|
+
returns a dictionary ``{\"uri\": ..., \"app_id\": ...}``.
|
2697
|
+
|
2698
|
+
Parameters
|
2699
|
+
----------
|
2700
|
+
app_id:
|
2701
|
+
Identifier for the new application.
|
2702
|
+
name:
|
2703
|
+
Human-readable application name (will be slugified by the server).
|
2704
|
+
expiry_days:
|
2705
|
+
Token validity period. Defaults to 30 days.
|
2706
|
+
"""
|
2707
|
+
|
2708
|
+
payload = {"app_id": app_id, "name": name, "expiry_days": expiry_days}
|
2709
|
+
return self._request("POST", "ee/create_app", data=payload)
|
2710
|
+
|
2711
|
+
def wait_for_graph_completion(
|
2712
|
+
self,
|
2713
|
+
graph_name: str,
|
2714
|
+
timeout_seconds: int = 300,
|
2715
|
+
check_interval_seconds: int = 5,
|
2716
|
+
) -> Graph:
|
2717
|
+
"""Block until the specified graph finishes processing.
|
2718
|
+
|
2719
|
+
Args:
|
2720
|
+
graph_name: Name of the graph to monitor.
|
2721
|
+
timeout_seconds: Maximum seconds to wait.
|
2722
|
+
check_interval_seconds: Seconds between status checks.
|
2723
|
+
|
2724
|
+
Returns:
|
2725
|
+
Graph: The completed graph object.
|
2726
|
+
"""
|
2727
|
+
import time
|
2728
|
+
|
2729
|
+
start = time.time()
|
2730
|
+
while time.time() - start < timeout_seconds:
|
2731
|
+
graph = self.get_graph(graph_name)
|
2732
|
+
if graph.is_completed:
|
2733
|
+
return graph
|
2734
|
+
if graph.is_failed:
|
2735
|
+
raise RuntimeError(graph.error or "Graph processing failed")
|
2736
|
+
time.sleep(check_interval_seconds)
|
2737
|
+
raise TimeoutError("Timed out waiting for graph completion")
|