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/__init__.py
CHANGED
morphik/_internal.py
CHANGED
@@ -232,7 +232,7 @@ class _MorphikClientLogic:
|
|
232
232
|
hop_depth: int,
|
233
233
|
include_paths: bool,
|
234
234
|
prompt_overrides: Optional[Dict],
|
235
|
-
folder_name: Optional[str],
|
235
|
+
folder_name: Optional[Union[str, List[str]]],
|
236
236
|
end_user_id: Optional[str],
|
237
237
|
schema: Optional[Union[Type[BaseModel], Dict[str, Any]]] = None,
|
238
238
|
) -> Dict[str, Any]:
|
@@ -278,7 +278,7 @@ class _MorphikClientLogic:
|
|
278
278
|
k: int,
|
279
279
|
min_score: float,
|
280
280
|
use_colpali: bool,
|
281
|
-
folder_name: Optional[str],
|
281
|
+
folder_name: Optional[Union[str, List[str]]],
|
282
282
|
end_user_id: Optional[str],
|
283
283
|
) -> Dict[str, Any]:
|
284
284
|
"""Prepare request for retrieve_chunks endpoint"""
|
@@ -302,7 +302,7 @@ class _MorphikClientLogic:
|
|
302
302
|
k: int,
|
303
303
|
min_score: float,
|
304
304
|
use_colpali: bool,
|
305
|
-
folder_name: Optional[str],
|
305
|
+
folder_name: Optional[Union[str, List[str]]],
|
306
306
|
end_user_id: Optional[str],
|
307
307
|
) -> Dict[str, Any]:
|
308
308
|
"""Prepare request for retrieve_docs endpoint"""
|
@@ -324,7 +324,7 @@ class _MorphikClientLogic:
|
|
324
324
|
skip: int,
|
325
325
|
limit: int,
|
326
326
|
filters: Optional[Dict[str, Any]],
|
327
|
-
folder_name: Optional[str],
|
327
|
+
folder_name: Optional[Union[str, List[str]]],
|
328
328
|
end_user_id: Optional[str],
|
329
329
|
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
330
330
|
"""Prepare request for list_documents endpoint"""
|
@@ -340,7 +340,7 @@ class _MorphikClientLogic:
|
|
340
340
|
return params, data
|
341
341
|
|
342
342
|
def _prepare_batch_get_documents_request(
|
343
|
-
self, document_ids: List[str], folder_name: Optional[str], end_user_id: Optional[str]
|
343
|
+
self, document_ids: List[str], folder_name: Optional[Union[str, List[str]]], end_user_id: Optional[str]
|
344
344
|
) -> Dict[str, Any]:
|
345
345
|
"""Prepare request for batch_get_documents endpoint"""
|
346
346
|
if folder_name or end_user_id:
|
@@ -355,7 +355,7 @@ class _MorphikClientLogic:
|
|
355
355
|
def _prepare_batch_get_chunks_request(
|
356
356
|
self,
|
357
357
|
sources: List[Union[ChunkSource, Dict[str, Any]]],
|
358
|
-
folder_name: Optional[str],
|
358
|
+
folder_name: Optional[Union[str, List[str]]],
|
359
359
|
end_user_id: Optional[str],
|
360
360
|
) -> Dict[str, Any]:
|
361
361
|
"""Prepare request for batch_get_chunks endpoint"""
|
@@ -382,7 +382,7 @@ class _MorphikClientLogic:
|
|
382
382
|
filters: Optional[Dict[str, Any]],
|
383
383
|
documents: Optional[List[str]],
|
384
384
|
prompt_overrides: Optional[Union[GraphPromptOverrides, Dict[str, Any]]],
|
385
|
-
folder_name: Optional[str],
|
385
|
+
folder_name: Optional[Union[str, List[str]]],
|
386
386
|
end_user_id: Optional[str],
|
387
387
|
) -> Dict[str, Any]:
|
388
388
|
"""Prepare request for create_graph endpoint"""
|
@@ -408,7 +408,7 @@ class _MorphikClientLogic:
|
|
408
408
|
additional_filters: Optional[Dict[str, Any]],
|
409
409
|
additional_documents: Optional[List[str]],
|
410
410
|
prompt_overrides: Optional[Union[GraphPromptOverrides, Dict[str, Any]]],
|
411
|
-
folder_name: Optional[str],
|
411
|
+
folder_name: Optional[Union[str, List[str]]],
|
412
412
|
end_user_id: Optional[str],
|
413
413
|
) -> Dict[str, Any]:
|
414
414
|
"""Prepare request for update_graph endpoint"""
|
morphik/async_.py
CHANGED
@@ -286,6 +286,7 @@ class AsyncFolder:
|
|
286
286
|
k: int = 4,
|
287
287
|
min_score: float = 0.0,
|
288
288
|
use_colpali: bool = True,
|
289
|
+
additional_folders: Optional[List[str]] = None,
|
289
290
|
) -> List[FinalChunkResult]:
|
290
291
|
"""
|
291
292
|
Retrieve relevant chunks within this folder.
|
@@ -296,12 +297,14 @@ class AsyncFolder:
|
|
296
297
|
k: Number of results (default: 4)
|
297
298
|
min_score: Minimum similarity threshold (default: 0.0)
|
298
299
|
use_colpali: Whether to use ColPali-style embedding model
|
300
|
+
additional_folders: Optional list of additional folder names to further scope operations
|
299
301
|
|
300
302
|
Returns:
|
301
303
|
List[FinalChunkResult]: List of relevant chunks
|
302
304
|
"""
|
305
|
+
effective_folder = self._merge_folders(additional_folders)
|
303
306
|
payload = self._client._logic._prepare_retrieve_chunks_request(
|
304
|
-
query, filters, k, min_score, use_colpali,
|
307
|
+
query, filters, k, min_score, use_colpali, effective_folder, None
|
305
308
|
)
|
306
309
|
response = await self._client._request("POST", "retrieve/chunks", data=payload)
|
307
310
|
return self._client._logic._parse_chunk_result_list_response(response)
|
@@ -313,6 +316,7 @@ class AsyncFolder:
|
|
313
316
|
k: int = 4,
|
314
317
|
min_score: float = 0.0,
|
315
318
|
use_colpali: bool = True,
|
319
|
+
additional_folders: Optional[List[str]] = None,
|
316
320
|
) -> List[DocumentResult]:
|
317
321
|
"""
|
318
322
|
Retrieve relevant documents within this folder.
|
@@ -323,12 +327,14 @@ class AsyncFolder:
|
|
323
327
|
k: Number of results (default: 4)
|
324
328
|
min_score: Minimum similarity threshold (default: 0.0)
|
325
329
|
use_colpali: Whether to use ColPali-style embedding model
|
330
|
+
additional_folders: Optional list of additional folder names to further scope operations
|
326
331
|
|
327
332
|
Returns:
|
328
333
|
List[DocumentResult]: List of relevant documents
|
329
334
|
"""
|
335
|
+
effective_folder = self._merge_folders(additional_folders)
|
330
336
|
payload = self._client._logic._prepare_retrieve_docs_request(
|
331
|
-
query, filters, k, min_score, use_colpali,
|
337
|
+
query, filters, k, min_score, use_colpali, effective_folder, None
|
332
338
|
)
|
333
339
|
response = await self._client._request("POST", "retrieve/docs", data=payload)
|
334
340
|
return self._client._logic._parse_document_result_list_response(response)
|
@@ -346,6 +352,7 @@ class AsyncFolder:
|
|
346
352
|
hop_depth: int = 1,
|
347
353
|
include_paths: bool = False,
|
348
354
|
prompt_overrides: Optional[Union[QueryPromptOverrides, Dict[str, Any]]] = None,
|
355
|
+
additional_folders: Optional[List[str]] = None,
|
349
356
|
schema: Optional[Union[Type[BaseModel], Dict[str, Any]]] = None,
|
350
357
|
) -> CompletionResponse:
|
351
358
|
"""
|
@@ -364,10 +371,12 @@ class AsyncFolder:
|
|
364
371
|
include_paths: Whether to include relationship paths in the response
|
365
372
|
prompt_overrides: Optional customizations for entity extraction, resolution, and query prompts
|
366
373
|
schema: Optional schema for structured output
|
374
|
+
additional_folders: Optional list of additional folder names to further scope operations
|
367
375
|
|
368
376
|
Returns:
|
369
377
|
CompletionResponse: Generated completion or structured output
|
370
378
|
"""
|
379
|
+
effective_folder = self._merge_folders(additional_folders)
|
371
380
|
payload = self._client._logic._prepare_query_request(
|
372
381
|
query,
|
373
382
|
filters,
|
@@ -380,15 +389,31 @@ class AsyncFolder:
|
|
380
389
|
hop_depth,
|
381
390
|
include_paths,
|
382
391
|
prompt_overrides,
|
383
|
-
|
392
|
+
effective_folder,
|
384
393
|
None,
|
385
394
|
schema,
|
386
395
|
)
|
396
|
+
|
397
|
+
# Add schema to payload if provided
|
398
|
+
if schema:
|
399
|
+
# If schema is a Pydantic model class, we need to serialize it to a schema dict
|
400
|
+
if isinstance(schema, type) and issubclass(schema, BaseModel):
|
401
|
+
payload["schema"] = schema.model_json_schema()
|
402
|
+
else:
|
403
|
+
payload["schema"] = schema
|
404
|
+
|
405
|
+
# Add a hint to the query to return in JSON format
|
406
|
+
payload["query"] = f"{payload['query']}\nReturn the answer in JSON format according to the required schema."
|
407
|
+
|
387
408
|
response = await self._client._request("POST", "query", data=payload)
|
388
409
|
return self._client._logic._parse_completion_response(response)
|
389
410
|
|
390
411
|
async def list_documents(
|
391
|
-
self,
|
412
|
+
self,
|
413
|
+
skip: int = 0,
|
414
|
+
limit: int = 100,
|
415
|
+
filters: Optional[Dict[str, Any]] = None,
|
416
|
+
additional_folders: Optional[List[str]] = None,
|
392
417
|
) -> List[Document]:
|
393
418
|
"""
|
394
419
|
List accessible documents within this folder.
|
@@ -397,48 +422,57 @@ class AsyncFolder:
|
|
397
422
|
skip: Number of documents to skip
|
398
423
|
limit: Maximum number of documents to return
|
399
424
|
filters: Optional filters
|
425
|
+
additional_folders: Optional list of additional folder names to further scope operations
|
400
426
|
|
401
427
|
Returns:
|
402
428
|
List[Document]: List of documents
|
403
429
|
"""
|
404
|
-
|
430
|
+
effective_folder = self._merge_folders(additional_folders)
|
431
|
+
params, data = self._client._logic._prepare_list_documents_request(skip, limit, filters, effective_folder, None)
|
405
432
|
response = await self._client._request("POST", "documents", data=data, params=params)
|
406
433
|
docs = self._client._logic._parse_document_list_response(response)
|
407
434
|
for doc in docs:
|
408
435
|
doc._client = self._client
|
409
436
|
return docs
|
410
437
|
|
411
|
-
async def batch_get_documents(
|
438
|
+
async def batch_get_documents(
|
439
|
+
self, document_ids: List[str], additional_folders: Optional[List[str]] = None
|
440
|
+
) -> List[Document]:
|
412
441
|
"""
|
413
442
|
Retrieve multiple documents by their IDs in a single batch operation within this folder.
|
414
443
|
|
415
444
|
Args:
|
416
445
|
document_ids: List of document IDs to retrieve
|
446
|
+
additional_folders: Optional list of additional folder names to further scope operations
|
417
447
|
|
418
448
|
Returns:
|
419
449
|
List[Document]: List of document metadata for found documents
|
420
450
|
"""
|
421
|
-
|
422
|
-
request = {"document_ids": document_ids}
|
423
|
-
if self._name:
|
424
|
-
request["folder_name"] = self._name
|
451
|
+
merged = self._merge_folders(additional_folders)
|
452
|
+
request = {"document_ids": document_ids, "folder_name": merged}
|
425
453
|
response = await self._client._request("POST", "batch/documents", data=request)
|
426
454
|
docs = self._client._logic._parse_document_list_response(response)
|
427
455
|
for doc in docs:
|
428
456
|
doc._client = self._client
|
429
457
|
return docs
|
430
458
|
|
431
|
-
async def batch_get_chunks(
|
459
|
+
async def batch_get_chunks(
|
460
|
+
self,
|
461
|
+
sources: List[Union[ChunkSource, Dict[str, Any]]],
|
462
|
+
additional_folders: Optional[List[str]] = None,
|
463
|
+
) -> List[FinalChunkResult]:
|
432
464
|
"""
|
433
465
|
Retrieve specific chunks by their document ID and chunk number in a single batch operation within this folder.
|
434
466
|
|
435
467
|
Args:
|
436
468
|
sources: List of ChunkSource objects or dictionaries with document_id and chunk_number
|
469
|
+
additional_folders: Optional list of additional folder names to further scope operations
|
437
470
|
|
438
471
|
Returns:
|
439
472
|
List[FinalChunkResult]: List of chunk results
|
440
473
|
"""
|
441
|
-
|
474
|
+
merged = self._merge_folders(additional_folders)
|
475
|
+
request = self._client._logic._prepare_batch_get_chunks_request(sources, merged, None)
|
442
476
|
response = await self._client._request("POST", "batch/chunks", data=request)
|
443
477
|
return self._client._logic._parse_chunk_result_list_response(response)
|
444
478
|
|
@@ -465,7 +499,9 @@ class AsyncFolder:
|
|
465
499
|
name, filters, documents, prompt_overrides, self._name, None
|
466
500
|
)
|
467
501
|
response = await self._client._request("POST", "graph/create", data=request)
|
468
|
-
|
502
|
+
graph = self._logic._parse_graph_response(response)
|
503
|
+
graph._client = self # Attach AsyncMorphik client for polling helpers
|
504
|
+
return graph
|
469
505
|
|
470
506
|
async def update_graph(
|
471
507
|
self,
|
@@ -490,7 +526,9 @@ class AsyncFolder:
|
|
490
526
|
name, additional_filters, additional_documents, prompt_overrides, self._name, None
|
491
527
|
)
|
492
528
|
response = await self._client._request("POST", f"graph/{name}/update", data=request)
|
493
|
-
|
529
|
+
graph = self._logic._parse_graph_response(response)
|
530
|
+
graph._client = self
|
531
|
+
return graph
|
494
532
|
|
495
533
|
async def delete_document_by_filename(self, filename: str) -> Dict[str, str]:
|
496
534
|
"""
|
@@ -511,6 +549,18 @@ class AsyncFolder:
|
|
511
549
|
# Then delete by ID
|
512
550
|
return await self._client.delete_document(doc.external_id)
|
513
551
|
|
552
|
+
# Helper --------------------------------------------------------------
|
553
|
+
def _merge_folders(self, additional_folders: Optional[List[str]] = None) -> Union[str, List[str]]:
|
554
|
+
"""Return the effective folder scope for this folder instance.
|
555
|
+
|
556
|
+
If *additional_folders* is provided it will be combined with the scoped
|
557
|
+
folder (*self._name*) and returned as a list. Otherwise just
|
558
|
+
*self._name* is returned so the API keeps backward-compatibility with
|
559
|
+
accepting a single string."""
|
560
|
+
if not additional_folders:
|
561
|
+
return self._name
|
562
|
+
return [self._name] + additional_folders
|
563
|
+
|
514
564
|
|
515
565
|
class AsyncUserScope:
|
516
566
|
"""
|
@@ -769,6 +819,7 @@ class AsyncUserScope:
|
|
769
819
|
k: int = 4,
|
770
820
|
min_score: float = 0.0,
|
771
821
|
use_colpali: bool = True,
|
822
|
+
additional_folders: Optional[List[str]] = None,
|
772
823
|
) -> List[FinalChunkResult]:
|
773
824
|
"""
|
774
825
|
Retrieve relevant chunks as this end user.
|
@@ -779,12 +830,14 @@ class AsyncUserScope:
|
|
779
830
|
k: Number of results (default: 4)
|
780
831
|
min_score: Minimum similarity threshold (default: 0.0)
|
781
832
|
use_colpali: Whether to use ColPali-style embedding model
|
833
|
+
additional_folders: Optional list of additional folder names to further scope operations
|
782
834
|
|
783
835
|
Returns:
|
784
836
|
List[FinalChunkResult]: List of relevant chunks
|
785
837
|
"""
|
838
|
+
effective_folder = self._merge_folders(additional_folders)
|
786
839
|
payload = self._client._logic._prepare_retrieve_chunks_request(
|
787
|
-
query, filters, k, min_score, use_colpali,
|
840
|
+
query, filters, k, min_score, use_colpali, effective_folder, self._end_user_id
|
788
841
|
)
|
789
842
|
response = await self._client._request("POST", "retrieve/chunks", data=payload)
|
790
843
|
return self._client._logic._parse_chunk_result_list_response(response)
|
@@ -796,6 +849,7 @@ class AsyncUserScope:
|
|
796
849
|
k: int = 4,
|
797
850
|
min_score: float = 0.0,
|
798
851
|
use_colpali: bool = True,
|
852
|
+
additional_folders: Optional[List[str]] = None,
|
799
853
|
) -> List[DocumentResult]:
|
800
854
|
"""
|
801
855
|
Retrieve relevant documents as this end user.
|
@@ -806,12 +860,14 @@ class AsyncUserScope:
|
|
806
860
|
k: Number of results (default: 4)
|
807
861
|
min_score: Minimum similarity threshold (default: 0.0)
|
808
862
|
use_colpali: Whether to use ColPali-style embedding model
|
863
|
+
additional_folders: Optional list of additional folder names to further scope operations
|
809
864
|
|
810
865
|
Returns:
|
811
866
|
List[DocumentResult]: List of relevant documents
|
812
867
|
"""
|
868
|
+
effective_folder = self._merge_folders(additional_folders)
|
813
869
|
payload = self._client._logic._prepare_retrieve_docs_request(
|
814
|
-
query, filters, k, min_score, use_colpali,
|
870
|
+
query, filters, k, min_score, use_colpali, effective_folder, self._end_user_id
|
815
871
|
)
|
816
872
|
response = await self._client._request("POST", "retrieve/docs", data=payload)
|
817
873
|
return self._client._logic._parse_document_result_list_response(response)
|
@@ -829,6 +885,7 @@ class AsyncUserScope:
|
|
829
885
|
hop_depth: int = 1,
|
830
886
|
include_paths: bool = False,
|
831
887
|
prompt_overrides: Optional[Union[QueryPromptOverrides, Dict[str, Any]]] = None,
|
888
|
+
additional_folders: Optional[List[str]] = None,
|
832
889
|
schema: Optional[Union[Type[BaseModel], Dict[str, Any]]] = None,
|
833
890
|
) -> CompletionResponse:
|
834
891
|
"""
|
@@ -847,10 +904,12 @@ class AsyncUserScope:
|
|
847
904
|
include_paths: Whether to include relationship paths in the response
|
848
905
|
prompt_overrides: Optional customizations for entity extraction, resolution, and query prompts
|
849
906
|
schema: Optional schema for structured output
|
907
|
+
additional_folders: Optional list of additional folder names to further scope operations
|
850
908
|
|
851
909
|
Returns:
|
852
910
|
CompletionResponse: Generated completion or structured output
|
853
911
|
"""
|
912
|
+
effective_folder = self._merge_folders(additional_folders)
|
854
913
|
payload = self._client._logic._prepare_query_request(
|
855
914
|
query,
|
856
915
|
filters,
|
@@ -863,15 +922,31 @@ class AsyncUserScope:
|
|
863
922
|
hop_depth,
|
864
923
|
include_paths,
|
865
924
|
prompt_overrides,
|
866
|
-
|
867
|
-
self.
|
925
|
+
effective_folder,
|
926
|
+
self._end_user_id,
|
868
927
|
schema,
|
869
928
|
)
|
929
|
+
|
930
|
+
# Add schema to payload if provided
|
931
|
+
if schema:
|
932
|
+
# If schema is a Pydantic model class, we need to serialize it to a schema dict
|
933
|
+
if isinstance(schema, type) and issubclass(schema, BaseModel):
|
934
|
+
payload["schema"] = schema.model_json_schema()
|
935
|
+
else:
|
936
|
+
payload["schema"] = schema
|
937
|
+
|
938
|
+
# Add a hint to the query to return in JSON format
|
939
|
+
payload["query"] = f"{payload['query']}\nReturn the answer in JSON format according to the required schema."
|
940
|
+
|
870
941
|
response = await self._client._request("POST", "query", data=payload)
|
871
942
|
return self._client._logic._parse_completion_response(response)
|
872
943
|
|
873
944
|
async def list_documents(
|
874
|
-
self,
|
945
|
+
self,
|
946
|
+
skip: int = 0,
|
947
|
+
limit: int = 100,
|
948
|
+
filters: Optional[Dict[str, Any]] = None,
|
949
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
875
950
|
) -> List[Document]:
|
876
951
|
"""
|
877
952
|
List accessible documents for this end user.
|
@@ -880,12 +955,13 @@ class AsyncUserScope:
|
|
880
955
|
skip: Number of documents to skip
|
881
956
|
limit: Maximum number of documents to return
|
882
957
|
filters: Optional filters
|
958
|
+
folder_name: Optional folder name (or list of names) to scope the request
|
883
959
|
|
884
960
|
Returns:
|
885
961
|
List[Document]: List of documents
|
886
962
|
"""
|
887
963
|
params, data = self._client._logic._prepare_list_documents_request(
|
888
|
-
skip, limit, filters,
|
964
|
+
skip, limit, filters, folder_name, self._end_user_id
|
889
965
|
)
|
890
966
|
response = await self._client._request("POST", "documents", data=data, params=params)
|
891
967
|
docs = self._client._logic._parse_document_list_response(response)
|
@@ -893,12 +969,15 @@ class AsyncUserScope:
|
|
893
969
|
doc._client = self._client
|
894
970
|
return docs
|
895
971
|
|
896
|
-
async def batch_get_documents(
|
972
|
+
async def batch_get_documents(
|
973
|
+
self, document_ids: List[str], folder_name: Optional[Union[str, List[str]]] = None
|
974
|
+
) -> List[Document]:
|
897
975
|
"""
|
898
976
|
Retrieve multiple documents by their IDs in a single batch operation for this end user.
|
899
977
|
|
900
978
|
Args:
|
901
979
|
document_ids: List of document IDs to retrieve
|
980
|
+
folder_name: Optional folder name (or list of names) to scope the request
|
902
981
|
|
903
982
|
Returns:
|
904
983
|
List[Document]: List of document metadata for found documents
|
@@ -915,12 +994,17 @@ class AsyncUserScope:
|
|
915
994
|
doc._client = self._client
|
916
995
|
return docs
|
917
996
|
|
918
|
-
async def batch_get_chunks(
|
997
|
+
async def batch_get_chunks(
|
998
|
+
self,
|
999
|
+
sources: List[Union[ChunkSource, Dict[str, Any]]],
|
1000
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
1001
|
+
) -> List[FinalChunkResult]:
|
919
1002
|
"""
|
920
1003
|
Retrieve specific chunks by their document ID and chunk number in a single batch operation for this end user.
|
921
1004
|
|
922
1005
|
Args:
|
923
1006
|
sources: List of ChunkSource objects or dictionaries with document_id and chunk_number
|
1007
|
+
folder_name: Optional folder name (or list of names) to scope the request
|
924
1008
|
|
925
1009
|
Returns:
|
926
1010
|
List[FinalChunkResult]: List of chunk results
|
@@ -952,7 +1036,9 @@ class AsyncUserScope:
|
|
952
1036
|
name, filters, documents, prompt_overrides, self._folder_name, self._end_user_id
|
953
1037
|
)
|
954
1038
|
response = await self._client._request("POST", "graph/create", data=request)
|
955
|
-
|
1039
|
+
graph = self._logic._parse_graph_response(response)
|
1040
|
+
graph._client = self
|
1041
|
+
return graph
|
956
1042
|
|
957
1043
|
async def update_graph(
|
958
1044
|
self,
|
@@ -982,7 +1068,9 @@ class AsyncUserScope:
|
|
982
1068
|
self._end_user_id,
|
983
1069
|
)
|
984
1070
|
response = await self._client._request("POST", f"graph/{name}/update", data=request)
|
985
|
-
|
1071
|
+
graph = self._logic._parse_graph_response(response)
|
1072
|
+
graph._client = self
|
1073
|
+
return graph
|
986
1074
|
|
987
1075
|
async def delete_document_by_filename(self, filename: str) -> Dict[str, str]:
|
988
1076
|
"""
|
@@ -1377,6 +1465,7 @@ class AsyncMorphik:
|
|
1377
1465
|
k: int = 4,
|
1378
1466
|
min_score: float = 0.0,
|
1379
1467
|
use_colpali: bool = True,
|
1468
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
1380
1469
|
) -> List[FinalChunkResult]:
|
1381
1470
|
"""
|
1382
1471
|
Search for relevant chunks.
|
@@ -1399,7 +1488,10 @@ class AsyncMorphik:
|
|
1399
1488
|
)
|
1400
1489
|
```
|
1401
1490
|
"""
|
1402
|
-
|
1491
|
+
effective_folder = folder_name if folder_name is not None else None
|
1492
|
+
payload = self._logic._prepare_retrieve_chunks_request(
|
1493
|
+
query, filters, k, min_score, use_colpali, effective_folder, None
|
1494
|
+
)
|
1403
1495
|
response = await self._request("POST", "retrieve/chunks", data=payload)
|
1404
1496
|
return self._logic._parse_chunk_result_list_response(response)
|
1405
1497
|
|
@@ -1410,6 +1502,7 @@ class AsyncMorphik:
|
|
1410
1502
|
k: int = 4,
|
1411
1503
|
min_score: float = 0.0,
|
1412
1504
|
use_colpali: bool = True,
|
1505
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
1413
1506
|
) -> List[DocumentResult]:
|
1414
1507
|
"""
|
1415
1508
|
Retrieve relevant documents.
|
@@ -1432,7 +1525,10 @@ class AsyncMorphik:
|
|
1432
1525
|
)
|
1433
1526
|
```
|
1434
1527
|
"""
|
1435
|
-
|
1528
|
+
effective_folder = folder_name if folder_name is not None else None
|
1529
|
+
payload = self._logic._prepare_retrieve_docs_request(
|
1530
|
+
query, filters, k, min_score, use_colpali, effective_folder, None
|
1531
|
+
)
|
1436
1532
|
response = await self._request("POST", "retrieve/docs", data=payload)
|
1437
1533
|
return self._logic._parse_document_result_list_response(response)
|
1438
1534
|
|
@@ -1449,6 +1545,7 @@ class AsyncMorphik:
|
|
1449
1545
|
hop_depth: int = 1,
|
1450
1546
|
include_paths: bool = False,
|
1451
1547
|
prompt_overrides: Optional[Union[QueryPromptOverrides, Dict[str, Any]]] = None,
|
1548
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
1452
1549
|
schema: Optional[Union[Type[BaseModel], Dict[str, Any]]] = None,
|
1453
1550
|
) -> CompletionResponse:
|
1454
1551
|
"""
|
@@ -1539,6 +1636,7 @@ class AsyncMorphik:
|
|
1539
1636
|
print(f"- {evidence}")
|
1540
1637
|
```
|
1541
1638
|
"""
|
1639
|
+
effective_folder = folder_name if folder_name is not None else None
|
1542
1640
|
payload = self._logic._prepare_query_request(
|
1543
1641
|
query,
|
1544
1642
|
filters,
|
@@ -1551,7 +1649,7 @@ class AsyncMorphik:
|
|
1551
1649
|
hop_depth,
|
1552
1650
|
include_paths,
|
1553
1651
|
prompt_overrides,
|
1554
|
-
|
1652
|
+
effective_folder,
|
1555
1653
|
None,
|
1556
1654
|
schema,
|
1557
1655
|
)
|
@@ -1571,7 +1669,11 @@ class AsyncMorphik:
|
|
1571
1669
|
return self._logic._parse_completion_response(response)
|
1572
1670
|
|
1573
1671
|
async def list_documents(
|
1574
|
-
self,
|
1672
|
+
self,
|
1673
|
+
skip: int = 0,
|
1674
|
+
limit: int = 100,
|
1675
|
+
filters: Optional[Dict[str, Any]] = None,
|
1676
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
1575
1677
|
) -> List[Document]:
|
1576
1678
|
"""
|
1577
1679
|
List accessible documents.
|
@@ -1580,6 +1682,7 @@ class AsyncMorphik:
|
|
1580
1682
|
skip: Number of documents to skip
|
1581
1683
|
limit: Maximum number of documents to return
|
1582
1684
|
filters: Optional filters
|
1685
|
+
folder_name: Optional folder name (or list of names) to scope the request
|
1583
1686
|
|
1584
1687
|
Returns:
|
1585
1688
|
List[Document]: List of accessible documents
|
@@ -1593,7 +1696,7 @@ class AsyncMorphik:
|
|
1593
1696
|
next_page = await db.list_documents(skip=10, limit=10, filters={"department": "research"})
|
1594
1697
|
```
|
1595
1698
|
"""
|
1596
|
-
params, data = self._logic._prepare_list_documents_request(skip, limit, filters,
|
1699
|
+
params, data = self._logic._prepare_list_documents_request(skip, limit, filters, folder_name, None)
|
1597
1700
|
response = await self._request("POST", "documents", data=data, params=params)
|
1598
1701
|
docs = self._logic._parse_document_list_response(response)
|
1599
1702
|
for doc in docs:
|
@@ -2047,12 +2150,15 @@ class AsyncMorphik:
|
|
2047
2150
|
|
2048
2151
|
return result
|
2049
2152
|
|
2050
|
-
async def batch_get_documents(
|
2153
|
+
async def batch_get_documents(
|
2154
|
+
self, document_ids: List[str], folder_name: Optional[Union[str, List[str]]] = None
|
2155
|
+
) -> List[Document]:
|
2051
2156
|
"""
|
2052
2157
|
Retrieve multiple documents by their IDs in a single batch operation.
|
2053
2158
|
|
2054
2159
|
Args:
|
2055
2160
|
document_ids: List of document IDs to retrieve
|
2161
|
+
folder_name: Optional folder name (or list of names) to scope the request
|
2056
2162
|
|
2057
2163
|
Returns:
|
2058
2164
|
List[Document]: List of document metadata for found documents
|
@@ -2066,18 +2172,25 @@ class AsyncMorphik:
|
|
2066
2172
|
"""
|
2067
2173
|
# API expects a dict with document_ids key, not a direct list
|
2068
2174
|
request = {"document_ids": document_ids}
|
2175
|
+
if folder_name:
|
2176
|
+
request["folder_name"] = folder_name
|
2069
2177
|
response = await self._request("POST", "batch/documents", data=request)
|
2070
2178
|
docs = self._logic._parse_document_list_response(response)
|
2071
2179
|
for doc in docs:
|
2072
2180
|
doc._client = self
|
2073
2181
|
return docs
|
2074
2182
|
|
2075
|
-
async def batch_get_chunks(
|
2183
|
+
async def batch_get_chunks(
|
2184
|
+
self,
|
2185
|
+
sources: List[Union[ChunkSource, Dict[str, Any]]],
|
2186
|
+
folder_name: Optional[Union[str, List[str]]] = None,
|
2187
|
+
) -> List[FinalChunkResult]:
|
2076
2188
|
"""
|
2077
2189
|
Retrieve specific chunks by their document ID and chunk number in a single batch operation.
|
2078
2190
|
|
2079
2191
|
Args:
|
2080
2192
|
sources: List of ChunkSource objects or dictionaries with document_id and chunk_number
|
2193
|
+
folder_name: Optional folder name (or list of names) to scope the request
|
2081
2194
|
|
2082
2195
|
Returns:
|
2083
2196
|
List[FinalChunkResult]: List of chunk results
|
@@ -2102,7 +2215,7 @@ class AsyncMorphik:
|
|
2102
2215
|
print(f"Chunk from {chunk.document_id}, number {chunk.chunk_number}: {chunk.content[:50]}...")
|
2103
2216
|
```
|
2104
2217
|
"""
|
2105
|
-
request = self._logic._prepare_batch_get_chunks_request(sources,
|
2218
|
+
request = self._logic._prepare_batch_get_chunks_request(sources, folder_name, None)
|
2106
2219
|
response = await self._request("POST", "batch/chunks", data=request)
|
2107
2220
|
return self._logic._parse_chunk_result_list_response(response)
|
2108
2221
|
|
@@ -2227,7 +2340,9 @@ class AsyncMorphik:
|
|
2227
2340
|
"""
|
2228
2341
|
request = self._logic._prepare_create_graph_request(name, filters, documents, prompt_overrides, None, None)
|
2229
2342
|
response = await self._request("POST", "graph/create", data=request)
|
2230
|
-
|
2343
|
+
graph = self._logic._parse_graph_response(response)
|
2344
|
+
graph._client = self # Attach AsyncMorphik client for polling helpers
|
2345
|
+
return graph
|
2231
2346
|
|
2232
2347
|
async def get_graph(self, name: str) -> Graph:
|
2233
2348
|
"""
|
@@ -2247,7 +2362,9 @@ class AsyncMorphik:
|
|
2247
2362
|
```
|
2248
2363
|
"""
|
2249
2364
|
response = await self._request("GET", f"graph/{name}")
|
2250
|
-
|
2365
|
+
graph = self._logic._parse_graph_response(response)
|
2366
|
+
graph._client = self
|
2367
|
+
return graph
|
2251
2368
|
|
2252
2369
|
async def list_graphs(self) -> List[Graph]:
|
2253
2370
|
"""
|
@@ -2265,7 +2382,10 @@ class AsyncMorphik:
|
|
2265
2382
|
```
|
2266
2383
|
"""
|
2267
2384
|
response = await self._request("GET", "graphs")
|
2268
|
-
|
2385
|
+
graphs = self._logic._parse_graph_list_response(response)
|
2386
|
+
for g in graphs:
|
2387
|
+
g._client = self
|
2388
|
+
return graphs
|
2269
2389
|
|
2270
2390
|
async def update_graph(
|
2271
2391
|
self,
|
@@ -2322,7 +2442,9 @@ class AsyncMorphik:
|
|
2322
2442
|
name, additional_filters, additional_documents, prompt_overrides, None, None
|
2323
2443
|
)
|
2324
2444
|
response = await self._request("POST", f"graph/{name}/update", data=request)
|
2325
|
-
|
2445
|
+
graph = self._logic._parse_graph_response(response)
|
2446
|
+
graph._client = self
|
2447
|
+
return graph
|
2326
2448
|
|
2327
2449
|
async def delete_document(self, document_id: str) -> Dict[str, str]:
|
2328
2450
|
"""
|
@@ -2384,3 +2506,37 @@ class AsyncMorphik:
|
|
2384
2506
|
|
2385
2507
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
2386
2508
|
await self.close()
|
2509
|
+
|
2510
|
+
async def create_app(self, app_id: str, name: str, expiry_days: int = 30) -> Dict[str, str]:
|
2511
|
+
"""Create a new application in Morphik Cloud and obtain its auth URI (async)."""
|
2512
|
+
|
2513
|
+
payload = {"app_id": app_id, "name": name, "expiry_days": expiry_days}
|
2514
|
+
return await self._request("POST", "ee/create_app", data=payload)
|
2515
|
+
|
2516
|
+
async def wait_for_graph_completion(
|
2517
|
+
self,
|
2518
|
+
graph_name: str,
|
2519
|
+
timeout_seconds: int = 300,
|
2520
|
+
check_interval_seconds: int = 5,
|
2521
|
+
) -> Graph:
|
2522
|
+
"""Block until the specified graph finishes processing (async).
|
2523
|
+
|
2524
|
+
Args:
|
2525
|
+
graph_name: Name of the graph to monitor.
|
2526
|
+
timeout_seconds: Maximum seconds to wait.
|
2527
|
+
check_interval_seconds: Seconds between status checks.
|
2528
|
+
|
2529
|
+
Returns:
|
2530
|
+
Graph: The completed graph object.
|
2531
|
+
"""
|
2532
|
+
import asyncio
|
2533
|
+
|
2534
|
+
start = asyncio.get_event_loop().time()
|
2535
|
+
while (asyncio.get_event_loop().time() - start) < timeout_seconds:
|
2536
|
+
graph = await self.get_graph(graph_name)
|
2537
|
+
if graph.is_completed:
|
2538
|
+
return graph
|
2539
|
+
if graph.is_failed:
|
2540
|
+
raise RuntimeError(graph.error or "Graph processing failed")
|
2541
|
+
await asyncio.sleep(check_interval_seconds)
|
2542
|
+
raise TimeoutError("Timed out waiting for graph completion")
|