unique_sdk 0.9.23__tar.gz → 0.9.28__tar.gz
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.
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/CHANGELOG.md +14 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/PKG-INFO +115 -18
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/README.md +99 -17
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/pyproject.toml +3 -1
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_content.py +92 -1
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_search.py +1 -1
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/utils/file_io.py +11 -1
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/LICENSE +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/__init__.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_api_requestor.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_api_resource.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_api_version.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_error.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_http_client.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_list_object.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_object_classes.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_request_options.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_unique_object.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_unique_ql.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_unique_response.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_util.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_version.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/_webhook.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/__init__.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_acronyms.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_chat_completion.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_embedding.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_event.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_integrated.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_message.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_message_assessment.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_search_string.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/api_resources/_short_term_memory.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/utils/chat_history.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/utils/sources.py +0 -0
- {unique_sdk-0.9.23 → unique_sdk-0.9.28}/unique_sdk/utils/token.py +0 -0
|
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.9.28] - 2025-05-20
|
|
9
|
+
- Add function to search content info. This also allows filtering content info by metadata info.
|
|
10
|
+
|
|
11
|
+
## [0.9.27] - 2025-05-14
|
|
12
|
+
- Add the possibility to specify metadata when creating or updating a Content.
|
|
13
|
+
|
|
14
|
+
## [0.9.26] - 2025-05-13
|
|
15
|
+
- Add the possibility to specify ingestionConfig when creating or updating a Content.
|
|
16
|
+
|
|
17
|
+
## [0.9.25] - 2025-05-02
|
|
18
|
+
- Fixed typos in `README.md`, including incorrect `sdk.utils` imports and code example errors.
|
|
19
|
+
|
|
20
|
+
## [0.9.24] - 2025-04-23
|
|
21
|
+
- Make `chatId` property in `Search.CreateParams` optional
|
|
8
22
|
|
|
9
23
|
## [0.9.23] - 2025-03-25
|
|
10
24
|
- Define programming language classifier explicitly for python 3.11
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: unique_sdk
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.28
|
|
4
4
|
Summary:
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Martin Fadler
|
|
@@ -10,6 +10,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
13
14
|
Requires-Dist: typing-extensions (>=4.9.0,<5.0.0)
|
|
14
15
|
Description-Content-Type: text/markdown
|
|
15
16
|
|
|
@@ -282,6 +283,73 @@ unique_sdk.Content.search(
|
|
|
282
283
|
)
|
|
283
284
|
```
|
|
284
285
|
|
|
286
|
+
#### `unique_sdk.Content.get_info`
|
|
287
|
+
|
|
288
|
+
Allows you to get content info. To filter the results you can define a metadata filter in UniqueQL language. Find out more about it in the UniqueQL section. An example of a metadata filter defined with UniqueQL is the following:
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
metadataFilter: {
|
|
292
|
+
"or": [
|
|
293
|
+
{
|
|
294
|
+
"and": [
|
|
295
|
+
{
|
|
296
|
+
"operator": "contains",
|
|
297
|
+
"path": [
|
|
298
|
+
"folderIdPath"
|
|
299
|
+
],
|
|
300
|
+
"value": "uniquepathid://test_id"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"operator": "contains",
|
|
304
|
+
"path": [
|
|
305
|
+
"title"
|
|
306
|
+
],
|
|
307
|
+
"value": "ai"
|
|
308
|
+
}
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
]
|
|
312
|
+
},
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Pagination is also enabled for this functionality, and the default number of returned results is 50 with no entries skipped. Use the following paramteres to get the desired page:`
|
|
316
|
+
|
|
317
|
+
- `skip`
|
|
318
|
+
- `take`
|
|
319
|
+
|
|
320
|
+
Here is an example of retrieving the first 3 content infos that contain the value `uniquepathid://scope_abcdibgznc4bkdcx120zm5d` in the `folderIdPath` metadata and the value `ai` for the `tile` metadata.
|
|
321
|
+
|
|
322
|
+
```python
|
|
323
|
+
content_info_result = unique_sdk.Content.get_info(
|
|
324
|
+
user_id=user_id,
|
|
325
|
+
company_id=company_id,
|
|
326
|
+
metadataFilter={
|
|
327
|
+
"or": [
|
|
328
|
+
{
|
|
329
|
+
"and": [
|
|
330
|
+
{
|
|
331
|
+
"operator": "contains",
|
|
332
|
+
"path": [
|
|
333
|
+
"folderIdPath"
|
|
334
|
+
],
|
|
335
|
+
"value": "uniquepathid://scope_abcdibgznc4bkdcx120zm5d"
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"operator": "contains",
|
|
339
|
+
"path": [
|
|
340
|
+
"title"
|
|
341
|
+
],
|
|
342
|
+
"value": "ai"
|
|
343
|
+
}
|
|
344
|
+
]
|
|
345
|
+
}
|
|
346
|
+
]
|
|
347
|
+
},
|
|
348
|
+
skip=0,
|
|
349
|
+
take=3,
|
|
350
|
+
)
|
|
351
|
+
```
|
|
352
|
+
|
|
285
353
|
#### `unique_sdk.Content.upsert`
|
|
286
354
|
|
|
287
355
|
Enables upload of a new Content into the Knowledge base of unique into a specific scope with `scopeId` or a specific `chatId`. One of the two must be set.
|
|
@@ -297,6 +365,14 @@ createdContent = upload_file(
|
|
|
297
365
|
"test.pdf",
|
|
298
366
|
"application/pdf",
|
|
299
367
|
"scope_stcj2osgbl722m22jayidx0n",
|
|
368
|
+
ingestionConfig={
|
|
369
|
+
"chunkMaxTokens": 1000,
|
|
370
|
+
"chunkStrategy": "default",
|
|
371
|
+
"uniqueIngestionMode": "standard",
|
|
372
|
+
},
|
|
373
|
+
metadata={
|
|
374
|
+
"folderIdPath": "uniquepathid://scope_id"
|
|
375
|
+
}
|
|
300
376
|
)
|
|
301
377
|
|
|
302
378
|
def upload_file(
|
|
@@ -306,6 +382,8 @@ def upload_file(
|
|
|
306
382
|
displayed_filename,
|
|
307
383
|
mimeType,
|
|
308
384
|
scope_or_unique_path,
|
|
385
|
+
ingestion_config=None,
|
|
386
|
+
metadata=None,
|
|
309
387
|
):
|
|
310
388
|
size = os.path.getsize(path_to_file)
|
|
311
389
|
createdContent = unique_sdk.Content.upsert(
|
|
@@ -315,6 +393,8 @@ def upload_file(
|
|
|
315
393
|
"key": displayed_filename,
|
|
316
394
|
"title": displayed_filename,
|
|
317
395
|
"mimeType": mimeType,
|
|
396
|
+
"ingestionConfig": ingestionConfig,
|
|
397
|
+
"metadata": metadata,
|
|
318
398
|
},
|
|
319
399
|
scopeId=scope_or_unique_path,
|
|
320
400
|
)
|
|
@@ -340,6 +420,8 @@ def upload_file(
|
|
|
340
420
|
"title": displayed_filename,
|
|
341
421
|
"mimeType": mimeType,
|
|
342
422
|
"byteSize": size,
|
|
423
|
+
"ingestionConfig": ingestionConfig,
|
|
424
|
+
"metadata": metadata,
|
|
343
425
|
},
|
|
344
426
|
scopeId=scope_or_unique_path,
|
|
345
427
|
readUrl=createdContent.readUrl,
|
|
@@ -544,6 +626,7 @@ These are the options are available for `searchType`:
|
|
|
544
626
|
`scopeIds` Specifies a collection of scope IDs to confine the search.
|
|
545
627
|
`language` Optional. The language specification for full text search.
|
|
546
628
|
`reranker` Optional. The reranker service to be used for re-ranking the search results.
|
|
629
|
+
`chatId` Optional, adds the documents uploaded in this chat to the scope of searched documents.
|
|
547
630
|
|
|
548
631
|
```python
|
|
549
632
|
search = unique_sdk.Search.create(
|
|
@@ -715,7 +798,7 @@ A metadata filter such as the one designed above can be used in a `Search.create
|
|
|
715
798
|
|
|
716
799
|
### Chat History
|
|
717
800
|
|
|
718
|
-
#### `unique_sdk.
|
|
801
|
+
#### `unique_sdk.utils.chat_history.load_history`
|
|
719
802
|
|
|
720
803
|
A helper function that makes sure the chat history is fully loaded and cut to the size of the token window that it fits into the next round of chat interactions.
|
|
721
804
|
|
|
@@ -733,7 +816,7 @@ history = unique_sdk.utils.chat_history.load_history(
|
|
|
733
816
|
)
|
|
734
817
|
```
|
|
735
818
|
|
|
736
|
-
#### `unique_sdk.
|
|
819
|
+
#### `unique_sdk.utils.chat_history.convert_chat_history_to_injectable_string`
|
|
737
820
|
|
|
738
821
|
convert history into a string that can be injected into a prompt. it als returns the token length of the converted history.
|
|
739
822
|
|
|
@@ -747,7 +830,7 @@ chat_history-string, chat_context_token_length = unique_sdk.utils.chat_history.c
|
|
|
747
830
|
|
|
748
831
|
Interacting with the knowledge-base.
|
|
749
832
|
|
|
750
|
-
#### `unique_sdk.
|
|
833
|
+
#### `unique_sdk.utils.file_io.download_content`
|
|
751
834
|
|
|
752
835
|
download files and save them into a folder in `/tmp`
|
|
753
836
|
|
|
@@ -763,7 +846,7 @@ pdfFile = download_content(
|
|
|
763
846
|
}
|
|
764
847
|
```
|
|
765
848
|
|
|
766
|
-
#### `unique_sdk.
|
|
849
|
+
#### `unique_sdk.utils.file_io.upload_file`
|
|
767
850
|
|
|
768
851
|
Allows for uploading files that then get ingested in a scope or a chat.
|
|
769
852
|
|
|
@@ -773,15 +856,15 @@ createdContent = upload_file(
|
|
|
773
856
|
userId=userId,
|
|
774
857
|
path_to_file="/tmp/hello.pdf",
|
|
775
858
|
displayed_filename="hello.pdf",
|
|
776
|
-
|
|
777
|
-
|
|
859
|
+
mime_type="application/pdf",
|
|
860
|
+
scope_or_unique_path="scope_stcj2osgbl722m22jayidx0n",
|
|
778
861
|
chat_id=None,
|
|
779
862
|
)
|
|
780
863
|
```
|
|
781
864
|
|
|
782
865
|
### Sources
|
|
783
866
|
|
|
784
|
-
#### `unique_sdk.
|
|
867
|
+
#### `unique_sdk.utils.sources.merge_sources`
|
|
785
868
|
|
|
786
869
|
Merges multiple search results based on their 'id', removing redundant document and info markers.
|
|
787
870
|
|
|
@@ -810,15 +893,15 @@ search = unique_sdk.Search.create(
|
|
|
810
893
|
chatOnly=False,
|
|
811
894
|
)
|
|
812
895
|
|
|
813
|
-
searchContext = unique_sdk.
|
|
896
|
+
searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
|
|
814
897
|
search["data"], config["maxTokens"] - historyLength
|
|
815
898
|
)
|
|
816
899
|
|
|
817
|
-
searchContext = unique_sdk.
|
|
900
|
+
searchContext = unique_sdk.utils.sources.merge_sources(search)
|
|
818
901
|
|
|
819
902
|
```
|
|
820
903
|
|
|
821
|
-
#### `unique_sdk.
|
|
904
|
+
#### `unique_sdk.utils.sources.sort_sources`
|
|
822
905
|
|
|
823
906
|
Sort sources by order of appearance in documents
|
|
824
907
|
|
|
@@ -835,14 +918,14 @@ search = unique_sdk.Search.create(
|
|
|
835
918
|
chatOnly=False,
|
|
836
919
|
)
|
|
837
920
|
|
|
838
|
-
searchContext = unique_sdk.
|
|
921
|
+
searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
|
|
839
922
|
search["data"], config["maxTokens"] - historyLength
|
|
840
923
|
)
|
|
841
924
|
|
|
842
|
-
searchContext = unique_sdk.
|
|
925
|
+
searchContext = unique_sdk.utils.sources.sort_sources(search)
|
|
843
926
|
```
|
|
844
927
|
|
|
845
|
-
#### `unique_sdk.
|
|
928
|
+
#### `unique_sdk.utils.sources.post_process_sources`
|
|
846
929
|
|
|
847
930
|
Post-processes the provided text by converting source references into superscript numerals (required
|
|
848
931
|
format by backend to display sources in the chat window)
|
|
@@ -869,7 +952,7 @@ text_with_sup = post_process_sources(text)
|
|
|
869
952
|
|
|
870
953
|
### Token
|
|
871
954
|
|
|
872
|
-
#### unique_sdk.
|
|
955
|
+
#### unique_sdk.utils.token.pick_search_results_for_token_window
|
|
873
956
|
|
|
874
957
|
Selects and returns a list of search results that fit within a specified token limit.
|
|
875
958
|
|
|
@@ -898,12 +981,12 @@ search = unique_sdk.Search.create(
|
|
|
898
981
|
chatOnly=False,
|
|
899
982
|
)
|
|
900
983
|
|
|
901
|
-
searchContext = unique_sdk.
|
|
984
|
+
searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
|
|
902
985
|
search["data"], config["maxTokens"] - historyLength
|
|
903
986
|
)
|
|
904
987
|
```
|
|
905
988
|
|
|
906
|
-
#### unique_sdk.
|
|
989
|
+
#### unique_sdk.utils.token.count_tokens
|
|
907
990
|
|
|
908
991
|
Counts the number of tokens in the provided text.
|
|
909
992
|
|
|
@@ -920,7 +1003,7 @@ Returns:
|
|
|
920
1003
|
|
|
921
1004
|
```python
|
|
922
1005
|
hello = "hello you!"
|
|
923
|
-
searchContext = unique_sdk.
|
|
1006
|
+
searchContext = unique_sdk.utils.token.count_tokens(hello)
|
|
924
1007
|
```
|
|
925
1008
|
|
|
926
1009
|
## Error Handling
|
|
@@ -940,6 +1023,20 @@ All notable changes to this project will be documented in this file.
|
|
|
940
1023
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
941
1024
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
942
1025
|
|
|
1026
|
+
## [0.9.28] - 2025-05-20
|
|
1027
|
+
- Add function to search content info. This also allows filtering content info by metadata info.
|
|
1028
|
+
|
|
1029
|
+
## [0.9.27] - 2025-05-14
|
|
1030
|
+
- Add the possibility to specify metadata when creating or updating a Content.
|
|
1031
|
+
|
|
1032
|
+
## [0.9.26] - 2025-05-13
|
|
1033
|
+
- Add the possibility to specify ingestionConfig when creating or updating a Content.
|
|
1034
|
+
|
|
1035
|
+
## [0.9.25] - 2025-05-02
|
|
1036
|
+
- Fixed typos in `README.md`, including incorrect `sdk.utils` imports and code example errors.
|
|
1037
|
+
|
|
1038
|
+
## [0.9.24] - 2025-04-23
|
|
1039
|
+
- Make `chatId` property in `Search.CreateParams` optional
|
|
943
1040
|
|
|
944
1041
|
## [0.9.23] - 2025-03-25
|
|
945
1042
|
- Define programming language classifier explicitly for python 3.11
|
|
@@ -267,6 +267,73 @@ unique_sdk.Content.search(
|
|
|
267
267
|
)
|
|
268
268
|
```
|
|
269
269
|
|
|
270
|
+
#### `unique_sdk.Content.get_info`
|
|
271
|
+
|
|
272
|
+
Allows you to get content info. To filter the results you can define a metadata filter in UniqueQL language. Find out more about it in the UniqueQL section. An example of a metadata filter defined with UniqueQL is the following:
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
metadataFilter: {
|
|
276
|
+
"or": [
|
|
277
|
+
{
|
|
278
|
+
"and": [
|
|
279
|
+
{
|
|
280
|
+
"operator": "contains",
|
|
281
|
+
"path": [
|
|
282
|
+
"folderIdPath"
|
|
283
|
+
],
|
|
284
|
+
"value": "uniquepathid://test_id"
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"operator": "contains",
|
|
288
|
+
"path": [
|
|
289
|
+
"title"
|
|
290
|
+
],
|
|
291
|
+
"value": "ai"
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
},
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Pagination is also enabled for this functionality, and the default number of returned results is 50 with no entries skipped. Use the following paramteres to get the desired page:`
|
|
300
|
+
|
|
301
|
+
- `skip`
|
|
302
|
+
- `take`
|
|
303
|
+
|
|
304
|
+
Here is an example of retrieving the first 3 content infos that contain the value `uniquepathid://scope_abcdibgznc4bkdcx120zm5d` in the `folderIdPath` metadata and the value `ai` for the `tile` metadata.
|
|
305
|
+
|
|
306
|
+
```python
|
|
307
|
+
content_info_result = unique_sdk.Content.get_info(
|
|
308
|
+
user_id=user_id,
|
|
309
|
+
company_id=company_id,
|
|
310
|
+
metadataFilter={
|
|
311
|
+
"or": [
|
|
312
|
+
{
|
|
313
|
+
"and": [
|
|
314
|
+
{
|
|
315
|
+
"operator": "contains",
|
|
316
|
+
"path": [
|
|
317
|
+
"folderIdPath"
|
|
318
|
+
],
|
|
319
|
+
"value": "uniquepathid://scope_abcdibgznc4bkdcx120zm5d"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
"operator": "contains",
|
|
323
|
+
"path": [
|
|
324
|
+
"title"
|
|
325
|
+
],
|
|
326
|
+
"value": "ai"
|
|
327
|
+
}
|
|
328
|
+
]
|
|
329
|
+
}
|
|
330
|
+
]
|
|
331
|
+
},
|
|
332
|
+
skip=0,
|
|
333
|
+
take=3,
|
|
334
|
+
)
|
|
335
|
+
```
|
|
336
|
+
|
|
270
337
|
#### `unique_sdk.Content.upsert`
|
|
271
338
|
|
|
272
339
|
Enables upload of a new Content into the Knowledge base of unique into a specific scope with `scopeId` or a specific `chatId`. One of the two must be set.
|
|
@@ -282,6 +349,14 @@ createdContent = upload_file(
|
|
|
282
349
|
"test.pdf",
|
|
283
350
|
"application/pdf",
|
|
284
351
|
"scope_stcj2osgbl722m22jayidx0n",
|
|
352
|
+
ingestionConfig={
|
|
353
|
+
"chunkMaxTokens": 1000,
|
|
354
|
+
"chunkStrategy": "default",
|
|
355
|
+
"uniqueIngestionMode": "standard",
|
|
356
|
+
},
|
|
357
|
+
metadata={
|
|
358
|
+
"folderIdPath": "uniquepathid://scope_id"
|
|
359
|
+
}
|
|
285
360
|
)
|
|
286
361
|
|
|
287
362
|
def upload_file(
|
|
@@ -291,6 +366,8 @@ def upload_file(
|
|
|
291
366
|
displayed_filename,
|
|
292
367
|
mimeType,
|
|
293
368
|
scope_or_unique_path,
|
|
369
|
+
ingestion_config=None,
|
|
370
|
+
metadata=None,
|
|
294
371
|
):
|
|
295
372
|
size = os.path.getsize(path_to_file)
|
|
296
373
|
createdContent = unique_sdk.Content.upsert(
|
|
@@ -300,6 +377,8 @@ def upload_file(
|
|
|
300
377
|
"key": displayed_filename,
|
|
301
378
|
"title": displayed_filename,
|
|
302
379
|
"mimeType": mimeType,
|
|
380
|
+
"ingestionConfig": ingestionConfig,
|
|
381
|
+
"metadata": metadata,
|
|
303
382
|
},
|
|
304
383
|
scopeId=scope_or_unique_path,
|
|
305
384
|
)
|
|
@@ -325,6 +404,8 @@ def upload_file(
|
|
|
325
404
|
"title": displayed_filename,
|
|
326
405
|
"mimeType": mimeType,
|
|
327
406
|
"byteSize": size,
|
|
407
|
+
"ingestionConfig": ingestionConfig,
|
|
408
|
+
"metadata": metadata,
|
|
328
409
|
},
|
|
329
410
|
scopeId=scope_or_unique_path,
|
|
330
411
|
readUrl=createdContent.readUrl,
|
|
@@ -529,6 +610,7 @@ These are the options are available for `searchType`:
|
|
|
529
610
|
`scopeIds` Specifies a collection of scope IDs to confine the search.
|
|
530
611
|
`language` Optional. The language specification for full text search.
|
|
531
612
|
`reranker` Optional. The reranker service to be used for re-ranking the search results.
|
|
613
|
+
`chatId` Optional, adds the documents uploaded in this chat to the scope of searched documents.
|
|
532
614
|
|
|
533
615
|
```python
|
|
534
616
|
search = unique_sdk.Search.create(
|
|
@@ -700,7 +782,7 @@ A metadata filter such as the one designed above can be used in a `Search.create
|
|
|
700
782
|
|
|
701
783
|
### Chat History
|
|
702
784
|
|
|
703
|
-
#### `unique_sdk.
|
|
785
|
+
#### `unique_sdk.utils.chat_history.load_history`
|
|
704
786
|
|
|
705
787
|
A helper function that makes sure the chat history is fully loaded and cut to the size of the token window that it fits into the next round of chat interactions.
|
|
706
788
|
|
|
@@ -718,7 +800,7 @@ history = unique_sdk.utils.chat_history.load_history(
|
|
|
718
800
|
)
|
|
719
801
|
```
|
|
720
802
|
|
|
721
|
-
#### `unique_sdk.
|
|
803
|
+
#### `unique_sdk.utils.chat_history.convert_chat_history_to_injectable_string`
|
|
722
804
|
|
|
723
805
|
convert history into a string that can be injected into a prompt. it als returns the token length of the converted history.
|
|
724
806
|
|
|
@@ -732,7 +814,7 @@ chat_history-string, chat_context_token_length = unique_sdk.utils.chat_history.c
|
|
|
732
814
|
|
|
733
815
|
Interacting with the knowledge-base.
|
|
734
816
|
|
|
735
|
-
#### `unique_sdk.
|
|
817
|
+
#### `unique_sdk.utils.file_io.download_content`
|
|
736
818
|
|
|
737
819
|
download files and save them into a folder in `/tmp`
|
|
738
820
|
|
|
@@ -748,7 +830,7 @@ pdfFile = download_content(
|
|
|
748
830
|
}
|
|
749
831
|
```
|
|
750
832
|
|
|
751
|
-
#### `unique_sdk.
|
|
833
|
+
#### `unique_sdk.utils.file_io.upload_file`
|
|
752
834
|
|
|
753
835
|
Allows for uploading files that then get ingested in a scope or a chat.
|
|
754
836
|
|
|
@@ -758,15 +840,15 @@ createdContent = upload_file(
|
|
|
758
840
|
userId=userId,
|
|
759
841
|
path_to_file="/tmp/hello.pdf",
|
|
760
842
|
displayed_filename="hello.pdf",
|
|
761
|
-
|
|
762
|
-
|
|
843
|
+
mime_type="application/pdf",
|
|
844
|
+
scope_or_unique_path="scope_stcj2osgbl722m22jayidx0n",
|
|
763
845
|
chat_id=None,
|
|
764
846
|
)
|
|
765
847
|
```
|
|
766
848
|
|
|
767
849
|
### Sources
|
|
768
850
|
|
|
769
|
-
#### `unique_sdk.
|
|
851
|
+
#### `unique_sdk.utils.sources.merge_sources`
|
|
770
852
|
|
|
771
853
|
Merges multiple search results based on their 'id', removing redundant document and info markers.
|
|
772
854
|
|
|
@@ -795,15 +877,15 @@ search = unique_sdk.Search.create(
|
|
|
795
877
|
chatOnly=False,
|
|
796
878
|
)
|
|
797
879
|
|
|
798
|
-
searchContext = unique_sdk.
|
|
880
|
+
searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
|
|
799
881
|
search["data"], config["maxTokens"] - historyLength
|
|
800
882
|
)
|
|
801
883
|
|
|
802
|
-
searchContext = unique_sdk.
|
|
884
|
+
searchContext = unique_sdk.utils.sources.merge_sources(search)
|
|
803
885
|
|
|
804
886
|
```
|
|
805
887
|
|
|
806
|
-
#### `unique_sdk.
|
|
888
|
+
#### `unique_sdk.utils.sources.sort_sources`
|
|
807
889
|
|
|
808
890
|
Sort sources by order of appearance in documents
|
|
809
891
|
|
|
@@ -820,14 +902,14 @@ search = unique_sdk.Search.create(
|
|
|
820
902
|
chatOnly=False,
|
|
821
903
|
)
|
|
822
904
|
|
|
823
|
-
searchContext = unique_sdk.
|
|
905
|
+
searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
|
|
824
906
|
search["data"], config["maxTokens"] - historyLength
|
|
825
907
|
)
|
|
826
908
|
|
|
827
|
-
searchContext = unique_sdk.
|
|
909
|
+
searchContext = unique_sdk.utils.sources.sort_sources(search)
|
|
828
910
|
```
|
|
829
911
|
|
|
830
|
-
#### `unique_sdk.
|
|
912
|
+
#### `unique_sdk.utils.sources.post_process_sources`
|
|
831
913
|
|
|
832
914
|
Post-processes the provided text by converting source references into superscript numerals (required
|
|
833
915
|
format by backend to display sources in the chat window)
|
|
@@ -854,7 +936,7 @@ text_with_sup = post_process_sources(text)
|
|
|
854
936
|
|
|
855
937
|
### Token
|
|
856
938
|
|
|
857
|
-
#### unique_sdk.
|
|
939
|
+
#### unique_sdk.utils.token.pick_search_results_for_token_window
|
|
858
940
|
|
|
859
941
|
Selects and returns a list of search results that fit within a specified token limit.
|
|
860
942
|
|
|
@@ -883,12 +965,12 @@ search = unique_sdk.Search.create(
|
|
|
883
965
|
chatOnly=False,
|
|
884
966
|
)
|
|
885
967
|
|
|
886
|
-
searchContext = unique_sdk.
|
|
968
|
+
searchContext = unique_sdk.utils.token.pick_search_results_for_token_window(
|
|
887
969
|
search["data"], config["maxTokens"] - historyLength
|
|
888
970
|
)
|
|
889
971
|
```
|
|
890
972
|
|
|
891
|
-
#### unique_sdk.
|
|
973
|
+
#### unique_sdk.utils.token.count_tokens
|
|
892
974
|
|
|
893
975
|
Counts the number of tokens in the provided text.
|
|
894
976
|
|
|
@@ -905,7 +987,7 @@ Returns:
|
|
|
905
987
|
|
|
906
988
|
```python
|
|
907
989
|
hello = "hello you!"
|
|
908
|
-
searchContext = unique_sdk.
|
|
990
|
+
searchContext = unique_sdk.utils.token.count_tokens(hello)
|
|
909
991
|
```
|
|
910
992
|
|
|
911
993
|
## Error Handling
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "unique_sdk"
|
|
3
|
-
version = "0.9.
|
|
3
|
+
version = "0.9.28"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = [
|
|
6
6
|
"Martin Fadler <martin.fadler@unique.ch>",
|
|
@@ -16,6 +16,7 @@ classifiers = [
|
|
|
16
16
|
[tool.poetry.dependencies]
|
|
17
17
|
python = "^3.11"
|
|
18
18
|
typing-extensions = "^4.9.0"
|
|
19
|
+
requests = "^2.32.3"
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
[tool.poetry.group.dev.dependencies]
|
|
@@ -25,6 +26,7 @@ tox = "^4.11.4"
|
|
|
25
26
|
pyright = "^1.1.341"
|
|
26
27
|
pytest-cov = "^4.1.0"
|
|
27
28
|
pytest-asyncio = "^0.24.0"
|
|
29
|
+
python-dotenv = "^1.1.0"
|
|
28
30
|
|
|
29
31
|
[build-system]
|
|
30
32
|
requires = ["poetry-core"]
|
|
@@ -65,8 +65,38 @@ class Content(APIResource["Content"]):
|
|
|
65
65
|
where: "Content.ContentWhereInput"
|
|
66
66
|
chatId: NotRequired[str]
|
|
67
67
|
|
|
68
|
-
class
|
|
68
|
+
class ContentInfoParams(TypedDict):
|
|
69
|
+
"""
|
|
70
|
+
Parameters for the content info endpoint.
|
|
71
|
+
This is used to retrieve information about content based on various filters.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
metadataFilter: dict
|
|
75
|
+
skip: int | None
|
|
76
|
+
take: int | None
|
|
77
|
+
|
|
78
|
+
class CustomApiOptions(TypedDict):
|
|
79
|
+
apiIdentifier: str
|
|
80
|
+
apiPayload: Optional[str]
|
|
81
|
+
customisationType: str
|
|
82
|
+
|
|
83
|
+
class VttConfig(TypedDict, total=False):
|
|
84
|
+
languageModel: Optional[str]
|
|
85
|
+
|
|
86
|
+
class IngestionConfig(TypedDict, total=False):
|
|
87
|
+
chunkMaxTokens: Optional[int]
|
|
88
|
+
chunkMaxTokensOnePager: Optional[int]
|
|
89
|
+
chunkMinTokens: Optional[int]
|
|
90
|
+
chunkStrategy: Optional[str]
|
|
91
|
+
customApiOptions: Optional[List["Content.CustomApiOptions"]]
|
|
92
|
+
documentMinTokens: Optional[int]
|
|
93
|
+
excelReadMode: Optional[str]
|
|
94
|
+
jpgReadMode: Optional[str]
|
|
95
|
+
pdfReadMode: Optional[str]
|
|
96
|
+
pptReadMode: Optional[str]
|
|
69
97
|
uniqueIngestionMode: str
|
|
98
|
+
vttConfig: Optional["Content.VttConfig"]
|
|
99
|
+
wordReadMode: Optional[str]
|
|
70
100
|
|
|
71
101
|
class Input(TypedDict):
|
|
72
102
|
key: str
|
|
@@ -76,6 +106,7 @@ class Content(APIResource["Content"]):
|
|
|
76
106
|
ownerId: str
|
|
77
107
|
byteSize: Optional[int]
|
|
78
108
|
ingestionConfig: "Content.IngestionConfig"
|
|
109
|
+
metadata: dict[str, any] | None = None
|
|
79
110
|
|
|
80
111
|
class UpsertParams(RequestOptions):
|
|
81
112
|
input: "Content.Input"
|
|
@@ -92,6 +123,30 @@ class Content(APIResource["Content"]):
|
|
|
92
123
|
endPage: Optional[int]
|
|
93
124
|
order: Optional[int]
|
|
94
125
|
|
|
126
|
+
class ContentInfo(TypedDict):
|
|
127
|
+
"""
|
|
128
|
+
Partial representation of the content containing only the base information.
|
|
129
|
+
This is used for the content info endpoint.
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
id: str
|
|
133
|
+
key: str
|
|
134
|
+
url: str | None
|
|
135
|
+
title: str | None
|
|
136
|
+
metadata: Dict[str, Any] | None
|
|
137
|
+
mimeType: str
|
|
138
|
+
byteSize: int
|
|
139
|
+
ownerId: str
|
|
140
|
+
createdAt: str
|
|
141
|
+
updatedAt: str
|
|
142
|
+
expiresAt: str | None
|
|
143
|
+
deletedAt: str | None
|
|
144
|
+
expiredAt: str | None
|
|
145
|
+
|
|
146
|
+
class PaginatedContentInfo(TypedDict):
|
|
147
|
+
contentInfo: List["Content.ContentInfo"]
|
|
148
|
+
totalCount: int
|
|
149
|
+
|
|
95
150
|
id: str
|
|
96
151
|
key: str
|
|
97
152
|
url: Optional[str]
|
|
@@ -136,6 +191,42 @@ class Content(APIResource["Content"]):
|
|
|
136
191
|
),
|
|
137
192
|
)
|
|
138
193
|
|
|
194
|
+
@classmethod
|
|
195
|
+
def get_info(
|
|
196
|
+
cls,
|
|
197
|
+
user_id: str,
|
|
198
|
+
company_id: str,
|
|
199
|
+
**params: Unpack["Content.ContentInfoParams"],
|
|
200
|
+
) -> PaginatedContentInfo:
|
|
201
|
+
return cast(
|
|
202
|
+
Content.PaginatedContentInfo,
|
|
203
|
+
cls._static_request(
|
|
204
|
+
"post",
|
|
205
|
+
"/content/info",
|
|
206
|
+
user_id,
|
|
207
|
+
company_id,
|
|
208
|
+
params=params,
|
|
209
|
+
),
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
@classmethod
|
|
213
|
+
async def get_info_async(
|
|
214
|
+
cls,
|
|
215
|
+
user_id: str,
|
|
216
|
+
company_id: str,
|
|
217
|
+
**params: Unpack["Content.ContentInfoParams"],
|
|
218
|
+
) -> PaginatedContentInfo:
|
|
219
|
+
return cast(
|
|
220
|
+
Content.PaginatedContentInfo,
|
|
221
|
+
await cls._static_request_async(
|
|
222
|
+
"post",
|
|
223
|
+
"/content/info",
|
|
224
|
+
user_id,
|
|
225
|
+
company_id,
|
|
226
|
+
params=params,
|
|
227
|
+
),
|
|
228
|
+
)
|
|
229
|
+
|
|
139
230
|
@classmethod
|
|
140
231
|
def upsert(
|
|
141
232
|
cls,
|
|
@@ -8,7 +8,7 @@ class Search(APIResource["Search"]):
|
|
|
8
8
|
OBJECT_NAME: ClassVar[Literal["search.search"]] = "search.search"
|
|
9
9
|
|
|
10
10
|
class CreateParams(RequestOptions):
|
|
11
|
-
chatId: str
|
|
11
|
+
chatId: NotRequired[Optional[str]]
|
|
12
12
|
searchString: str
|
|
13
13
|
searchType: Literal["VECTOR", "COMBINED"]
|
|
14
14
|
language: NotRequired[Optional[str]]
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import tempfile
|
|
3
3
|
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
4
5
|
|
|
5
6
|
import requests
|
|
6
7
|
|
|
7
8
|
import unique_sdk
|
|
9
|
+
from unique_sdk.api_resources._content import Content
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
# download readUrl a random directory in /tmp
|
|
@@ -38,19 +40,23 @@ def upload_file(
|
|
|
38
40
|
mime_type,
|
|
39
41
|
scope_or_unique_path=None,
|
|
40
42
|
chat_id=None,
|
|
43
|
+
ingestion_config: Optional[Content.IngestionConfig] = None,
|
|
44
|
+
metadata: dict[str, any] | None = None,
|
|
41
45
|
):
|
|
42
46
|
# check that chatid or scope_or_unique_path is provided
|
|
43
47
|
if not chat_id and not scope_or_unique_path:
|
|
44
48
|
raise ValueError("chat_id or scope_or_unique_path must be provided")
|
|
45
49
|
|
|
46
50
|
size = os.path.getsize(path_to_file)
|
|
47
|
-
createdContent =
|
|
51
|
+
createdContent = Content.upsert(
|
|
48
52
|
user_id=userId,
|
|
49
53
|
company_id=companyId,
|
|
50
54
|
input={
|
|
51
55
|
"key": displayed_filename,
|
|
52
56
|
"title": displayed_filename,
|
|
53
57
|
"mimeType": mime_type,
|
|
58
|
+
"ingestionConfig": ingestion_config,
|
|
59
|
+
"metadata": metadata,
|
|
54
60
|
},
|
|
55
61
|
scopeId=scope_or_unique_path,
|
|
56
62
|
chatId=chat_id,
|
|
@@ -78,6 +84,8 @@ def upload_file(
|
|
|
78
84
|
"title": displayed_filename,
|
|
79
85
|
"mimeType": mime_type,
|
|
80
86
|
"byteSize": size,
|
|
87
|
+
"ingestionConfig": ingestion_config,
|
|
88
|
+
"metadata": metadata,
|
|
81
89
|
},
|
|
82
90
|
fileUrl=createdContent.readUrl,
|
|
83
91
|
chatId=chat_id,
|
|
@@ -91,6 +99,8 @@ def upload_file(
|
|
|
91
99
|
"title": displayed_filename,
|
|
92
100
|
"mimeType": mime_type,
|
|
93
101
|
"byteSize": size,
|
|
102
|
+
"ingestionConfig": ingestion_config,
|
|
103
|
+
"metadata": metadata,
|
|
94
104
|
},
|
|
95
105
|
fileUrl=createdContent.readUrl,
|
|
96
106
|
scopeId=scope_or_unique_path,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|